-
Creator 版本: 3.5.2
-
目标平台: 浏览器 chrome
-
重现方式:
当一个opaque 材质的模型放置在近处同时在 距离摄像机更深的位置上放置transparent材质的模型,会出现可以看穿opaque 材质的模型,看到后面透明物体,而理论上不透明材质在前面的话,应该不能看到其挡住的物体,透明的也不行。这应该是一种基本物理规则吧。
我这项目场景必现,不知道咋复现。。。也可能是我没用对(ps:用了一个摄像机做镜像,但是我想该摄像机是输出到RT中,且优先级比主摄像机低,也就是其在主摄像机前渲染)。
不管啥原因,出了问题就要找原因。
通过阅读延迟渲染部分的源码,我发现在引擎中透明物体是在light-stage时渲染的,而且其渲染时,深度模板数据应该被重置了?望知道的大佬解释下。从而渲染透明问题出现穿模现象。分析了原因,解决办法也好办,把Gbuffer阶段的深度模板数据传给透明物体的shader中,然后根据物体顶点在NDC的深度进行discard就行了。
不多说上代码吧!
:grinning:
引用
import { gfx, pipeline } from “cc”;const { DescriptorSetLayoutBinding, UniformSamplerTexture, DescriptorType, ShaderStageFlagBit, Type } = gfx;
const { SetIndex, PipelineGlobalBindings, globalDescriptorSetLayout } = pipeline;
let GlobalBindingStart = PipelineGlobalBindings.COUNT;
let GlobalBindingIndex = 0;
const UNIFORM_DEPTH_STENCIL_NAME = ‘cc_depth_stencil’;
export const UNIFORM_DEPTH_STENCIL_BINDING = GlobalBindingStart + GlobalBindingIndex++;
const UNIFORM_DEPTH_STENCIL_DESCRIPTOR = new DescriptorSetLayoutBinding(UNIFORM_DEPTH_STENCIL_BINDING, DescriptorType.SAMPLER_TEXTURE, 1, ShaderStageFlagBit.FRAGMENT);
const UNIFORM_DEPTH_STENCIL_LAYOUT = new UniformSamplerTexture(SetIndex.GLOBAL, UNIFORM_DEPTH_STENCIL_BINDING, UNIFORM_DEPTH_STENCIL_NAME, Type.SAMPLER2D, 1);
globalDescriptorSetLayout.layouts[UNIFORM_DEPTH_STENCIL_NAME] = UNIFORM_DEPTH_STENCIL_LAYOUT;
globalDescriptorSetLayout.bindings[UNIFORM_DEPTH_STENCIL_BINDING] = UNIFORM_DEPTH_STENCIL_DESCRIPTOR;
预格式化文本将缩进 4 格
import { _decorator, Component, Node, RenderPipeline, DeferredPipeline, gfx } from “cc”;
import { UNIFORM_DEPTH_STENCIL_BINDING } from “./UboDeffined”;
const { ccclass, property } = _decorator;
@ccclass(“DefferRPCustom”)
export class DefferRPCustom extends DeferredPipeline {
public activate (swapchain: gfx.Swapchain): boolean { const result = super.activate(swapchain); this._generateCustomData(swapchain); return result; } private _generateCustomData(swapchain: gfx.Swapchain) { this._width = swapchain.width; this._height = swapchain.height; const deferredData = this.getPipelineRenderData(); //将深度图传入全局中 this.descriptorSet.bindTexture(UNIFORM_DEPTH_STENCIL_BINDING, deferredData.gbufferFrameBuffer.depthStencilTexture!); const sampler = this.globalDSManager.pointSampler;; this.descriptorSet.bindSampler(UNIFORM_DEPTH_STENCIL_BINDING, sampler); }
}
然后就是把标准shader拷贝出来改一下透明物体的片元着色器代码罗!
太长了就只贴关键代码了
#if(CC_PIPELINE_TYPE == CC_PIPELINE_TYPE_DEFERRED) #pragma builtin(global) layout (set = 0, binding = 7) uniform sampler2D cc_depth_stencil; #endif
然后在surf中加入处理逻辑:
#if (CC_PIPELINE_TYPE == CC_PIPELINE_TYPE_DEFERRED)
vec2 v_uv2 = vec2(v_clipDepth.x,v_clipDepth.y); vec4 depthColor = texture(cc_depth_stencil, v_uv2); float depth = depthColor.x;//0-1 // vec3 worldPos = screen2WS(vec3(gl_FragCoord.xy, depth)).xyz; // s.albedo = vec4(worldPos.xyz,1.0); // return; if(v_clipDepth.z>depth) discard; #endif
其中v_clipDepth由顶点传递过来的。。。顶点里面关键代码。咋定义,自己看effect文档。其中posClip为齐次裁剪坐标,取值范围为【-1,1】,所以*0.5+0.5就到【0,1】区间了。
#if(CC_PIPELINE_TYPE == CC_PIPELINE_TYPE_DEFERRED)
v_clipDepth = posClip.xyz/posClip.w*0.5+0.5; #endif