three.js3dshaderwebglobjloader

How to add custom shadermaterial to an obj 3D object in Three.js


The following is a working example with ObjLoader for 3D object. Is there anyone that can teach me how to add shader material to this 3D object?

Most tutorials are like using standard three.geometry and then add the geometry and shader to a scene. But, if I want to add a custom shader material to the 3D object, not to a standard Three.js geometry, how should I do?

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>OBJ loader</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                font-family: Monospace;
                background-color: #fff;
                color: #fff;
                margin: 0px;
                overflow: hidden;
            }
            
        </style>
    </head>

    <body>


        <script src="http://threejs.org/build/three.min.js"></script>
        <script src="http://threejs.org/examples/js/loaders/OBJLoader.js"></script>

        <script src="http://threejs.org/examples/js/libs/stats.min.js"></script>

        <script>
            var clock = new THREE.Clock();
            var delta = clock.getDelta(); // seconds.
            var rotateAngle = Math.PI / 2 * delta;   // pi/2 radians (90 degrees) per second
            var container, stats;

            var camera, scene, renderer, texture;

            var mouseX = 0, mouseY = 0;

            var windowHalfX = window.innerWidth / 2;
            var windowHalfY = window.innerHeight / 2;

            init();
            animate();
    //var texture = new THREE.Texture();
                new THREE.OBJLoader( ).load( 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/40480/head.obj', function ( object ) {

                    object.traverse( function ( child ) {

                        if ( child instanceof THREE.Mesh ) {

                            child.material.map = texture;

                        }

                    } );

    
                  
                    scene.add( object );

                } );

            function init() {

                container = document.createElement( 'div' );
                document.body.appendChild( container );

                camera = new THREE.PerspectiveCamera( 15, window.innerWidth / window.innerHeight, 1, 2000 );
                camera.position.z = 100;

                // scene

                scene = new THREE.Scene();

                var ambient = new THREE.AmbientLight( 0x111130 );
                scene.add( ambient );

                var directionalLight = new THREE.DirectionalLight( 0xffeeff );
                directionalLight.position.set( 1, 1,0.5 );
                scene.add( directionalLight );

    
        

                renderer = new THREE.WebGLRenderer();
                renderer.setSize( window.innerWidth, window.innerHeight );
                container.appendChild( renderer.domElement );

                document.addEventListener( 'mousemove', onDocumentMouseMove, false );

                window.addEventListener( 'resize', onWindowResize, false );

            }

            function onWindowResize() {
                windowHalfX = window.innerWidth / 2;
                windowHalfY = window.innerHeight / 2;

                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();

                renderer.setSize( window.innerWidth, window.innerHeight );
            }

            function onDocumentMouseMove( event ) {
                mouseX = ( event.clientX - windowHalfX ) / 2;
                mouseY = ( event.clientY - windowHalfY ) / 2;
            }

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

            function render() {
             

                camera.position.x += ( mouseX - camera.position.x ) * .05;
                camera.position.y += ( - mouseY - camera.position.y ) * .05;

                camera.lookAt( scene.position );

                renderer.render( scene, camera );
            }
        </script>
    </body>
</html>

Solution

  • You can create your custom ShaderMaterial in whatever method you learned, and then simply substitute the .material property of each of the meshes in your obj.

    const vertString = "GLSL shader code...";
    const fragString = "GLSL shader code...";
    
    // Declare the custom material we'll use
    const customMaterial = new THREE.ShaderMaterial({
        uniforms: {
            time: { value: 1.0 },
            map: { value: texture },
            resolution: { value: new THREE.Vector2() }
        },
        vertexShader: vertString,
        fragmentShader: fragString 
    });
    
    // We load the OBJ
    new THREE.OBJLoader( ).load( 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/40480/head.obj', function ( object ) {
    
        // Now we find each Mesh...
        object.traverse( function ( child ) {
            if ( child instanceof THREE.Mesh ) {
    
                // ...and we replace the material with our custom one
                child.material = customMaterial;
    
            }
        });
    
        scene.add( object );
    });