unity URP前向渲染流程以及获取屏幕空间UV和深度

前向渲染流程

cpu上进行剔除和排序,剔除为,相机的视椎体剔除,将相机视角外的模型剔除掉,不再渲染。遮挡剔除,将视椎体内不可见的模型剔除掉,不再渲染。排序为了保证性能,不透明为从近到远,减少不必要的渲染,半透明物体为了保证正确性,从远到近。

cpu上获取到所需的相关模型数据:顶点数据 贴图数据 还有材质属性,将数据提交给gpu,并调用gpu进行渲染,每调用渲染一次,为一次drawcall。

在gpu上,分为两部分,一部分是顶点着色器,另一部分是片元着色器。
在顶点着色器里,主要是位置变换,将顶点的位置,依次是 模型空间 世界空间 视线空间 裁剪空间 这个过程是 MVP矩阵变换。

在顶点着色器到片元着色器中间还有一个过程,这个过程中,将进行裁剪剔除,将不在屏幕中的片元裁剪到只在裁剪显示空间内的,显示范围为[-w, w],在这里得到的四维变量 xy是裁剪空间下的xy坐标,z是深度,w就是w,注意这里,因为获取屏幕uv也需要在这一步操作,而且不同平台的兼容的问题也需要从这一步开始出现,因为深度也就是z从这一步根据平台也不同。然后进行NDC(归一化设备坐标系),归一化操作,在unity里面,xy限制在0到w之间,而深度z,根据平台不同,则为-w到w或者0-w。NDC操作完成之后,将进行背面剔除,将一些无法看到图元(主要是三角形面,点和线不需要)给剔除掉。图元三角形的三个点如果是顺时针渲染的为背面,将被剔除,逆时针渲染的面为正面,将被渲染。

背面剔除完成以后,将要转换到屏幕空间(或者缓冲区空间),这里将根据渲染的宽高进行转换,转换完成后,将进行图元装配,然后进行光栅化,光栅化可以理解为获取到图元占用屏幕的像素(一般叫片元),占用多少像素,将调用多少次的片元着色器进行运算颜色。这个步骤是图元的所有的片元结果同步计算的。

片元着色器运算完成,就到了最后输出合并阶段。你计算完成后,也不一定能够给像素填充颜色,我们还需要进行多个测试,通过这些测试以后,才可以将颜色写入帧缓冲区。这些步骤分别是:

  1. 半透明测试 根据透明度,将多少透明度以下的颜色直接放弃写入。unity里面函数是clip,内部如果传入的值小于0,则不会写入颜色。
  2. 模板测试 根据之前设置的模板,对比,如果通过将继续下一步。
  3. 深度测试 对比帧缓冲区的深度,通过继续下一步。
  4. 混合测试 这一步主要针对于半透明物体的,当前的颜色和帧缓冲区的像素颜色按比例进行混合,得到最终颜色。
    最后,完成后,可以顺利的将颜色写入到缓冲区。注意,缓冲区不单单只存储了像素的颜色,还有深度信息,以及模板信息。

获取屏幕空间UV

前面渲染流程说了这么多,那么大家应该能清楚如何去获取屏幕uv了吧。肯定是NDC空间的xy坐标就是了,那么怎么获取,在urp里面,有两种方式,先说一下最简单的:
在这里插入图片描述
如下,直接使用urp内置的GetVertexPositionInputs函数,传入模型空间下的顶点坐标,即可获取到包含世界空间,视线空间,裁剪空间,NDC空间下的所有信息。我们可以看一下结构体:
在这里插入图片描述
第二种方式呢,就是我们通过裁剪空间下的坐标自己去计算,unity也内置了相关方法,
在这里插入图片描述
可以看到,其实就是修改了xy的坐标,zw根本没动。将xy从-w到w,变换到了0到w的区间。
在这里插入图片描述
_ProjectionParams的x项是为了兼容平台,dx的y坐标0是上面,而opengl平台的0到1是从下向上。
我还找到了屏幕的宽高常量:
在这里插入图片描述
还有时间相关的
在这里插入图片描述
再列一下其它的吧
在这里插入图片描述
这些都在UnityInput.hlsl文件中,大家可以自己去看看。

