我正在尝试编写一个着色器来为SceneKit中的自定义几何着色。我要设置颜色,以使面向上的水平表面为白色,面向下的水平表面为黑色,而介于两者之间的所有其他表面根据其方向都是灰色阴影。我使用了材质的表面入口点来调用以下着色器
vec4 normal = vec4(_surface.normal, 1.0);
// Assume value is [-1, 1], scale to [0, 1]
float color = normal.z * 0.5 + 0.5;
_surface.diffuse = vec4(color, color, color, 1.0);
看来normal.z
是相对于相机(或视图)的。我假设我需要转换值,以便它在另一个空间中。我尝试了多个转换(以及转换的组合),例如u_inverseViewTransform
,但是结果似乎都在视图空间中。有人知道如何根据几何图形的表面方向为其着色吗?
答案 0 :(得分:4)
由于_surface.normal
是视图空间中的向量,因此必须将向量转换为世界空间。
将点从世界空间转换为视图空间是由u_viewTransform
完成的,因此逆操作(从视图空间到世界空间)可以由u_inverseViewTransform
完成。
_surface.normal
是方向矢量,但不是点。向量必须由法线矩阵转换,该法线矩阵是4 * 4矩阵左上3 * 3矩阵的逆矩阵:
transpose(inverse(mat3(u_viewTransform)))
请参见Why is the transposed inverse of the model view matrix used to transform the normal vectors?,Why transforming normals with the transpose of the inverse of the modelview matrix?
但是由于u_viewTransform
和u_inverseViewTransform
是Orthogonal matrices的转置,因此可以跳过逆,因为逆矩阵和转置矩阵相等。参见In which cases is the inverse matrix equal to the transpose?。
接下来,您必须按mat3(u_inverseViewTransform)
进行转换:
vec3 normal = mat3(u_inverseViewTransform) * _surface.normal;
float color = normal.z * 0.5 + 0.5;
_surface.diffuse = vec4(color, color, color, 1.0);