0

I'm trying to create a shader for a 3d object generated from Maya.

I can get the 3d object to load, however when I try to apply the shader I'm getting this error:

GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 1

From what I have read, I understand that I need to define the vertices, but I have no idea on how to do this.

Here is the code:

<html xmlns="http://www.w3.org/1999/xhtml"><head>
<title>3D render</title>
<script src="js/three.min.js"></script>
<script src="js/OBJLoader.js"></script>
</head>

<body onload="start()" >
<script> 
    var gl;
    var camera, cubeCamera, scene, renderer; 
    var intervalProgress;  

    var fov = 70,

        lon = 0, 
        lat = 70,  
        phi = 0, 
        theta = 0;

    init(); 
    animate(); 

    function init() {

        camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1000 ); 

        scene = new THREE.Scene();

        var mesh = new THREE.Mesh( new THREE.SphereGeometry( 500, 60, 40 ), new THREE.MeshBasicMaterial({color: 0xFFFFFF}) ); 
        mesh.scale.x = -1;

        scene.add( mesh );


        var light = new THREE.PointLight(0xFFFFFF);
        light.position.set(0, 0, 500);
        scene.add(light);

        renderer = new THREE.WebGLRenderer( { antialias: true } ); 
        renderer.setSize( window.innerWidth, window.innerHeight ); 

        document.body.appendChild( renderer.domElement );


            var material = new THREE.MeshBasicMaterial( { color:0xFFFFFF } );

        var loader = new THREE.OBJLoader();

        loader.load( "mesh/3d.obj", function ( object ) {

                object.traverse(function(child) {
                        if (child instanceof THREE.Mesh) {


                            var vertShader = document.getElementById('vertexShader').innerHTML;
                            var fragShader = document.getElementById('fragmentShader').innerHTML;                           


                            var uniforms = {
                                texture1: { type: "t", value: THREE.ImageUtils.loadTexture( "textures/texture.jpg" ) }
                            };

                            material = new THREE.ShaderMaterial({
                                uniforms: uniforms,
                                vertexShader: vertShader,
                                fragmentShader: fragShader,
                                wrapping: THREE.ClampToEdgeWrapping,
                                shading: THREE.SmoothShading,
                                side: THREE.DoubleSide
                            });


                            child.material = material;
                            child.material.needsUpdate = true;
                            // child.material.color.setRGB (1, 0, 0);


                        }
                    });

                    //SET SCALE, POSITION AND ROTATION OF OBJECT  
                    object.scale.set( 40,40,40 );
                    object.rotation.x = 0;
                    object.rotation.y = 90; 
                    object.position.y = 0;

                    scene.add(object);

              }); 



    }

    function animate() { 
        requestAnimationFrame( animate );
        render(); 
    }

    function render() {

        var time = Date.now(); 
        lon += .15; 
        lat = Math.max( - 85, Math.min( 85, lat ) );
        phi = THREE.Math.degToRad( 90 - lat );
        theta = THREE.Math.degToRad( lon );

        camera.position.x = 100 * Math.sin( phi ) * Math.cos( theta );
        camera.position.y = 100 * Math.cos( phi );
        camera.position.z = 100 * Math.sin( phi ) * Math.sin( theta ); 
        camera.lookAt( scene.position ); 

        renderer.render( scene, camera ); 
    }

    function start() {
      var canvas = document.getElementById("glcanvas");

      gl = initWebGL(canvas);      // Initialize the GL context

      if (gl) {
        gl.clearColor(0.0, 0.0, 0.0, 1.0);                      // Set clear color to black, fully opaque
        gl.enable(gl.DEPTH_TEST);                               // Enable depth testing
        gl.depthFunc(gl.LEQUAL);                                // Near things obscure far things
        gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);      // Clear the color as well as the depth buffer.
      }
    }

    function initWebGL(canvas) {
      gl = null;

      try {
        // Try to grab the standard context. If it fails, fallback to experimental.
        gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
      }
      catch(e) {}

      // If we don't have a GL context, give up now
      if (!gl) {
        alert("Unable to initialize WebGL. Your browser may not support it.");
        gl = null;
      }

      return gl;
    }

</script> 

<script id="vertexShader" type="x-shader/x-vertex">
varying vec2 vUv;

