平面反射

屏幕空间反射是利用屏幕空间数据进行计算反射的一种技术。它通常用于创建更精细的反射,如在潮湿的地板表面或水坑。

一、实现思路

主要分两次进行基本的离屏渲染。第一遍将镜像的场景渲染到具有颜色和深度附件的单独帧缓冲区,第二遍从该颜色附件采样以渲染镜面。

1.1 第一次渲染:离屏渲染

首先先创建一个渲染通道专门提前处理离屏渲染:将镜像的镜像的场景数据存储到单独的帧缓冲区中:

1.2 第二次渲染:采样附件

在第一次离屏渲染结束后,数据会被存储到附件中,之后,在第二次渲染的时候,将数据提取出来并在平面所使用的镜面片元着色器中采样,并渲染出来:

之后再进行渲染原始模型:

二、Vulkan主要实现步骤

本次场景使用两个模型(模型及地板平面)和两套对应着色器(模型冯氏光照shader及平面镜面shader),具体模型加载及Unform等数据创建不再赘述,主要讲述下重点实现部分。

2.1 离屏帧缓冲区

首先我们需要专门创建一个函数prepareOffscreen来为离屏帧缓冲区以呈现镜像场景,这个帧缓冲区的颜色附件将用于在最终遍历的片段着色器中采样:

