UGP1-9 Cube room投影

发布于 14 天前  46 次阅读


本篇讨论UnityGraphicsPrograming第一册第九章内容 MultiPlane PerspectiveProjection。

▲9.1 渲染流水线中的空间转换问题
作者提到了Object、World、View、Clip、DNC、Screen等常见的坐标系。

▲9.2 复数相机的观察内容可以实现无缝拼接
这个类似于Cubemap,以一个观察角度记录6个方向的图像。
在只有观察角度变化且不移动的情况下,不会感觉到6个面之间有缝隙。
这个观点可能和Unity达哥的想法类似,参考Unity无模型研究

▲9.3 证明View→Clip矩阵
国内这边,关于渲染的基础数学资料主要是《Shader入门精要》,这里不重复研究,可参考我之前的笔记。
View→Clip矩阵(4X4)中包含5个参数,参与计算的点必须是4元的,且w分量为1。
在URP中,可使用TransformObjectToHClip、TransformWorldToHClip、TransformWViewToHClip等;
可以参考SRP包文件夹下的/ShaderLibrary/SpaceTransforms.hlsl。

▲9.3.1 View→Clip矩阵中值的注意的地方
在渲染流水线中,vertex shader会输出Clip空间坐标,这个坐标将转换为NDC坐标、用于深度测试。
由于OpenGL和DX标准的差异,DNC空间中的Z轴范围和方向不同。

平台差异
1.RenderTexture 坐标系
DX的(0, 0)在左上角,OpenGL的(0, 0)在左下角。
在Shader代码中,我们经常会有Texture类型的变量,用于采样。
如果我们tex2D(_MainTex, float2(0, 0)),在不同平台中不会出BUG,是因为Unity将DX模式下shader的Texture上下翻转,但是本质上同样的坐标(0, 0)可能描述的是两个不同的位置。
由于有Unity的帮忙,我们通常无需做什么(包括在Blit时),只要Texture是shader的变量。
当需要基于UV坐标系渲染时,判断Unity是否做了Texture翻转:
UNITY_UV_STARTS_AT_TOP
_ProjectionParams.x < 0
_MainTex_TexelSize.y < 0
开启了MSAA的情况下,需要手动翻转UV的Y轴。

2.NDC空间Z轴和depth buffer
DX中NDC空间Z轴范围为1至0,1处为near,0处为far。
OpenGL中NDC空间Z轴范围为-1至1,-1处为为near,1处为far。
但是,这些并不影响ZTest(depth buffer)的默认值LessEqual,离相机更近-更小的值才能通过深度测试。
在FrameDebug中观察深度贴图可以看到深度轮廓,近的物体亮红,远的物体暗红。
当在深度值颠倒的平台中使用深度值时:
UNITY_REVERSED_Z is defined
_CameraDepth Texture texture range is 1 (near) to 0 (far).
Clip space range is within “near” (near) to 0 (far).
需要获取深度值时:
float z = tex2D(_CameraDepthTexture, uv);
#if defined(UNITY_REVERSED_Z)
z = 1.0f - z;
#endif
如果从Clip坐标系获取深度值需要处理平台差异。

3.const语法
在HLSL中,const在声明范围内只读,可以通过任何方式进行初始化。
在GLSL中,const必须在编译时必须是常量。
建议采样GLSL中const的语义,避免平台冲突。

4.Semantics平台差异
使用Unity推荐设置
vertex输出位置时使用SV_POSITION
fragment输出颜色时使用SV_Target

5.Shader Model级别
自定义Buffer和可写入Texture2D需要DX11以上支持,对应Shader Model 4.5+。
#ifdef SHADER_API_D3D11
StructuredBuffer\ myColors;
RWTexture2D\ myRandomWriteTexture;
#endif

▲9.4 对视椎体的操作
前面提到,Cubemap中因为无法移动,只能转向,这样容易让人感觉画面是贴在地面上的。
随着人物移动需要有画面上的变化,特别是近处的物体。
这里提出修改Clip矩阵,调整视椎体形状的方案:

通过提供x和y轴上的偏移量(修改第一行+第二行的第三个变量),使是视椎体的尾部左右上下移动。
这样人物向前走时,视椎体上移,看起来就像视椎体内物体相对向后运动了。

▲Unity工程部分
运行工程后搜索“camera”,我们可以找到7个相机:
5个相机对应地图A中的前、后、左、右、下5个面,都渲染到RenderTexture。
2个相机分别对应地图B中的第三人称相机和第一人称相机,人物处于一个封闭的Cube中,前面5个相机渲染出的RenderTexture作为Cube的壁纸。
在人物移动时,地图A中的5个相机会有对视椎体的操作,导致Cube中人物观察到的画面有变化。

总结:
代码和效果上均没有亮点,作为一种沉浸式体验的假设,远没有VR(双眼渲染)的成熟程度。
但是可以往Unity达哥的烘焙方向走,使移动设备也可以渲染出复杂的室内场景。


关注成长,注重因果。