void main() {
    vUv = uv;

    gl_Position =   projectionMatrix * 
                    modelViewMatrix * 
                    vec4(position,1.0);
}
</script>

<script id="fragmentShader" type="x-shader/x-fragment">
uniform sampler2D texture1;

varying vec2 vUv;

void main() {
    gl_FragColor = vec4(0.5, 0.2, 1.0, 1.0); 
}
</script>
<canvas id="glcanvas" width="1" height="1"></canvas>
<canvas width="1920" height="951"></canvas>
</body>
</html>
9
  • you do not have scene.add( object ). is it somewhere else in your code? Commented Oct 31, 2015 at 2:35
  • Yes, I did have it in there, I just forgot to copy it into this question. I have edited the question to include the complete code. If I comment out the shader it works. Commented Oct 31, 2015 at 3:36
  • 1
    you should move the shader and material code outside the object.traverse() code. Why are you keep downloading the texture for each child? It is always the same. Commented Oct 31, 2015 at 3:41
  • Yes, you're right. But I will still have the same problem. Commented Oct 31, 2015 at 3:54
  • do var texture = THREE.ImageUtils.loadTexture( "textures/texture.jpg" ) and then value: texture. actually what you should do is use the texture loader manager and assign the texture to the material only when the texture has downloaded. look at threejs.org/docs/#Reference/Loaders/TextureLoader Commented Oct 31, 2015 at 3:59

1 Answer 1

1

I found the problem, it was a combination of all mentioned above, so I cleaned up the code: here is the working example:

function loadObj(name, metal){

var material = null;
loadTexture('textures/'+metal+'.jpg', function(texture){
    loadTexture('normal/243-normal.jpg', function(texture2){
        var material = createMetalShader(metal, texture, texture2);
        var loader = new THREE.OBJLoader();

        loader.load( "mesh/"+name+".obj", function ( object ) {


            object.traverse(function(child) {
                if (child instanceof THREE.Mesh) {

                    child.geometry = new THREE.Geometry().fromBufferGeometry( child.geometry );  
                    child.geometry.mergeVertices(); 

                    //assignUVs(child.geometry);

                    child.material = material;
                    child.verticesNeedUpdate = true;
                    child.normalsNeedUpdate = true;
                    child.uvsNeedUpdate = true;

                    child.material.shading = THREE.SmoothShading;
                    child.geometry.computeVertexNormals(); 

                }

                object.scale.set( 30,30,30 );
                object.rotation.x = 0;
                object.rotation.y = 90; 
                object.position.y = 0;
                scene.add(object);
                currentMetalObject = object;
            });
        });
    });
});


}

function loadTexture(path, callback){
var loader = new THREE.TextureLoader();

// load a resource
loader.load(path,function ( texture ) {
        callback(texture);
    },
    function ( xhr ) {
        console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
    },
    function ( xhr ) {
        console.log( 'An error happened' );
    }
);


}

function createMetalShader(metal, textureMatCap, textureNormal){
var material = new THREE.ShaderMaterial({
    uniforms: {
        tNormal: {
            type: 't',
            value: textureNormal
        },
        tMatCap: {
            type: 't',
            value: textureMatCap
        },
        time: {
            type: 'f',
            value: 0
        },
        bump: {
            type: 'f',
            value: 0
        },
        noise: {
            type: 'f',
            value: .04
        },
        repeat: {
            type: 'v2',
            value: new THREE.Vector2(1, 1)
        },
        useNormal: {
            type: 'f',
            value: 0
        },
        useRim: {
            type: 'f',
            value: 0
        },
        rimPower: {
            type: 'f',
            value: 2
        },
        useScreen: {
            type: 'f',
            value: 0
        },
        normalScale: {
            type: 'f',
            value: .5
        },
        normalRepeat: {
            type: 'f',
            value: 1
        }
    },
    vertexShader: document.getElementById('vertexShader').textContent,
    fragmentShader: document.getElementById('fragmentShader').textContent,
    wrapping: THREE.ClampToEdgeWrapping,
    shading: THREE.SmoothShading,
    side: THREE.DoubleSide
});
material.uniforms.tMatCap.value.wrapS = material.uniforms.tMatCap.value.wrapT = THREE.ClampToEdgeWrapping;
material.uniforms.tNormal.value.wrapS = material.uniforms.tNormal.value.wrapT = THREE.RepeatWrapping;
material.name = name;
return material;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.