three.jswebglfragment-shadervertex-shaderuv-mapping

Three.js - Vertex Shader UV variable return only 0,0


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.


Solution

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