// 离屏帧缓冲属性
#define FB_DIM 1024 //此处可控制反射区域模型的分辨率
#define FB_COLOR_FORMAT VK_FORMAT_R8G8B8A8_UNORM...void prepareOffscreen(){offscreenPass.width = FB_DIM;offscreenPass.height = FB_DIM;// 找到合适的深度格式VkFormat fbDepthFormat;VkBool32 validDepthFormat = vks::tools::getSupportedDepthFormat(physicalDevice, &fbDepthFormat);assert(validDepthFormat);// 附件颜色VkImageCreateInfo image = vks::initializers::imageCreateInfo();image.imageType = VK_IMAGE_TYPE_2D;image.format = FB_COLOR_FORMAT;image.extent.width = offscreenPass.width;image.extent.height = offscreenPass.height;image.extent.depth = 1;image.mipLevels = 1;image.arrayLayers = 1;image.samples = VK_SAMPLE_COUNT_1_BIT;image.tiling = VK_IMAGE_TILING_OPTIMAL;// 我们将直接从颜色附件中取样image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;VkMemoryAllocateInfo memAlloc = vks::initializers::memoryAllocateInfo();VkMemoryRequirements memReqs;VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &offscreenPass.color.image));vkGetImageMemoryRequirements(device, offscreenPass.color.image, &memReqs);memAlloc.allocationSize = memReqs.size;memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &offscreenPass.color.mem));VK_CHECK_RESULT(vkBindImageMemory(device, offscreenPass.color.image, offscreenPass.color.mem, 0));VkImageViewCreateInfo colorImageView = vks::initializers::imageViewCreateInfo();colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;colorImageView.format = FB_COLOR_FORMAT;colorImageView.subresourceRange = {};colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;colorImageView.subresourceRange.baseMipLevel = 0;colorImageView.subresourceRange.levelCount = 1;colorImageView.subresourceRange.baseArrayLayer = 0;colorImageView.subresourceRange.layerCount = 1;colorImageView.image = offscreenPass.color.image;VK_CHECK_RESULT(vkCreateImageView(device, &colorImageView, nullptr, &offscreenPass.color.view));// 在片段着色器的附件中创建采样器VkSamplerCreateInfo samplerInfo = vks::initializers::samplerCreateInfo();samplerInfo.magFilter = VK_FILTER_LINEAR;samplerInfo.minFilter = VK_FILTER_LINEAR;samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;samplerInfo.addressModeV = samplerInfo.addressModeU;samplerInfo.addressModeW = samplerInfo.addressModeU;samplerInfo.mipLodBias = 0.0f;samplerInfo.maxAnisotropy = 1.0f;samplerInfo.minLod = 0.0f;samplerInfo.maxLod = 1.0f;samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;//unform image samplerVK_CHECK_RESULT(vkCreateSampler(device, &samplerInfo, nullptr, &offscreenPass.sampler));// 深度模板附件image.format = fbDepthFormat;image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &offscreenPass.depth.image));vkGetImageMemoryRequirements(device, offscreenPass.depth.image, &memReqs);memAlloc.allocationSize = memReqs.size;memAlloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &offscreenPass.depth.mem));VK_CHECK_RESULT(vkBindImageMemory(device, offscreenPass.depth.image, offscreenPass.depth.mem, 0));VkImageViewCreateInfo depthStencilView = vks::initializers::imageViewCreateInfo();depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;depthStencilView.format = fbDepthFormat;depthStencilView.flags = 0;depthStencilView.subresourceRange = {};depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;depthStencilView.subresourceRange.baseMipLevel = 0;depthStencilView.subresourceRange.levelCount = 1;depthStencilView.subresourceRange.baseArrayLayer = 0;depthStencilView.subresourceRange.layerCount = 1;depthStencilView.image = offscreenPass.depth.image;VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &offscreenPass.depth.view));// 为屏幕外渲染创建一个单独的渲染通道,因为它可能不同于用于场景渲染的通道std::array<VkAttachmentDescription, 2> attchmentDescriptions = {};// Color attachment 颜色附件attchmentDescriptions[0].format = FB_COLOR_FORMAT;attchmentDescriptions[0].samples = VK_SAMPLE_COUNT_1_BIT;attchmentDescriptions[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;attchmentDescriptions[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;attchmentDescriptions[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;attchmentDescriptions[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;attchmentDescriptions[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;attchmentDescriptions[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;// Depth attachment 测深附件attchmentDescriptions[1].format = fbDepthFormat;attchmentDescriptions[1].samples = VK_SAMPLE_COUNT_1_BIT;attchmentDescriptions[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;attchmentDescriptions[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;attchmentDescriptions[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;attchmentDescriptions[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;attchmentDescriptions[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;attchmentDescriptions[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };VkAttachmentReference depthReference = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };VkSubpassDescription subpassDescription = {};subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;subpassDescription.colorAttachmentCount = 1;subpassDescription.pColorAttachments = &colorReference;subpassDescription.pDepthStencilAttachment = &depthReference;// 使用子传递依赖关系进行布局转换std::array<VkSubpassDependency, 2> dependencies;dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;dependencies[0].dstSubpass = 0;dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;dependencies[1].srcSubpass = 0;dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;// 创建实际的渲染通道VkRenderPassCreateInfo renderPassInfo = {};renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;renderPassInfo.attachmentCount = static_cast<uint32_t>(attchmentDescriptions.size());renderPassInfo.pAttachments = attchmentDescriptions.data();renderPassInfo.subpassCount = 1;renderPassInfo.pSubpasses = &subpassDescription;renderPassInfo.dependencyCount = static_cast<uint32_t>(dependencies.size());renderPassInfo.pDependencies = dependencies.data();VK_CHECK_RESULT(vkCreateRenderPass(device, &renderPassInfo, nullptr, &offscreenPass.renderPass));VkImageView attachments[2];attachments[0] = offscreenPass.color.view;attachments[1] = offscreenPass.depth.view;VkFramebufferCreateInfo fbufCreateInfo = vks::initializers::framebufferCreateInfo();fbufCreateInfo.renderPass = offscreenPass.renderPass;fbufCreateInfo.attachmentCount = 2;fbufCreateInfo.pAttachments = attachments;fbufCreateInfo.width = offscreenPass.width;fbufCreateInfo.height = offscreenPass.height;fbufCreateInfo.layers = 1;VK_CHECK_RESULT(vkCreateFramebuffer(device, &fbufCreateInfo, nullptr, &offscreenPass.frameBuffer));// 填充描述符,以便稍后在描述符集中使用offscreenPass.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;offscreenPass.descriptor.imageView = offscreenPass.color.view;offscreenPass.descriptor.sampler = offscreenPass.sampler;}

2.2 渲染管线

在上述离屏帧缓冲区创建完毕后,我们加载模型、创建uniformBuffer、管线布局等,然后在preparePipelines函数中创建两个主要的shader:Pong、mirror顶点和片元着色器:
其中冯氏光照着色器供模型使用,如下:

