我想了解使用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中實現它,但沒有運氣。有沒有人有任何想法?
什麼看起來不對,你可以更具體嗎?也許這是一個好主意,只是渲染法線,或者做一個恆定的顏色NdotL來觀察表面如何變化。這與反照率混淆。 – pailhead