浅谈RenderTexture的shadowmap格式
来源:互联网 发布:性能测试 知乎 编辑:程序博客网 时间:2024/06/05 07:09
作为一个初学者,最近开始研究Unity中的Shader,在研究一个案例《BlackSmith》时发现其使用render texture时所选择的格式为shadowmap,于是便打算研究一下这种存储格式。
首先,这里是在Unity官方文档中对shadowmap的介绍:
这是一种自带的shadowmap格式。
这种格式的数据可以GPU自动完成对这种数据格式的shadowmap比较计算。当设备支持时,Unity在内部使用这种数据格式进行阴影计算。需要注意的是,在某些平台或GPU不支持shadowmap格式的情况下,阴影将会使用RenderTextureFormat.Depth格式进行计算。
由于并不是所有显卡都支持shadowmap,使用SystemInfo.SupportsRenderTextureFormat方法去检查设备是否支持此格式。
从官方的描述中我们可以看出,shadowmap的数据格式应该和Depth格式相似,因此猜测shadowmap中也是存储的Depth值,且存储于R通道中,距离camera越近Depth值越小,距离Camera越远Depth值越大,camera近裁面Depth值为0,远裁面Depth值为1。
为了验证此猜测,我们在Unity中简单创建一个场景来进行测试。
创建Cube和Sphere作为场景内容,创建camera获取场景画面,创建Rendertexture作为camera的target texture。将RenderTexture的Color Format格式设置为Depth模式,如下:
此时我们在下方可以看到RenderTexture的画面:
当我们将Color Format改为shadowmap时,画面则变为如下:
两者数据大小都是1M,可以进一步验证推测,但是为何shadowmap格式却无法显示任何画面内容呢?我们又该如何使用shadowmap中的数据呢?
为此我们需要使用shader,新建一个shader用来显示RenderTexture中的数据内容。新建一个材质应用此shader,并将材质赋予新建的Plane上,用MainCamera观察此Plane。
当RenderTexture格式为Depth时,我们只需一个简单的Shader,就能获取RenderTexture中的数据,并显示出来。主要代码如下:
fixed4 frag (v2f i) : SV_Target
{
float depth = tex2D(_MainTex, i.uv).r;
fixed4 col = fixed4(0,0,0,1);
if(depth != 1.f)
col = fixed4(depth,depth, depth,1.f);
return col;
}
画面和将RenderTexture作为材质直接赋予Plane一样,显示画面如下:
但是当我们将RenderTexture格式改为shadowmap时,正如我们所想画面中完全变为红色,没有显示任何内容,可见shadowmap中的数据无法使用这种方式获取。
此时,我们需要使用Texture2D.Sample方法来获取shadowmap中的数据,此方式是笔者研究的shader案例中所使用的方法。
为此,我们需要添加如下变量:
Texture2D _ShadowTexture;
Texture2D fakePoint;
SamplerState samplerfakePoint;
_ShadowTexture需要在Properties中进行声明,用来获取RenderTexture。fakePoint为使用采样器创建的Texture2D纹理,其中是否含有数据,以及数据内容都无关紧要;samplerfakePoint是基于fakePoint进行初始化的采样器,具体采样器命名和初始化方法见这里。
主要代码如下:
float depth = fakePoint.Sample(samplerfakePoint,float2(0,0)).a;
for (int j = 0; j < 5; j++) {
depth += _ShadowTexture.Sample(samplerfakePoint, i.uv).r;//对该点进行反复采样/
}
depth -= fakePoint.Sample(samplerfakePoint, float2(0, 0)).a;//去除多余量/
depth = depth / 5.f;//对采样总和取平均值/
由此,我们可以得到和Depth格式下相同的画面。如果对GBA通道进行采样,我们都无法得到数据值,因此,我们可以确定shadowmap中数据格式和Depth中数据格式是相同的,将深度信息值存储于R通道中,但是为何Depth格式就可以使用tex2D方法获取,而shadowmap格式却需要使用采样?
笔者通过测试发现,如果如果直接使用_ShadowTexture所初始化的采样器(sampler_ShadowTexture)直接对_ShadowTexture进行采样,如下:
float depth = _ShadowTexture.Sample(sampler_ShadowTexture,i.uv).r;
如果RenderTexture格式为Depth时,可以正常获取数据内容;而当格式为shadowmap时则无法获取数据内容。
由此,笔者推测shadowmap格式在Unity内部进行了数据内容的变换,正常情况下无法直接读取,因此需要通过另外声明一个采样器,按照新的采样器的数据格式对shadowmap数据进行采样,采样的过程中Unity会对shadowmap中的数据进行变换,使其对应新采样器的格式,从而让我们可以向shadowmap中的数据正确的提取出来。
但是,在测试过程中,笔者发现使用Depth格式或shadowmap格式时都会使得物体边缘出现一圈白边。经过测试发现此是由于边缘处depth值突变所导致,推测其原因应该是在camera获取图像转化为深度信息值的过程中,但具体原因为何则仍需进一步学习和探索了。
以下是shader源码:
Shader "Custom/rendertextureformat"{Properties{_MainTex ("Texture", 2D) = "white" {}_ShadowTexture("ShadowTexture", 2D) = "white" {}}SubShader{// No culling or depthCull Off ZWrite Off ZTest AlwaysPass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};v2f vert (appdata v){v2f o;o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);o.uv = v.uv;return o;}sampler2D _MainTex;uniform Texture2D _ShadowTexture;uniform SamplerState sampler_ShadowTexture;Texture2D fakePoint;SamplerState samplerfakePoint;fixed4 frag (v2f i) : SV_Target{#if 1//float depth = _ShadowTexture.Sample(sampler_ShadowTexture,i.uv).r;float depth = fakePoint.Sample(samplerfakePoint,float2(0,0)).a;//建立采样器/for (int j = 0; j < 5; j++) {depth += _ShadowTexture.Sample(samplerfakePoint, i.uv).r;//对该点进行反复采样/}depth -= fakePoint.Sample(samplerfakePoint, float2(0, 0)).a;//去除多余量/depth = depth / 5.f;//对采样总和取平均值/#elsefloat depth = tex2D(_MainTex, i.uv).r;#endiffixed4 col = fixed4(0,0,0,1);if(depth != 1.f)col = fixed4(depth,depth, depth,1.f);return col;}ENDCG}}}
最后,笔者是Unity初学者,也非计算机背景,很多编程内容也都是自学所得,因此如有表述错误或者疏漏之处,还请指正。希望和大家一起进步。
- 浅谈RenderTexture的shadowmap格式
- shadowmap 的一些变种
- gamebryo--ShadowMap的使用
- ShadowMap
- ShadowMap
- Shadowmap
- SHADOWMAP
- ShadowMap
- SHADOWMAP
- RenderTexture的使用
- 关于Unity 的 RenderTexture
- 修改RenderTexture的size
- RenderTexture
- RenderTexture
- void OnRenderImage(RenderTexture src, RenderTexture dst) 的坑
- 保存RenderTexture类型的图片
- ShadowMap的实现 -- 正中要害简化版
- 目前出现的ShadowMap实现方式名称
- rocketmq问题汇总-如何将特定消息发送至特定queue,消费者从特定queue消费
- 你应该更新的 Java 知识之常用程序库
- 百度前端技术学院task
- 百度前端技术学院task
- web项目自动化
- 浅谈RenderTexture的shadowmap格式
- eclipse 启动报错 Ensure that the org.eclipse.core.runtime bundle is resolved
- C# RSA加密解密
- Linux命令之dos2unix - DOS格式文本文件UNIX格式文件的转换
- JDK容器与并发—Queue—SynchronousQueue
- HTMl5的存储方式sessionStorage和localStorage详解
- java和javac的基本用法
- 病毒木马查杀实战第018篇:病毒特征码查杀之基本原理
- 静态二分查找