vec3 xP1 = vertex + vec3(1.0,0.0,0.0); vec3 xN1 = vertex + vec3(-1.0,0.0); vec3 zP1 = vertex + vec3(0.0,1.0); vec3 zN1 = vertex + vec3(0.0,-1.0); float sx = snoise(xP1) - snoise(xN1); float sz = snoise(zP1) - snoise(zN1); vec3 n = vec3(-sx,1.0,sz); normalize(n); return n;
以上实际产生的照明像perlin噪音一样四处移动!那么关于如何正确获得每顶点法线的任何建议?
解决方法
所以,我们假设您的位置计算如下:
vec3 CalcPosition(in vec2 loc) { float height = MyNoiseFunc2D(loc); return vec3(loc,height); }
这会生成3D位置.但这个位置在哪个空间?这就是问题所在.
大多数噪声函数都希望loc在某个特定的浮点范围内是两个值.您的噪声函数有多好将决定您可以传入值的范围.现在,如果您的模型空间2D位置不能保证在噪声函数的范围内,那么您需要将它们转换为该范围,进行计算,以及然后将其转换回模型空间.
这样,您现在拥有3D位置. X和Y值的变换很简单(与噪声函数空间的变换相反),但是Z的变换是什么?在这里,你必须在高度上应用某种比例.噪声函数将返回范围[0,1]上的数字,因此您需要将此范围缩放到与X和Y值相同的模型空间.这通常通过选择最大高度并适当地缩放位置来完成.因此,我们修改的计算位置看起来像这样:
vec3 CalcPosition(in vec2 modelLoc,const in mat3 modelToNoise,const in mat4 noiseToModel) { vec2 loc = modelToNoise * vec3(modelLoc,1.0); float height = MyNoiseFunc2D(loc); vec4 modelPos = noiseToModel * vec4(loc,height,1.0); return modelPos.xyz; }
两个矩阵转换为噪声函数的空间,然后转换回来.您的实际代码可能会使用不太复杂的结构,具体取决于您的用例,但完整的仿射变换很容易描述.
好了,既然我们已经确定了这一点,那么你需要记住的是:除非你知道它处于什么空间,否则没有任何意义.你的正常,你的立场,没有关系,直到你确定它所处的空间.
此函数返回模型空间中的位置.我们需要计算模型空间中的法线.要做到这一点,我们需要3个位置:顶点的当前位置,以及稍微偏离当前位置的两个位置.我们获得的位置必须在模型空间中,否则我们的正常情况不会.
因此,我们需要具备以下功能:
void CalcDeltas(in vec2 modelLoc,const in mat4 noiseToModel,out vec3 modelXOffset,out vec3 modelYOffset) { vec2 loc = modelToNoise * vec3(modelLoc,1.0); vec2 xOffsetLoc = loc + vec2(delta,0.0); vec2 yOffsetLoc = loc + vec2(0.0,delta); float xOffsetHeight = MyNoiseFunc2D(xOffsetLoc); float yOffsetHeight = MyNoiseFunc2D(yOffsetLoc); modelXOffset = (noiseToModel * vec4(xOffsetLoc,xOffsetHeight,1.0)).xyz; modelYOffset = (noiseToModel * vec4(yOffsetLoc,yOffsetHeight,1.0)).xyz; }
显然,您可以将这两个函数合并为一个.
增量值是噪声纹理输入空间中的小偏移量.此偏移的大小取决于您的噪声功能;它需要足够大才能返回与实际当前位置返回的高度明显不同的高度.但它需要足够小,以免你从噪声分布的随机部分中拉出来.
你应该了解你的噪音功能.
现在您在模型空间中有三个位置(当前位置,x偏移和y偏移),您可以在模型空间中计算顶点法线:
vec3 modelXGrad = modelXOffset - modelPosition; vec3 modelYGrad = modelYOffset - modelPosition; vec3 modelNormal = normalize(cross(modelXGrad,modelYGrad));
从这里开始做常规事.但永远不要忘记跟踪各种向量的空间.
哦,还有一件事:这应该在顶点着色器中完成.在几何着色器中没有理由这样做,因为没有计算影响其他顶点.让GPU的并行性为您服务.