javascript - Three.js - 使用 ShaderMaterial、TangentSpace 和 fromGeometry 进行法线贴图

标签 javascript graphics three.js 3d light

我正在尝试使用 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 ;
      }

结果如下:
screenshot

这看起来不太正确。我一直在尝试关注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/

相关文章:

c# - 查找两个矩形的重叠区域(在 C# 中)

javascript - Three.js - 未捕获的类型错误 : undefined is not a function

javascript - 如何增加图像的大小以使其可见?

javascript - 如何从txt文件或pastebin中获取文本?

javascript - 如何使用 Easel.js 在 Canvas 中创建数据库图标

c++ - 在对象不再存在后,如何销毁与该对象关联的数据?

javascript - 如何使用新的 THREE.TextureLoader 加载多个纹理

math - Three.js 精准地形碰撞

javascript - Angular 2 中嵌套的 json 数据 - 如何过滤?

javascript - 为什么从数组调用时会出现非法调用?