回归正题,既然我们得到NDC空间的xy,它们现在的区间范围是[0, w],那么就好办了,只要我们除以w,那么就得到了屏幕空间下的UV坐标了。
在这里插入图片描述

获取深度

上面,我们获取到屏幕的UV,是通过NDC空间下的坐标xy获取的,其实z的值就是深度,我们获取深度,首先限制到0-1或者根据平台不同,在-1到1之间,其实就是处于w就好了。
在这里插入图片描述
这样,可以获得,距离相机越近的物体,颜色越量,越远的,就越暗。
在这里插入图片描述
为什么要这么写呢,因为unity里面已经内置好了各个平台的近裁剪面和远裁剪面的值,我们只需要判断一下即可
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上面列举了几个,平台的远裁剪面和近裁剪面归一化后的值,我们就可以以此来计算出统一的深度渲染效果,剩下的你可以自己在unity库里面搜索一下,名字在下面列出来了。

在这里插入图片描述

获取深度贴图内的深度

情绪都到这了,那么再写一下如何实现获取深度贴图内的深度吧。
首先,你要在urp Pipeline Asset里面,开启深度纹理渲染。
在这里插入图片描述
开启了以后,你可以在shader里面声明纹理_CameraDepthTexture,就可以获取到深度贴图了。
然后拿着上面获取到的屏幕uv,你就能够获取到深度贴图上的深度了。
在这里插入图片描述
就这么简单,你就获取到了深度,渲染出来,就是这样的
在这里插入图片描述
最后,还有一个问题,现在深度贴图里面的深度和你获取到的深度,它不是线性的,我们需要转成线性的,unity也有内置方法
在这里插入图片描述
根据自己需求用,一个是从近裁剪面开始算的,一个是从相机位置开始算的。1就是远裁剪面。
第一个值就传入你计算出来的深度,或者从深度贴图里面获取到的深度。
第二个值 _ZBufferParams,我上面也截图了,你可以从上面找。

结束。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以为您提供一个基本的Unity URP渲染管线镜面Shader示例。这个Shader将为物体表面创建一个镜面反射效果。 首先,您需要在Unity中创建一个新的URP项目。然后,您可以创建一个新的Shader文件并将以下代码添加到其中: ```csharp Shader "Custom/URP Mirror" { Properties { _Color ("Color", Color) = (1, 1, 1, 1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Metallic ("Metallic", Range(0, 1)) = 0.5 _Smoothness ("Smoothness", Range(0, 1)) = 0.5 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Standard fullforwardshadows #include "UnityCG.cginc" struct Input { float2 uv_MainTex; }; sampler2D _MainTex; fixed4 _Color; float _Metallic; float _Smoothness; void surf (Input IN, inout SurfaceOutputStandard o) { fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Metallic = _Metallic; o.Smoothness = _Smoothness; o.Alpha = c.a; o.Specular = 1; // 启用高光 o.Specular *= c.a; // 根据纹理透明度调整高光强度 } ENDCG } FallBack "Diffuse" } ``` 这个示例中的Shader使用了标准的SurfaceOutputStandard结构,以便与Unity URP渲染管线兼容。它具有_Color(颜色)、_MainTex(主纹理)、_Metallic(金属度)和_Smoothness(光滑度)属性,您可以在材质面板中调整它们。 Shader中的surf函数定义了如何计算表面输出。在这个例子中,我们首先从_MainTex纹理中采样颜色,并将其乘以_Color属性。然后,我们将乘以纹理透明度后的结果设置为表面的漫反射颜色(o.Albedo)。_Metallic和_Smoothness属性用于设置金属度和光滑度。 在这个示例中,我们还启用了高光(o.Specular),并根据纹理透明度调整了高光强度。 最后,请将此Shader文件保存,并将其应用于您想要添加镜面反射效果的物体上。您可以通过创建一个新材质,然后将其Shader属性设置为您创建的Shader来实现这一点。 希望这可以帮助到您!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值