Three.js-Vertex Shader UV变量仅返回0,0

时间:2018-12-08 09:28:13

标签: three.js webgl fragment-shader vertex-shader uv-mapping

我用OBJLoader加载了一个对象。我想使用带有纹理的着色器材质。我将纹理传递给材质的统一参数。 我将UV变量从顶点着色器传递到片段着色器。

但是当我使用uv坐标映射我的纹理时,我总是得到0,0,或者至少这就是它的样子。整个对象都带有纹理的左下像素。

这是我的着色器:

  <script type='x-shader/x-vertex' id='vertex-shader'>
    uniform float u_time;
    varying vec2 vUv;
    void main() {
      vUv = uv;
      vec4 pos = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      gl_Position = pos;
    }
  </script>
  <script type='x-shader/x-fragment' id='fragment-shader'>
    precision highp float;
    uniform float u_time;
    uniform vec2 u_resolution;
    uniform sampler2D texture;
    varying vec2 vUv;
    void main(){
      vec2 st = vUv;
      vec4 tex = texture2D(texture, st);
      gl_FragColor = tex;
     }
  </script>

这是我加载对象和分配材料的方式

var loader = new THREE.OBJLoader();
loader.load(
    'assets/standing.obj',
    function (object){

    main.man = object;
    main.man.position.set(0,-600,400);

    main.texture = new THREE.TextureLoader().load( 'assets/na_00004c.jpg' );

    main.texture_needsUpdate = true;
    var uniforms = {
      u_time:{type:'f', value:0.0},
      u_mouse:{type:'v2', value: new THREE.Vector2()},
      u_resolution: {type: 'v2', value: {x:2048.,y:1024.}},
      texture: {type: 't', value: main.texture}
    }

    main.material = new THREE.ShaderMaterial({  
      uniforms: uniforms,
      vertexShader: document.getElementById('vertex-shader').textContent,
      fragmentShader: document.getElementById('fragment-shader').textContent,
      transparent: true
    });

    main.material.needsUpdate = true;
    main.material.side = THREE.DoubleSide;

    main.man.traverse(function(child){
      if(child instanceof THREE.Mesh){
        child.material = main.material;
        child.material.needsUpdate = true;
        child.geometry = new THREE.Geometry().fromBufferGeometry( child.geometry );  
        child.geometry.computeVertexNormals();
        child.geometry.elementsNeedUpdate = true;
        child.geometry.mergeVertices(); 
        child.verticesNeedUpdate = true;
        child.normalsNeedUpdate = true;
        child.uvsNeedUpdate = true;
        child.material.flatShading = THREE.SmoothShading;
      } 
    });

        main.scene.add(main.man);

    },
    function (xhr){
        console.log((xhr.loaded/xhr.total*100)+'% loaded');
    },
    function (error){
        console.log(error,'An error happened');
    }
);

这里有完整的例子 http://cmt.re/dev/na/

这是我要用作纹理的图像 http://cmt.re/dev/na/assets/na_00004c.jpg

有人知道为什么会这样吗?

非常感谢。

1 个答案:

答案 0 :(得分:2)

您的代码可以正常工作,但您的*.obj文件不包含任何纹理坐标。 Wavefront OBJ文件(.obj文件)是一个文本文件,纹理坐标是带有键vt的条目,如果缺少这些条目,则网格将没有任何纹理坐标。

您的代码运行良好,请参见示例,其中我将您的原始代码与一个简单模型一起使用:

