2017-10-07 101 views
2

我想了解使用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 ; 
     } 

下面是結果:
screenshot

這看起來不太正確。我一直在試圖遵循http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-13-normal-mapping/,但在three.js中實現它,但沒有運氣。有沒有人有任何想法?

+0

什麼看起來不對,你可以更具體嗎?也許這是一個好主意,只是渲染法線,或者做一個恆定的顏色NdotL來觀察表面如何變化。這與反照率混淆。 – pailhead

回答

2

您沒有正確指定切線空間矩陣。將其更改爲:

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 ] 


參見:

+0

這是一個很好的答案,但是這個問題不適合它:)'webgl矩陣中列的主要順序會更好。仍然投票了 – pailhead

+0

@pailhead謝謝,一方面你是對的,但另一方面它指出了一個錯誤,在問題的源代碼。 – Rabbid76

+0

應該以某種方式編輯問題嗎? – pailhead