顶点着色器:

#version 450layout (location = 0) in vec4 inPos;
layout (location = 2) in vec3 inColor;
layout (location = 3) in vec3 inNormal;layout (binding = 0) uniform UBO
{mat4 projection;mat4 view;mat4 model;vec4 lightPos;
} ubo;layout (location = 0) out vec3 outNormal;
layout (location = 1) out vec3 outColor;
layout (location = 2) out vec3 outEyePos;
layout (location = 3) out vec3 outLightVec;void main()
{outNormal = inNormal;outColor = inColor;gl_Position = ubo.projection * ubo.view * ubo.model * inPos;outEyePos = vec3(ubo.view * ubo.model * inPos);outLightVec = normalize(ubo.lightPos.xyz - outEyePos);//针对反射平面的裁剪vec4 clipPlane = vec4(0.0, -1.0, 0.0, 1.5);  gl_ClipDistance[0] = dot(inPos, clipPlane);
}

片元着色器:

#version 450layout (location = 0) in vec3 inNormal;
layout (location = 1) in vec3 inColor;
layout (location = 2) in vec3 inEyePos;
layout (location = 3) in vec3 inLightVec;layout (location = 0) out vec4 outFragColor;void main()
{vec3 Eye = normalize(-inEyePos);vec3 Reflected = normalize(reflect(-inLightVec, inNormal)); vec4 IAmbient = vec4(0.1, 0.1, 0.1, 1.0);vec4 IDiffuse = vec4(max(dot(inNormal, inLightVec), 0.0));float specular = 0.75;vec4 ISpecular = vec4(0.0);if (dot(inEyePos, inNormal) < 0.0){ISpecular = vec4(0.5, 0.5, 0.5, 1.0) * pow(max(dot(Reflected, Eye), 0.0), 16.0) * specular; }outFragColor = vec4((IAmbient + IDiffuse) * vec4(inColor, 1.0) + ISpecular);}

下边我们来看下供平面使用的镜面着色器:

顶点着色器:

#version 450layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUV;layout (binding = 0) uniform UBO
{mat4 projection;mat4 view;mat4 model;
} ubo;layout (location = 0) out vec2 outUV;
layout (location = 1) out vec4 outPos;void main()
{outUV = inUV;outPos = ubo.projection * ubo.view * ubo.model * vec4(inPos.xyz, 1.0);gl_Position = outPos;
}

片元着色器:

#version 450layout (binding = 1) uniform sampler2D samplerColor;
//控制镜面反射扰动的相关数据
layout (binding = 3) uniform CON {float blur;int rang;float scale;float bias;
} con;layout (location = 0) in vec2 inUV;
layout (location = 1) in vec4 inPos;layout (location = 0) out vec4 outFragColor;void main()
{vec4 tmp = vec4(1.0 / inPos.w);vec4 projCoord = inPos * tmp;// 比例与基准点projCoord += vec4(1.0);projCoord *= vec4(0.5);// 测试使用的扰动因子const float blurSize = con.blur / 512.0;  outFragColor = vec4(vec3(0.0), 1.0f);//仅在镜面正面(上)面渲染镜像场景if (gl_FrontFacing) {vec4 reflection = vec4(0.0);for (int x = -con.rang; x <= con.rang; x++){for (int y = -con.rang; y <= con.rang; y++){reflection += texture(samplerColor, vec2(projCoord.s + x * blurSize, projCoord.t + y * blurSize)) / 49.0;}}outFragColor += reflection;};
}

从上边两个顶点着色器来看,我们都加入了MVP矩阵,是为了可以同步模型旋转与镜像数据旋转一致这些情况,在镜面的片元着色器中,我们仅在模型面正面进行了采样反射,除了100%采样反射模型外,我们还加入了扰动因子对采样进行模糊处理,通过不同的因子数值可以调整镜面映像的模糊程度(效果可见开头gif)。

2.3 绘制渲染

