我正在尝试使用 Three.js 学习法线贴图,但我似乎无法正确理解。
这是我的代码:
Javascript:
var bufferGeometry = new THREE.BufferGeometry();
bufferGeometry.fromGeometry( new THREE.BoxGeometry(2,2,2) );
var positionAttributes = bufferGeometry.getAttribute('position');
var uvAttributes = bufferGeometry.getAttribute('uv');
var realVertices = [];
var realUvs = [];
for (var i = 0; i < positionAttributes.array.length ; i += 3){
realVertices.push(new THREE.Vector3(positionAttributes.array[i+0], positionAttributes.array[i+1], positionAttributes.array[i+2] ));
}
for (var i = 0; i < uvAttributes.array.length; i+= 2){
realUvs.push (new THREE.Vector2( uvAttributes.array[i], uvAttributes.array[i+1] ) );
}
var tangents = new Float32Array(positionAttributes.array.length);
var bitangents = new Float32Array(positionAttributes.array.length);
var tangArray = [];
var bitangentArray = [];
for (var i = 0; i < realVertices.length ; i += 3){
var v0 = realVertices[i+0];
var v1 = realVertices[i+1];
var v2 = realVertices[i+2];
var uv0 = realUvs[i+0];
var uv1 = realUvs[i+1];
var uv2 = realUvs[i+2];
var deltaPos1 = v1.sub(v0);
var deltaPos2 = v2.sub(v0);
var deltaUV1 = uv1.sub(uv0);
var deltaUV2 = uv2.sub(uv0);
var r = 1.0 / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
var tangent = deltaPos1.multiplyScalar(deltaUV2.y).sub( deltaPos2.multiplyScalar(deltaUV1.y) ).multiplyScalar(r); //p1 * uv2.y - p2 * uv1.y
var bitangent = deltaPos2.multiplyScalar(deltaUV2.x).sub( deltaPos1.multiplyScalar(deltaUV2.x) ).multiplyScalar(r);
tangArray.push(tangent.x);
tangArray.push(tangent.y);
tangArray.push(tangent.z);
tangArray.push(tangent.x);
tangArray.push(tangent.y);
tangArray.push(tangent.z);
tangArray.push(tangent.x);
tangArray.push(tangent.y);
tangArray.push(tangent.z);
bitangentArray.push (bitangent.x);
bitangentArray.push (bitangent.y);
bitangentArray.push (bitangent.z);
bitangentArray.push (bitangent.x);
bitangentArray.push (bitangent.y);
bitangentArray.push (bitangent.z);
bitangentArray.push (bitangent.x);
bitangentArray.push (bitangent.y);
bitangentArray.push (bitangent.z);
}
for (var i = 0; i < bitangentArray.length; i++ ){
tangents[i] =tangArray[i];
bitangents[i] = bitangentArray[i];
}
bufferGeometry.addAttribute( 'tangent', new THREE.BufferAttribute( tangents, 3 ) );
bufferGeometry.addAttribute( 'bitangent', new THREE.BufferAttribute( bitangents, 3 ) );
顶点着色器:
varying vec3 L;
varying vec3 V;
uniform vec3 lightPosition;
uniform vec3 eyePosition;
varying vec2 vUv;
attribute vec3 tangent;
attribute vec3 bitangent;
void main() {
vUv = uv; //uv is built-in
mTangent = bitangent;
vec3 surfaceNormal = (modelViewMatrix * vec4(normal,0.0)).xyz;
vec3 norm = normalize(surfaceNormal);
vec3 tang = normalize((modelViewMatrix * vec4(tangent, 0.0)).xyz);
vec3 bitang = normalize(cross(norm, tang));
mat3 toTangentSpace = mat3(
tang.x, bitang.x, norm.x,
tang.y, bitang.y, norm.y,
tang.z, bitang.z, norm.z
);
vec3 mvPosition = (modelViewMatrix * vec4(position,1.0)).xyz;
L = toTangentSpace * (lightPosition - mvPosition) ;
V = toTangentSpace * (- mvPosition);
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
片段着色器:
varying vec3 L;
varying vec3 V;
uniform vec3 lightColor;
uniform sampler2D baseTexture;
uniform sampler2D normalMap;
varying vec2 vUv;
void main() {
vec4 normalMapValue = 2.0 * texture2D(normalMap, vUv, -1.0) - 1.0;
vec3 unitNormal = normalize(normalMapValue.rgb);
vec3 unitVectorToCamera = normalize(V);
vec3 totalDiffuse = vec3(0.0);
vec3 totalSpecular = vec3(0.0);
float distance = length(L);
vec3 unitLightVector = normalize(L);
float nDotl = dot(unitNormal,unitLightVector);
float brightness = max(nDotl,0.0);
totalDiffuse = vec3( 0.5,0.5,0.5) + totalDiffuse + (brightness * lightColor);
vec4 textureColour = texture2D(baseTexture,vUv);
gl_FragColor= vec4(totalDiffuse,1.0) * textureColour ;
}
这看起来不太正确。我一直在尝试关注http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-13-normal-mapping/但在 Three.js 中实现它,但没有运气。有人有什么想法吗?
最佳答案
您没有正确指定切线空间矩阵。将其更改为:
mat3 toTangentSpace = mat3( tang, bitang, norm );
4*4 矩阵如下所示:
c0 c1 c2 c3 c0 c1 c2 c3
[ Xx Yx Zx Tx ] [ 0 4 8 12 ]
[ Xy Yy Zy Ty ] [ 1 5 9 13 ]
[ Xz Yz Zz Tz ] [ 2 6 10 14 ]
[ 0 0 0 1 ] [ 3 7 11 15 ]
在 GLSL 中,列的寻址方式如下:
vec4 c0 = m44[0].xyzw;
vec4 c1 = m44[1].xyzw;
vec4 c2 = m44[2].xyzw;
vec4 c3 = m44[3].xyzw;
4*4 矩阵可以这样初始化:
mat4 m44 = mat4(c0, c1, c2, c3);
3*3 矩阵如下所示:
x y z
[ Xx Yx Zx ] [ 0 4 8 ]
[ Xy Yy Zy ] [ 1 5 9 ]
[ Xz Yz Zz ] [ 2 6 10 ]
在 GLSL 中,列的寻址方式如下:
vec3 x = m33[0].xyz;
vec3 y = m33[1].xyz;
vec3 z = m33[2].xyz;
一个 3*3 矩阵可以这样初始化:
mat3 m33 = mat3(x, y, z);
注意,4*4矩阵的内存图像如下所示:
[ Xx, Xy, Xz, 0, Yx, Yy, Yz, 0, Zx, Zy, Zz, 0, Tx, Ty, Tz, 1 ]
像这样的 3*3 矩阵:
[ Xx, Xy, Xz, Yx, Yy, Yz, Zx, Zy, Zz, Tx, Ty, Tz ]
请参阅:
关于javascript - Three.js - 使用 ShaderMaterial、TangentSpace 和 fromGeometry 进行法线贴图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46615844/