Three.js-顶点着色器UV变量只返回0,0[英] Three.js - Vertex Shader UV variable return only 0,0

本文是小编为大家收集整理的关于Three.js-顶点着色器UV变量只返回0,0的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我用objloader加载了一个对象.我想使用带有纹理的着色器材料.我将纹理传递给材料的制服参数. 我将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/na/assets/na_000000004c.jpgge/a >

有人知道为什么会发生这种情况吗?

非常感谢.

推荐答案

您的代码工作正常,但是您的*.obj文件不包含任何纹理坐标. wavefront obj file(.obj file)是文本文件,纹理坐标是条目键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.renderer.domElement);
    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://cdn.jsdelivr.net/npm/three@0.115/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115/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>

本文地址:https://www.itbaoku.cn/post/2091110.html

问题描述

I loaded an object with OBJLoader. I want to use a Shader Material with a texture. I pass my texture to the uniforms parameters of the material. I pass the UV variable from the vertex shader to the fragment shader.

But when I use the uv coordinate for mapping my texture I get always 0,0 or at least this is what it looks like. The whole object is coloured with the bottom left pixel of the texture.

Here are my shaders:

  <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>

And here is how I load the object and assign the material

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');
    }
);

Here there is the full example http://cmt.re/dev/na/

This is the image that I want to use as a texture http://cmt.re/dev/na/assets/na_00004c.jpg

Does somebody know why this is happening?

Thanks a lot.

推荐答案

Your code works fine, but your *.obj file doesn't contain any texture coordinates. The Wavefront OBJ file (.obj file) is a text file, texture coordinates are the entries with the key vt, if this entries are missing, the mesh doesn't have any texture coordinates.

Your code works fine, see the example, where I used your original code with a simple model:

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.renderer.domElement);
    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://cdn.jsdelivr.net/npm/three@0.115/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115/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>