创建完管线后,我们对描述符集、描述符池进行uniform数据填充和管理,之后就到了buildCommandBuffer部分,此部分就是离屏数据填充离屏帧缓存以及绘制模型部分(详细部分可见代码注释):

 void buildCommandBuffers(){VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();VkClearValue clearValues[2];VkViewport viewport;VkRect2D scissor;VkDeviceSize offsets[1] = { 0 };for (int32_t i = 0; i < drawCmdBuffers.size(); ++i){VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));/*第一次渲染:离屏渲染*/{VkClearValue clearValues[2];//默认区域颜色clearValues[0].color = { { 0.76f, 0.76f, 0.76f, 0.0f } };clearValues[1].depthStencil = { 1.0f, 0 };VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();renderPassBeginInfo.renderPass = offscreenPass.renderPass;renderPassBeginInfo.framebuffer = offscreenPass.frameBuffer;renderPassBeginInfo.renderArea.extent.width = offscreenPass.width;renderPassBeginInfo.renderArea.extent.height = offscreenPass.height;renderPassBeginInfo.clearValueCount = 2;renderPassBeginInfo.pClearValues = clearValues;vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);VkViewport viewport = vks::initializers::viewport((float)offscreenPass.width, (float)offscreenPass.height, 0.0f, 1.0f);vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);VkRect2D scissor = vks::initializers::rect2D(offscreenPass.width, offscreenPass.height, 0, 0);vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);VkDeviceSize offsets[1] = { 0 };// 镜像场景vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.shaded, 0, 1, &descriptorSets.offscreen, 0, NULL);vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.shadedOffscreen);vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &models.example.vertices.buffer, offsets);vkCmdBindIndexBuffer(drawCmdBuffers[i], models.example.indices.buffer, 0, VK_INDEX_TYPE_UINT32);vkCmdDrawIndexed(drawCmdBuffers[i], models.example.indexCount, 1, 0, 0, 0);vkCmdEndRenderPass(drawCmdBuffers[i]);}/*注意:呈现通道之间不需要显式同步,因为这是通过子通道依赖项隐式地完成的*//*第二次渲染通道:应用径向模糊的场景渲染*/{clearValues[0].color = defaultClearColor;clearValues[1].depthStencil = { 1.0f, 0 };VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();renderPassBeginInfo.renderPass = renderPass;renderPassBeginInfo.framebuffer = frameBuffers[i];renderPassBeginInfo.renderArea.extent.width = width;renderPassBeginInfo.renderArea.extent.height = height;renderPassBeginInfo.clearValueCount = 2;renderPassBeginInfo.pClearValues = clearValues;vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0);vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);VkDeviceSize offsets[1] = { 0 };// 渲染的场景// 反射平面vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.textured, 0, 1, &descriptorSets.mirror, 0, NULL);vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.mirror);vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &models.plane.vertices.buffer, offsets);vkCmdBindIndexBuffer(drawCmdBuffers[i], models.plane.indices.buffer, 0, VK_INDEX_TYPE_UINT32);vkCmdDrawIndexed(drawCmdBuffers[i], models.plane.indexCount, 1, 0, 0, 0);// 模型vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.shaded, 0, 1, &descriptorSets.model, 0, NULL);vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.shaded);vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &models.example.vertices.buffer, offsets);vkCmdBindIndexBuffer(drawCmdBuffers[i], models.example.indices.buffer, 0, VK_INDEX_TYPE_UINT32);vkCmdDrawIndexed(drawCmdBuffers[i], models.example.indexCount, 1, 0, 0, 0);vkCmdEndRenderPass(drawCmdBuffers[i]);}VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));}}

可以看到,我们也是使用了两个通道先处理离屏渲染的数据,再处理场景模型及需要反射的数据,也在反射平面中进行了采样渲染。
至此所有步骤结束,你也可以调整各级参数来控制展示显示效果:

Vulkan_平面反射相关推荐

  1. OpenGL渲染纹理和平面反射

    OpenGL渲染纹理和平面反射 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <stdio.h> #include "GL ...

  2. Unity下平面反射实现

    平面反射通常指的是在镜子或者光滑地面的反射效果上,如下图所示, 上图是一个光滑的平面,平面上的物体在平面上有对称的投影. 一.平面反射的原理 对于光照射到物体表面然后发生完美镜面反射的示意图,如下所示 ...

  3. UE4-(反射)平面反射

    一.创建 注意:平面反射拖拽到场景后,会创建一大块平面,这个平面是临时创建的,当程序运行后,我们不会看到这个平面. 平面反射会捕获反射信息,只能用于平面反射效果,所以只适用于平整的对象,例如镜子,水池 ...

  4. 平面反射builltinURP—— UnityShader学习记笔记

    文章目录 自言自语 一.C# builltin 二.URP 总结 自言自语 又是好久没有更新笔记了.最近项目真的很忙.一直想更新的笔记现在才有空梳理.今天要记载的就是平面反射. 一.C# buillt ...

  5. Shader实例:Planar Reflection 平面反射

    目前采用比较多的反射,最终效果示例: 代码已经中文注解,有2部分需扩展:反射矩阵.歪截头体矩阵.注解中有来源链接可以去理解推导过程. 可用于镜面和水面. 咱还是直接看注解过的代码 MirrorRefl ...

  6. Unity URP Planar reflection 平面反射

    利用双休天写的,代码和shader还有不少问题 修复中.... 一开始是用模板测试和后处理写的,后面改成屏幕坐标,更方便了,加入到我的水体康康 主要思想是动态创建一个翻转的反射摄像机 ,但是不打开这个 ...

  7. matlab 平面反射,一种基于MatlabGUI平台的反射板型面优化方法与流程

    本发明属于海洋工程领域,尤其是涉及一种反射板型面优化方法. 背景技术: 在灯管安装灯座之后,由于灯管的光线照明方向呈辐射状,使得位于灯座下方的所需照射范围实际上仅能获得部分的照明亮度,其余的照明光线则 ...

  8. ue4 改变枢轴位置_UE4渲染模块概述(四)---反射

    在前一文中介绍了像素着色器与material,大概知道了UE4材质的生产管线: Jerry:UE4渲染模块概述(三)---Pixel Shader & Material Rendering​z ...

  9. 屏幕空间实时非平面反射

    转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=1964 在KlayGE开发版中,deferred rendering的流水线中新增加了由组员王 ...

最新文章

  1. 引擎设计跟踪(九.14.2i) Android GLES 3.0 完善
  2. Virtex-6系列FPGA的CLB
  3. vs2008页面布局GridLayout绝对定位的设置
  4. 金融风控实战——特征工程上
  5. 只需 4 步,自己搞个 Spring Boot Starter!
  6. Spring框架你敢写精通,面试官就敢问@Autowired注解的实现原理
  7. How Nokia both helped and hindered Microsoft's earnings
  8. django学习第77天Django框架ORM
  9. css如何让滚轮滚动时 不让页面滚动_中国第五届 CSS 大会参会总结
  10. Fov手术会不会在手术中新增手术边界
  11. Chromium Embedded Framework中文文档之(基本使用)
  12. 炒了8年的概念,到底该如何理解DevOps这个词?
  13. oracle仲裁机制,仲裁逻辑设计要点
  14. Java后端实现websocket与微信小程序端连接简单例子
  15. cmake下载,安装
  16. java jshell_[Java JShell 指南] - 介绍
  17. 世纪互联评测至强5500 总结云平台经验
  18. prefixTreeEspan 频繁子树模式挖掘 A pattern growth 算法实现 mining embedded subtrees.
  19. NGUI 动态操作sprite
  20. 阵列天线中阵元间距、波程差与相位差之间的关系

热门文章

  1. 程序员带你了解黑帽与白帽的区别!
  2. 为什么php面试笔试题,PHP笔试题
  3. 淘宝卖家,应该怎么让网店远离负面评价?
  4. 使用div+css编写网页框架
  5. 剖析MCU的IAP升级软件设计思路
  6. 手机上有好用的时间管理工具吗?
  7. 杭电计算机专业认可度,杭州电子科技大学每年的录取分数高不高?杭电的社会认可度怎么样?...
  8. 实现“小学生算术题出题器”
  9. java输出排列整齐,java 每次输出有单个数字和好几位数字时候 排列不整齐。。这个不知道有没有办法解决的?...
  10. 听说“辣鸡小隔膜”出V1.3了?