【Unity Shader】Shadow Caster、RenderType和_CameraDepthTexture

2023-11-19

当我们制作某些屏幕特效时,需要取到屏幕的深度图或法线图,比如ssao,景深等,另外像是制作软粒子shader,体积雾等也需要取到深度图,以计算深度差等。unity提供了两个内置的纹理_CameraDepthTexture和_CameraDepthNormalsTexture,使用时只需声明sampler2D _CameraDepthTexture、sampler2D _CameraDepthNormalsTexture,并修改需要渲染出深度图的Camera的depthTextureMode为Depth或DepthNormals就行了。

其中_CameraDepthTexture存储的是屏幕深度信息,而_CameraDepthNormalsTexture存储的还包括法线信息。

而接下来我需要研究的问题是,究竟怎样的物体会被渲染到_CameraDepthTexture这张图里,以及会以什么样的方式渲染(Unity中_CameraDepthNormalsTexture的渲染已经在上一篇文章中解释过了,链接:http://blog.csdn.net/mobilebbki399/article/details/50512059)。

研究这个的意义,我们可以想象,如果写了一个shader,其blend为srcalpha onesrcalpha,也就是普通的transparent效果,并且我们可以通过属性去修改它的alpha,但是我们将RenderType改成Opaque,那么这个物体会以实心的形式渲染到_CameraDepthNormalsTexture(5.x中_CameraDepthTexture不再由RenderType替代渲染得到)。

举个例子,注意下面两张图:


其中第一张图中黄色方块的shader中使用了blend srcalpha onesrcalpha,并给予一个_Alpha属性控制其alpha,也就是普通的transparent shader,区别就是其RenderType为Opaque,然后使用了一个景深屏幕特效,其实现屏幕特效的shader中用_CameraDepthNormalsTexture来解码得到的深度对原始图像和模糊后图像插值(4.x的版本应该用_CameraDepthTexture也一样有效),可以看到当把黄色方块的_Alpha改成0,但因为其RenderType为Opaque,也就是会渲染到_CameraDepthNormalsTexture,导致出现如第二幅图中的情况。

注意尽管_CameraDepthTexture里存放的是深度信息,但这和深度缓存还是不同的,我们知道在shader中用zwrite off可以关闭写入深度缓存,但这不表示关闭写入_CameraDepthTexture,_CameraDepthTexture本身是渲染得到的屏幕纹理,和zwrite并没有直接的联系。

之前的文章中有提过,在unity5.x新特性中可以看到:


我们可以尝试在unity4.x中编写shader,写一个最简单的vertex&fragment shader,并删除最后的FallBack,将RenderType改成Opaque,挂在场景中的一个物体上,然后写一个屏幕特效shader,这个shader只输出_CameraDepthTexture,并编写使用屏幕特效的脚本挂到摄像机上(注意记得将该Camera的DepthTextureMode改成Depth),然后可以看到Game视图输出的效果如下,可以看到这个shader成功被写入_CameraDepthTexture。


然后我们切换到unity5.x,编写同样的shader(unity5.x中直接右键创建Unlit shader就行了),然后同样输出_CameraDepthTexture,可以看到效果:


说明这个shader没有被成功写入_CameraDepthTexture,我们修改一下屏幕特效shader,将其输出_CameraDepthNormalsTexture,可以看到效果:


可以看到_CameraDepthNormalsTexture中存在这个物体,也就是说Unity5.x中_CameraDepthNormalsTexture是通过RenderType进行替代渲染得到的,上一篇文章已经证明过了,而_CameraDepthTexture在unity5.x中不再和RenderType有直接关系了。

根据unity5.0新特性描述我们已经知道,5.0中_CameraDepthTexture的渲染是通过同一个shader中的Shadow Caster Pass渲染得到的。

我们修改在5.x中创建的Unlit Shader,在其最后加入FallBack "Diffuse",然后再次运行场景观察_CameraDepthTexture的输出情况,效果如下:


可以看到_CameraDepthTexture中成功渲染出该物体,并且注意此时如果开启场景中灯光的阴影,这个Unlit Shader的物体会投射阴影,那么FallBack "Diffuse"究竟有什么玄机呢,先来看看Unity 官网上关于shader中投射阴影的描述:

In order to cast shadows, a shader has to have a ShadowCaster pass type in any of its subshaders or any fallback. The ShadowCaster pass is used to render the object into the shadowmap, and typically it is fairly simple - the vertex shader only needs to evaluate the vertex position, and the fragment shader pretty much does not do anything. The shadowmap is only the depth buffer, so even the color output by the fragment shader does not really matter.


也就是说产生阴影首先要包含LightMode=ShadowCaster的Pass或者FallBack一个包含该Pass的shader,这个Pass实际上就是为了渲染到一张shadowmap,而实际上我们加入的FallBack语句返回的Diffuse shader,该shader会Fall Back一个Legacy Shaders/VertexLit,在其中能找到这个Pass,事实上Unity 官网上能看到其提供了一种产生实心阴影的普遍方式:

UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"

就是在你的shader中使用Legacy Shaders/VertexLit这个shader中的ShadowCaster的Pass,之所以这样用,因为绝大多数不透明物体产生的阴影都是相同的,即都是实心的,因此使用一个相同的ShaderCaster Pass即可,除非遇到有修改过顶点函数,比如顶点挤出或是扭曲等,亦或是使用过clip裁剪像素的shader,比如溶解shader,其投射的阴影需要重新编写LightMode=ShadowCaster的Pass。

接下来我们尝试自己编写ShadowCaster,观察其对_CameraDepthTexture的影响,在原来的Unlit Shader基础上我们删除添加的FallBack,并添加LightMode=ShadowCaster的Pass内容如下:

Pass {
	Tags { "LightMode"="ShadowCaster" }
	CGPROGRAM
	#pragma vertex vert
	#pragma fragment frag
	#pragma multi_compile_shadowcaster
	#include "UnityCG.cginc"

	sampler2D _Shadow;

	struct v2f{
		V2F_SHADOW_CASTER;
		float2 uv:TEXCOORD2;
	};

	v2f vert(appdata_base v){
		v2f o;
		o.uv = v.texcoord.xy;
		TRANSFER_SHADOW_CASTER_NORMALOFFSET(o);
		return o;
	}

	float4 frag( v2f i ) : SV_Target
	{
		fixed alpha = tex2D(_Shadow, i.uv).a;
		clip(alpha - 0.5);
		SHADOW_CASTER_FRAGMENT(i)
	}

	ENDCG
}


然后我们看效果,可以看到投射的阴影变成镂空效果了,尽管物体本身还是实心的,然后再观察_CameraDepthTexture,看到深度图的效果也是镂空的了,最后再试着输出_CameraDepthNormalsTexture,看到物体还是实心的,因为_CameraDepthNormalsTexture的渲染是依据RenderType的,而_CameraDepthTexture的渲染在5.x中是依据ShadowCaster Pass的。


所以,在Unity5.x中_CameraDepthTexture的渲染是通过ShodowCaster Pass的。


最后总结一下:简单的说,我们在编写某些shader(如景深,软粒子,ssao等),需要取到屏幕深度图或法线图信息,而为了保证这两张纹理中有正确的数据,需要给shader使用正确的rendertype,比如当你的shader使用了clip进行像素裁剪,那么RenderType应该是TransparentCutOut,unity在渲染_CameraDepthNormalsTexture的时候会使用内置的一个Camera-DepthNormalTexture.shader中的RenderType同样是TransparentCutOut的Pass来替代这个shader,那么渲染进入_CameraDepthNormalsTexture的内容同样是clip过的而不是实心的,同样如果你的shader使用了blend制作了半透明效果,应该给RenderType设置为Transparent,由于Camera-DepthNormalTexture.shader中没有RenderType为Transparent的Pass,这个shader将不会渲染到_CameraDepthNormalsTexture中,同样对于_CameraDepthTexture,5.x中需要编写LightMode=ShadowCaster的Pass来将物体渲染到_CameraDepthTexture(4.x以及之前是通过RenderType来渲染_CameraDepthTexture和_CameraDepthNormalsTexture,到了5.x,unity将_CameraDepthTexture的渲染交给shadowcaster pass而不是RenderType)。




更多内容关注我的个人博客http://www.lsngo.net



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Unity Shader】Shadow Caster、RenderType和_CameraDepthTexture 的相关文章

  • 移动物体的漫射照明

    当计算移动物体的漫射照明时 我必须将光源与物体本身一起移动 Override public void draw draw frame Move object GLES20 glVertexAttribPointer aPositionLin
  • 游戏开发常见操作梳理之NPC任务系统

    多数游戏存在任务系统 接下来介绍通过NPC触发任务的游戏制作代码 using System Collections using System Collections Generic using UnityEngine
  • 游戏开发之常见操作梳理——武器装备商店系统(NGUI版)

    游戏开发中经常出现武器商店 接下来为你们带来武器装备商店系统的具体解决办法 后续出UGUI Json版本 敬请期待 武器道具的具体逻辑 using System Collections using System Collections Ge
  • 游戏开发常用实践操作之按动任意键触发

    接下来一些笔记会对于一些大大小小的实践操作进行记录 希望对你有所帮助 在游戏中 我们经常会遇到一些按动任意键触发的操作 接下来展示核心代码 以下是对于Unity中的操作 使用的UI是NGUI 对于核心操作没有影响 你可以自己置换 void
  • OpenGL 影子彼得潘

    我通过执行两个绘制通道 一个到深度图 一个到普通帧缓冲区 向 OpenGL 中的场景添加阴影 使用深度图时不使用偏置 会出现很多阴影痘痘 这是通过在深度图检查中添加偏差来解决的 然而 当光线移动到不同的角度时 这会导致阴影与物体 分离 我相
  • 如何在 ImageMagick 中绘制文本并为其添加阴影?

    我正在图像上打印一些文本convert我想用黑色阴影装饰文本 我尝试过 blur or 高斯但我不能应用于文本 它仅应用于背景图像 我需要使用 draw命令与否 注释 这是我需要更新阴影的代码 font geometricslab703bt
  • OpenGL 中着色器的问题

    我正在尝试在 C 中使用像 glShaderSource 这样的东西 Visual Studio 表示像 glCompileShader 或 glCreateProgram 这样的函数不存在 我使用 FreeGLUT 来包含 OpenGL
  • 是否可以在Unity的HDRP中创建DepthMask效果?

    我已经为此努力了一段时间 但我不知道是否有可能创建一个深度掩模着色器HDRP 如此处所述 http wiki unity3d com index php DepthMask 对于我的确切用途 我试图在应用了材质的任何形状上创建一个 洞 以显
  • 我们可以在透明窗口上应用着色器吗

    I am looking to apply a particular shader to a transparent window for example on a live desktop I want to create a trans
  • 以到最近边缘的距离为函数的着色矩形会在对角线上产生奇怪的结果

    I m trying to color a rectangle in ShaderToy GLSL in function of each pixel s distance to the nearest rectangle edge How
  • 使用 texelFetch() 进行纹理化

    当我将非最大值传递到纹理缓冲区时 在渲染时它会绘制具有最大值颜色的几何图形 我在使用 glTexBuffer API 时发现了这个问题 例如 假设我的纹理数据是GLubyte 当我传递任何小于255的值时 那么颜色与用255绘制的颜色相同
  • OpenGL 实现多通道

    我在移植一些已成功实现的代码时遇到问题着色玩具 https www shadertoy com view XdyfWK对于桌面 OpenGL 问题是我需要创建一个 FrameBufferObject FBO 以便我可以进行离屏计算 稍后将其
  • 在Unity中如何使两个精灵的重叠区域透明?

    在Unity中如何使两个精灵的重叠区域透明 你能写一个关于它的着色器吗 经过一些研究 我了解到我应该使用模板缓冲区 但我不知道如何使用 这对我来说至关重要 我必须在 6 天内完成这个学校项目 请帮忙 示例图片 就这样 请记住这是我第一次使用
  • 在 UIImage iOS 6.0 的所有四个面上添加阴影

    我正在尝试向 imageView 的所有四个侧面添加阴影 我看到 self shadowView layer shadowOffset CGSizeMake 10 20 在两侧添加阴影 如何在四个面上都添加阴影 刚刚设置shadowOffs
  • 基于石英的阴影在 UITextView 上对我不起作用

    我已经能够向视图中的许多 UI 对象添加阴影 包括在 UIImageView 中很好地为一些自定义绘图添加阴影 然而 相同的代码在应用于 UITextView 时不会产生任何结果 desc layer setShadowColor UICo
  • OpenGL:多个顶点的单个顶点属性?

    我有一个接受以下属性的顶点着色器 a posCoord 顶点位置 a texCoord 纹理坐标 传递给片段着色器 a alpha 透明度因子 传递给片段着色器 我正在渲染的对象都是 广告牌 一对直角三角形组成一个矩形 我正在使用一次调用g
  • Unity 后处理 PostProcessEffectRenderer 在编辑器中显示,但在构建中不显示

    将 PostProcessEffectRenderer 的实现添加到 Unity 后处理堆栈后 效果在 Unity 编辑器中完美运行 但不会在构建的游戏中显示 对构建质量的更改没有效果 使用针对 Windows x86 64 构建的最高质量
  • DirectX 世界视图矩阵乘法 - GPU 或 CPU 的地方

    我是 directx 的新手 但令我惊讶的是 我看到的大多数示例中 世界矩阵和视图矩阵都是作为顶点着色器的一部分相乘 而不是与 CPU 相乘并将结果传递给着色器 对于刚性对象 这意味着您为对象的每个顶点将相同的两个矩阵相乘一次 我知道 GP
  • 使用 QuartzCore 为 UITextView 创建阴影 [重复]

    这个问题在这里已经有答案了 我使用创建了一个阴影QuartzCore for my UITextView使用以下代码 myTextView layer masksToBounds NO myTextView layer shadowColo
  • UIView 框架更改时阴影层不调整大小

    问题图像截图 https i stack imgur com cyc5o png class ViewController UIViewController var shadow UIView override func viewDidLo

随机推荐

  • 互联网JAVA面试常问问题(三)

    一 volatile原理和使用场景 volatile 原理 volatile变量进行写操作时 JVM会向处理器发送一条Lock前缀的指令 将这个变量所在缓存行的数据写会到系统内存 Lock前缀指令实际上相当于一个内存屏障 也成内存栅栏 它确
  • LED用DMX512协议整个系统怎么连接?

    提问1 EIA485规范只支持 雏菊链 或每段上最多以32个 单元负载 所构成的串行网络 DMX512不是可以支持512个通道吗 那是不是说 超过32个的情况下需要使用中继 提问2 控制器 接收端1 接收端2 接收端n 电阻 GND 这样的
  • BIO、NIO、AIO理解

    一 到底什么是BIO NIO AIO 这些可以理解为是Java语言对操作系统的各种IO模型的封装 程序员在使用这些API的时候 不需要关系操作系统层面的知识 也不需要根据不同操作系统编写不同的代码 只需要使用Java的API就可以了 二 B
  • Eclipse搭建stm32+jlink开发环境全攻略(进阶篇一)

    Eclipse搭建stm32 jlink开发环境全攻略 进阶篇 一 本篇开始讲解一些比较实用的东西 在前面的两章中 我们讲解了eclipse开发stm32的大部分问题 然而 在实际使用过程中 我们仍然会遇到一些不太理想的地方 比如 ecli
  • Leetcode力扣题解 - 30.串联所有单词的子串

    地址 30 串联所有单词的子串 力扣 LeetCode 一 思路 本题关键点是 1 所有关键词长度一致 2 匹配的是所有关键词连接起来的 大体思路 那么我们就可以从字符串头开始 每次只匹配关键词总长度个字符 如果匹配成功 在返回的数组中保存
  • HDMI中的视频时序分析

    一 前言 建立层次观念 说到时序 我们首先想到的例子是IIC SPI 串口等接口的例子 以我们之前的理解 时序就是传输线上电平随时间变化的顺序 但是但是但是 在HDMI这里 我们应该建立一个新的观念 即时序不一定对应到物理层 即传输线上 这
  • python--- end=“ , 单独的一行print()是什么意思

    有如下一道练习题 编写代码打印出下列图形 代码如下 for i in range 4 for j in range 5 print end print 其中end 意思是为末尾end传递一个空字符串 这样print函数不会在字符串末尾添加一
  • 工频干扰频谱测量_【鼎阳硬件智库译文

    英文原文 by Mratin Miller 汪进进 译 鼎阳硬件设计与测试智库发起人之一 简介 多通道串行数据链路容易受到串扰的影响 这些串扰可能来自于相邻通道 也可能是外部的干扰源 Aggressor 其结果是增加了受干扰通道 Victi
  • leetcode数组刷题总结与分析

    文章目录 小结 数组中元素的计算 子序列 任意元素 题目一 两数之和 题目15 三数的和 17 四数之和 16 最接近三数之和 167 两数之和 输入有序数组 560 和为k的子数组 523 连续的子数组的和 53 最大子数组和 713 乘
  • Shell脚本到底是什么高大上的技术吗?

    本文介绍shell脚本知识 学习前最好有linux命令知识储备 一篇文章看完 下次找工作时简历上请写上会shell脚本 栓Q shell脚本是什么 shell脚本就是一个包含shell命令的脚本 常说的linux命令 也可以认为是shell
  • ArrayList与顺序表

    目录 编辑 一 线性表 二 顺序表 1 接口的实现 1 打印顺序表 2 新增元素 3 判定是否包含某个元素 4 查找某个元素对应的位置下标 5 获取 pos 位置的元素 6 获取顺序表长度 7 给 pos 位置的元素设为 value 更新的
  • C++ 一些学习笔记(三) 内存区域

    C 一些学习笔记 三 内存区域 主要是针对之前学习C的时候一些知识点的遗漏的补充 还有一些我自己觉得比较重要的地方 本文章的主要内容是关于程序内存模型的 内存的分区模型 1 程序运行前 2 程序运行后 3 new操作符 主要是针对之前学习C
  • 华为OD机试 - 路灯照明问题(Java)

    题目描述 在一条笔直的公路上安装了N个路灯 从位置0开始安装 路灯之间间距固定为100米 每个路灯都有自己的照明半径 请计算第一个路灯和最后一个路灯之间 无法照明的区间的长度和 输入描述 第一行为一个数N 表示路灯个数 1 lt N lt
  • 课程设计总结

    1 政府职能部门 望细分 具体 课程压缩所致 2 企业家 结构好 利于规划 参考 强烈希望协调与管理融合进来 3 工程师 技术人员 指导行强 望精化 深化 细化 4 学生 利于未来规划 创业 就业 发展 学习方向等等 老师总结课程缺陷 1
  • 虚拟机VMware的安装及使用

    一 虚拟机VMware的安装 1 准备工作 1 需要软件VMware安装包 VMware下载地址 http www uzzf com soft 51188 html 2 需要一个系统镜像 windows系统 http www xitongc
  • 【计算机视觉】最后显示的CIFAR-100数据集照片很模糊怎么解决?

    文章目录 一 前言 二 如何解决 2 1 使用图像增强技术 2 2 使用插值方法 2 3 使用更高分辨率的图像数据集 2 4 手动调整图像尺寸 三 总结 一 前言 如果从CIFAR 100数据集加载的图像显示模糊 可能有几个可能的原因 分辨
  • 小程序中里的bindinput_微信小程序中input标签的使用方法(附代码)

    本篇文章给大家带来的内容是关于微信小程序中input标签的使用方法 附代码 有一定的参考价值 有需要的朋友可以参考一下 希望对你有所帮助 在开发过程中经常遇到这样的需求 用户只能输入数字并且只保留小数点两位 虽然我们可以在提交表单的时候进行
  • [ASM C/C++] C函数调用分析

    在执行程序时 操作系统为进程分配一块栈空间来保存函数栈帧 esp寄存器总是指向栈顶 x86平台上这个栈是从高地址向低地址增长的 每次调用一个函数都要分配一个栈帧来保存参数和局部变量 C函数参数是按从右到左的顺序入栈的 各个堆栈桢之间是通过把
  • 多线程(1):互斥锁

    leetcode 1114题 按序打印 给你一个类 public class Foo public void first print first public void second print second public void thi
  • 【Unity Shader】Shadow Caster、RenderType和_CameraDepthTexture

    当我们制作某些屏幕特效时 需要取到屏幕的深度图或法线图 比如ssao 景深等 另外像是制作软粒子shader 体积雾等也需要取到深度图 以计算深度差等 unity提供了两个内置的纹理 CameraDepthTexture和 CameraDe