[Unity]在Shader中获取摄像机角度、视线的问题

又踩了一坑,好在谷歌到了之前的一个人遇到相同的问题,顺利解决。

先说说问题背景,我目前的毕设是体数据渲染,实现的办法是raycast。最基本的一点就是在fragment program里,获取raycast的方向。

问题出现在加入阴影之后。在这之前,获取方向是没问题的。

在透视相机中,可以简单地用float3 viewDir = normalize(worldPos - _WorldSpaceCameraPos);来获取方向。

在正交相机中,我们需要换个方法,来获取相机的朝向(对正交相机来说,朝向就是raycast的方向)。Unity提供了一个参数来表示当前相机的类型。

因此我们可以用这样的式子替换,来适应两种相机

	float3 viewDir =
		unity_OrthoParams.w * -UNITY_MATRIX_V[2].xyz    //这个-UNITY_MATRIX_V[2].xyz可以用来表示相机的朝向,即C#代码里的transform.forward
		+
		(1- unity_OrthoParams.w) * (worldPos - _WorldSpaceCameraPos);
    

这个时候我用常规的办法加入了阴影(引入ShadowCaster的pass)。并且用同样的办法计算深度然后输出。然后……就出问题了,主要表现是在Shadow Map里渲染错位。

一番排查之后发现了问题。目前我只考虑单个Directional Light,下面也都按照Directional Light来说。按照Shadow Map的流程,我们会需要Directional Light为相机渲染一次Shadow Map。此时该Light相当于一个正交相机。尽管之前我们对两种相机都做了适应,但是……在渲染ShadowMap的时候,这个unity_OrthoParams,是不管用的,因此viewDir的计算是按照透视相机来的,于是就错位了。

所以我们得自己判断正交还是透视了。好在有大神给出了解答:使用UNITY_MATRIX_P[3][3] 进行判断。为0表示透视,1表示正交。具体原理我也不清楚,不过测试之后是完全可行的。

修改后的viewDir如下:

	float3 viewDir = normalize(
		UNITY_MATRIX_P[3][3] * -UNITY_MATRIX_V[2].xyz
		+
		(1 - UNITY_MATRIX_P[3][3]) * (worldPos - _WorldSpaceCameraPos));

另外推荐一个系列教程:http://catlikecoding.com/unity/tutorials/ 其中包括了shader编程,由浅入深地把unity5的standard surface shader复现了一遍,包括编辑器界面。同时包括了各种技术的原理、实现。看一遍绝对是受益颇多。除开shader的教程,其他的几个教程也是非常有意思。总之强烈推荐。

posted @ 2017-05-04 21:04  yangrc1234  阅读(5307)  评论(0编辑  收藏  举报