Three.js - 使用ShaderMaterial,TangentSpace和几何法的正常映射
问题描述:
我想了解使用Three.js的正常映射,但我似乎无法弄清楚它的正确性。Three.js - 使用ShaderMaterial,TangentSpace和几何法的正常映射
这里是我的代码:
的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);
A 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 ]
参见:
什么看起来不对,你可以更具体吗?也许这是一个好主意,只是渲染法线,或者做一个恒定的颜色NdotL来观察表面如何变化。这与反照率混淆。 – pailhead