var main = new function(){
  
  this.init = function(){
    
    this.initThree();
    
  }
  
  this.initThree = function(){
    
    main.scene = new THREE.Scene();
    main.scene.background = new THREE.Color(0xCCCCCC);
    
    var aspectRatio = window.innerWidth / window.innerHeight;
    main.camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 100000);
    //main.camera.position.set(-40, 0, 512);
    main.camera.position.set(1,2,0);
    
    main.renderer = new THREE.WebGLRenderer({antialias: true});
    main.renderer.setPixelRatio(window.devicePixelRatio);
    main.renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(main.renderer.domElement);

    main.controls = new THREE.OrbitControls(main.camera);
    main.controls.enableDamping = true;
    main.controls.dampingFactor = 0.1;
    main.controls.screenSpacePanning = false;

    var helper = new THREE.GridHelper(2000, 100);
    helper.material.opacity = 0.25;
    helper.material.transparent = true;
    main.scene.add(helper);

    var axis = new THREE.AxesHelper();
    main.scene.add(axis);
    
    makeTextFile = function (text) {
      var data = new Blob([text], {type: 'text/plain'});
      var textFile = window.URL.createObjectURL(data);
      return textFile;   
    }
    var textbox_obj = document.getElementById('plane_obj');
    var obj_url = makeTextFile(textbox_obj.value);

    var loader = new THREE.OBJLoader();
    loader.load(
    	obj_url,
    	function (object){
        
        main.man = object;
        //main.man.position.set(0,-600,400);
        main.man.position.set(0,0,0);
        
        main.texture = new THREE.TextureLoader().load( 'https://raw.githubusercontent.com/Rabbid76/graphics-snippets/master/resource/texture/Gominolas.png' );
        
        main.texture_needsUpdate = true;
        var uniforms = {
          u_time:{type:'f', value:0.0},
          u_mouse:{type:'v2', value: new THREE.Vector2()},
          u_resolution: {type: 'v2', value: {x:2048.,y:1024.}},
          texture: {type: 't', value: main.texture}
        }
        
        main.material = new THREE.ShaderMaterial({  
          uniforms: uniforms,
          vertexShader: document.getElementById('vertex-shader').textContent,
          fragmentShader: document.getElementById('fragment-shader').textContent,
          transparent: true
        });
        
        main.material.needsUpdate = true;
        main.material.side = THREE.DoubleSide;
        
        // main.material = new THREE.MeshNormalMaterial();
        
        main.man.traverse(function(child){
          if(child instanceof THREE.Mesh){
            child.material = main.material;
            child.material.needsUpdate = true;
            child.geometry = new THREE.Geometry().fromBufferGeometry( child.geometry );  
            child.geometry.computeVertexNormals();
            child.geometry.elementsNeedUpdate = true;
            child.geometry.mergeVertices(); 
            child.verticesNeedUpdate = true;
            child.normalsNeedUpdate = true;
            child.uvsNeedUpdate = true;
            child.material.flatShading = THREE.SmoothShading;
          } 
        });
        
    		main.scene.add(main.man);
        
    	},
    	function (xhr){
    		console.log((xhr.loaded/xhr.total*100)+'% loaded');
    	},
    	function (error){
    		console.log(error,'An error happened');
    	}
    );
    
    window.onresize = main.onResize;

    this.render();
    
  }
  
  this.render = function(){

    var time = Date.now();
    main.controls.update();
    requestAnimationFrame(main.render);
    main.renderer.render(main.scene, main.camera);
    
  }
  
  this.onResize = function(event) {
    
    main.renderer.setSize(window.innerWidth, window.innerHeight);
    main.camera.aspect = window.innerWidth / window.innerHeight;
    main.camera.updateProjectionMatrix();
    
  }

}

 main.init();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/99/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/OBJLoader.js"></script>

<textarea id="plane_obj" style="display:none;">
    v -1.000000 0.000000 1.000000
    v 1.000000 0.000000 1.000000
    v -1.000000 0.000000 -1.000000
    v 1.000000 0.000000 -1.000000
    
    vt 0.000000 0.000000
    vt 1.000000 0.000000
    vt 0.000000 1.000000
    vt 1.000000 1.000000
    
    vn 0.0000 1.0000 0.0000
    
    f 1/1/1 2/2/1 4/4/1 3/3/1
</textarea>

<script type='x-shader/x-vertex' id='vertex-shader'>
uniform float u_time;
varying vec2 vUv;
void main() {
    vUv = uv;
    vec4 pos = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    gl_Position = pos;
}
</script>

<script type='x-shader/x-fragment' id='fragment-shader'>
precision highp float;
uniform float u_time;
uniform vec2 u_resolution;
uniform sampler2D texture;
varying vec2 vUv;
void main(){
    vec2 st = vUv;
    vec4 tex = texture2D(texture, st);
    gl_FragColor = tex;
}
</script>