找回密码
 立即注册
查看: 515|回复: 2

[笔记] Unity Shader ScreenPos详解

[复制链接]
发表于 2021-3-8 09:40 | 显示全部楼层 |阅读模式
最近有人询问《卡通湖水渲染》中基于深度着色方法中深度差的计算方法,发现是摄像机深度图中的深度值(线性化后)减去ScreenPos.w,而不是ScreenPos.z,这一章正好一起讲一讲屏幕空间位置的计算方法及其中的一些相关原理。其中部分内容涵盖个人理解,如有疏漏,还请大佬们指正交流!
1. ComputeScreenPos函数

首先要知道ScreenPos中存储的是什么,就要知道shader中ScreenPos是如何求得的,一般情况下,我们会采用ComputeScreenPos函数来计算模型顶点的ScreenPos(需要注意的是,这里的ScreenPos并不是真正的顶点在屏幕中的坐标值,而是一个齐次空间坐标)
我们可以在Unity内置shader中找到这个函数的内部定义:
其中UNITY_SINGLE_PASS_STEREO宏是用来控制不同平台的计算方法的差异,其核心的计算方法在ComputeNonStereoScreenPos方法中,首先,其传入的float4类型的pos值是模型顶点的齐次裁剪空间的坐标值,其中x、y的范围都是在-w到w的范围内的(后面会讲),将齐次裁剪空间的坐标映射到屏幕空间,我们假设屏幕空间的宽高分别为WidthHeight,那么转换公式为:
我们再来看一下Unity做的处理,其中_ProjectionParams.x是用来处理平台差异的(opengl原点为左下角,而DirectX的原点在左上角,ProjectionParams.x的值一般为1或-1),可以发现,其返回的x、y值的范围是0到w,并非我们所期望的0到width/height。这其实是因为unity在顶点着色器中并不会进行透视除法的计算,我们通过渲染管线的流程也很容易发现,透视除法一般在裁剪后的屏幕映射阶段进行(顶点数据一般由GPU管线底层自动执行,但我们自己定义的数据需要手动进行),这是由于齐次裁剪空间是一个非线性的空间(透视投影),从几何阶段传入到光栅化阶段的几何数据需要进行插值从而计算出片元的相关数据,而插值过程是线性的,提前进行透视除法会使得结果不准确,所以我们需要在片元着色器手动进行透视除法的实现,而这一般使用Tex2DProj函数实现:
2、齐次裁剪空间
介绍完了ComputeScreenPos函数,我们上面说道齐次裁剪空间的顶点坐标值为xy在【-w,w】范围内,下面就来详细介绍一下其中的原理与相关的矩阵变换,帮助大家了解ScreenPos的整个变换过程
齐次坐标

什么是齐次坐标呢?
简单地说,就是使用更高维度的数据去表示一个低维度的数据,比如用(4,3,2,1)去表示一个三维空间的点(表示三维空间的点只需要三个参数)。在Unity中,我们知道对模型顶点进行位移是需要额外多出一个维度的(相关变换可以参考冯乐乐的《Unity shader入门精要》),齐次坐标的部分功能便是如此。当然,除了为了表示位移,齐次坐标主要是为投影和裁剪做准备的,其第四个参数w将会成为判断该点是否被裁剪的关键。
       从摄像机空间到裁剪空间的矩阵是投影矩阵,但要注意的是,投影矩阵并没有实现真正的投影,而是将顶点变换到齐次裁剪坐标,为裁剪做准备,并未进行透视除法(原因上面讲过)。投影矩阵的变换过程这里不加讨论(详细过程参看《Shader入门精要》第78页),经过投影矩阵变换后,透视投影下的顶点齐次坐标w值为-z,正交投影的w值为1。
透视投影
正交投影


从图中可以看出,经过UnityObjectToClipPos函数变换的顶点坐标,其表示深度的参数已经从z值变为了w值,此时的z值是一个跟远近裁剪面相关的数据,我们通过判断x、y、z值是否都在【-w,w】的范围内,如果不在,就要对其进行裁剪剔除。
如此,我们结合上面的ComputeScreenPos函数可以发现,ComputeScreenPos并未对顶点数据的z、w值进行修改,所以在进行深度比较时使用的是screenPos.w而不是screenPos.z
3. 总结

本文中比较关键的知识点便是齐次裁剪空间是一个非线性空间,从几何阶段传入光栅化阶段的顶点数据需要进行插值变换,插值变换的过程通常是线性过程
对几何阶段,尤其是几次空间变换的了解是unity shader编写的基础知识,必须巩固扎实,把握其中的每一个细节。当然,这只是顶点着色器阶段,但在很多比较基础的效果材质中,往往顶点着色器中的工作便决定了整体shader的制作思路。选择在哪个空间进行何种变换符合项目的效果需求,如果对这一部分理解充分的话,方案思路也会随之得到扩展,代码的编写也就更加得心应手了

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-3-8 09:44 | 显示全部楼层
又是大佬你
发表于 2021-3-8 09:52 | 显示全部楼层
既然说到了ComputeScreenPos,大佬能讲一下怎么在shader里算顶点在屏幕上的xy坐标吗?
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-18 20:37 , Processed in 0.101140 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表