1

I've been looking like crazy for a solution for this. I've been using this example for instance https://stemkoski.github.io/Three.js/Shader-Fireball.html to try and set up a Solar System.

I can't seem to understand how to add my current scene lights to the shader materials (customMaterial2 in this case) and get a proper shadow? This is roughly what my code looks like. I attached all of it!

Would be extremely thankful for some inputs on the matter.

    <html>

<head>
    <title></title>
    <link rel="stylesheet" href="css/style.css" type="text/css" />
</head>

<body>

    <script src="http://code.jquery.com/jquery-1.11.2.min.js"></script>
    <script src="js/three.min.js"></script>
    <script src="js/OrbitControls.js"></script>
    <script src="js/stats.min.js"></script>

<!-- VERTEX SHADER -->

<script id="vertexShader" type="x-shader/x-vertex">

uniform sampler2D noiseTexture;
uniform float noiseScale;

uniform sampler2D bumpTexture;
uniform float bumpSpeed;
uniform float bumpScale;

uniform float time;

varying vec2 vUv;

void main() 
{ 
    vUv = uv;

    vec2 uvTimeShift = vUv + vec2( 1.1, 1.9 ) * time * bumpSpeed;
    vec4 noiseGeneratorTimeShift = texture2D( noiseTexture, uvTimeShift );
    vec2 uvNoiseTimeShift = vUv + noiseScale * vec2( noiseGeneratorTimeShift.r, noiseGeneratorTimeShift.g );
    // below, using uvTimeShift seems to result in more of a "rippling" effect
    //   while uvNoiseTimeShift seems to result in more of a "shivering" effect
    vec4 bumpData = texture2D( bumpTexture, uvTimeShift );

    // move the position along the normal
    //  but displace the vertices at the poles by the same amount
    float displacement = ( vUv.y > 0.999 || vUv.y < 0.001 ) ? 
        bumpScale * (0.3 + 0.02 * sin(time)) :  
        bumpScale * bumpData.r;
    vec3 newPosition = position + normal * displacement;

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


<!-- FRAGMENT SHADER A.K.A. PIKEL SHADER -->

<script id="fragmentShader" type="x-shader/x-vertex">

uniform sampler2D baseTexture;
uniform float baseSpeed;
uniform float repeatS;
uniform float repeatT;

uniform sampler2D noiseTexture;
uniform float noiseScale;

uniform sampler2D blendTexture;
uniform float blendSpeed;
uniform float blendOffset;

uniform float time;
uniform float alpha;

varying vec2 vUv;

void main() 
{
    vec2 uvTimeShift = vUv + vec2( -0.7, 1.5 ) * time * baseSpeed;  
    vec4 noiseGeneratorTimeShift = texture2D( noiseTexture, uvTimeShift );
    vec2 uvNoiseTimeShift = vUv + noiseScale * vec2( noiseGeneratorTimeShift.r, noiseGeneratorTimeShift.b );
    vec4 baseColor = texture2D( baseTexture, uvNoiseTimeShift * vec2(repeatS, repeatT) );

    vec2 uvTimeShift2 = vUv + vec2( 1.3, -1.7 ) * time * blendSpeed;    
    vec4 noiseGeneratorTimeShift2 = texture2D( noiseTexture, uvTimeShift2 );
    vec2 uvNoiseTimeShift2 = vUv + noiseScale * vec2( noiseGeneratorTimeShift2.g, noiseGeneratorTimeShift2.b );
    vec4 blendColor = texture2D( blendTexture, uvNoiseTimeShift2 * vec2(repeatS, repeatT) ) - blendOffset * vec4(1.0, 1.0, 1.0, 1.0);

    vec4 theColor = baseColor + blendColor;
    theColor.a = alpha;

    gl_FragColor = theColor;
}  
</script>


<script>

window.requestAnimationFrame = (function(){
  return  window.requestAnimationFrame       ||
          window.webkitRequestAnimationFrame ||
          window.mozRequestAnimationFrame    ||
          function( callback ){
            window.setTimeout(callback, 1000 / 60);
          };
})();

var container, stats;

var camera, scene, renderer;

var cameraControls;

var cube, materials;

var clock = new THREE.Clock();

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

init(); // INITIALIZING
animate(); // START ANIMATIONS

function init() {


    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 5000 );
    camera.position.x = 0;
    camera.position.y = 10;
    camera.position.z = 50;


    scene.add( new THREE.AmbientLight( 0x111111 ) );

    // lens flares

    var textureFlare0 = THREE.ImageUtils.loadTexture( 'img/lensflare0.png' );
    var textureFlare2 = THREE.ImageUtils.loadTexture( 'img/lensflare2.png' );
    var textureFlare3 = THREE.ImageUtils.loadTexture( 'img/lensflare3.png' );

/*              addLight( 0.55, 0.9, 0.5, 5000, 0, -1000 );*/
    addLight( 0.08, 0.8, 0.5, 0, 0, -1500 );
/*              addLight( 0.995, 0.5, 0.9, 5000, 5000, -1000 );*/

    function addLight( h, s, l, x, y, z ) {

        var light = new THREE.PointLight( 0xffffff, 0, 4500 );
        light.color.setHSL( h, s, l );
        light.position.set( -700, y, -1200 );
        scene.add( light );

        var flareColor = new THREE.Color( 0xffffff );
        flareColor.setHSL( h, s, l + 0.5 );

        var lensFlare = new THREE.LensFlare( textureFlare0, 350, 0.0, THREE.AdditiveBlending, flareColor );

        lensFlare.add( textureFlare2, 256, 0.0, THREE.AdditiveBlending );
        lensFlare.add( textureFlare2, 256, 0.0, THREE.AdditiveBlending );
        lensFlare.add( textureFlare2, 256, 0.0, THREE.AdditiveBlending );

        lensFlare.add( textureFlare3, 60, 0.6, THREE.AdditiveBlending );
        lensFlare.add( textureFlare3, 70, 0.7, THREE.AdditiveBlending );
        lensFlare.add( textureFlare3, 120, 0.9, THREE.AdditiveBlending );
        lensFlare.add( textureFlare3, 70, 1.0, THREE.AdditiveBlending );

        lensFlare.customUpdateCallback = lensFlareUpdateCallback;
        lensFlare.position.copy( light.position );

        scene.add( lensFlare );

    }

    spotLight = new THREE.SpotLight( 0xdfebff, 1 );

    scene.add(spotLight);


    sunLight = new THREE.PointLight( 0xffdea4, 1, 0 );
    sunLight.position.set( 500, 200, -300 );

    scene.add(sunLight);


/*********************************************** SKYBOX/SPACE */

    var spaceGeometry = new THREE.SphereGeometry(2000, 32, 100);

    var spaceTexture = THREE.ImageUtils.loadTexture( 'img/space.jpg' );
    spaceTexture.wrapS = spaceTexture.wrapT = THREE.RepeatWrapping;
    spaceTexture.repeat.set( 2, 1 );
    spaceTexture.anisotropy = 5;

    var spaceMesh = new THREE.MeshBasicMaterial({
            map: spaceTexture,
            side: THREE.BackSide
        });

    space = new THREE.Mesh( spaceGeometry, spaceMesh);

    space.position.set( 0, 0, 0);
    space.rotation.set( 0, 0, 0 );
    space.scale.set( 1, 1, 1 );

    scene.add( space );


/***************************************************************** SUN */

    // base image texture for mesh
    var lavaTexture = new THREE.ImageUtils.loadTexture( 'img/lava.jpg');
    lavaTexture.wrapS = lavaTexture.wrapT = THREE.RepeatWrapping; 
    // multiplier for distortion speed      
    var baseSpeed = 0.01;
    // number of times to repeat texture in each direction
    var repeatS = repeatT = 10.0;

    // texture used to generate "randomness", distort all other textures
    var noiseTexture = new THREE.ImageUtils.loadTexture( 'img/cloud.png' );
    noiseTexture.wrapS = noiseTexture.wrapT = THREE.RepeatWrapping; 
    // magnitude of noise effect
    var noiseScale = 0.5;

    // texture to additively blend with base image texture
    var blendTexture = new THREE.ImageUtils.loadTexture( 'img/lava.jpg' );
    blendTexture.wrapS = blendTexture.wrapT = THREE.RepeatWrapping; 
    // multiplier for distortion speed 
    var blendSpeed = 0.005;
    // adjust lightness/darkness of blended texture
    var blendOffset = 0.15;

    // texture to determine normal displacement
    var bumpTexture = noiseTexture;
    bumpTexture.wrapS = bumpTexture.wrapT = THREE.RepeatWrapping; 
    // multiplier for distortion speed      
    var bumpSpeed   = 0.05;
    // magnitude of normal displacement
    var bumpScale   = 150.0;

    // use "this." to create global object
    this.customUniforms = {
        baseTexture:    { type: "t", value: lavaTexture },
        baseSpeed:      { type: "f", value: baseSpeed },
        repeatS:        { type: "f", value: repeatS },
        repeatT:        { type: "f", value: repeatT },
        noiseTexture:   { type: "t", value: noiseTexture },
        noiseScale:     { type: "f", value: noiseScale },
        blendTexture:   { type: "t", value: blendTexture },
        blendSpeed:     { type: "f", value: blendSpeed },
        blendOffset:    { type: "f", value: blendOffset },
        bumpTexture:    { type: "t", value: bumpTexture },
        bumpSpeed:      { type: "f", value: bumpSpeed },
        bumpScale:      { type: "f", value: bumpScale },
        alpha:          { type: "f", value: 1.0 },
        time:           { type: "f", value: 1.0 },
    };

    // create custom material from the shader code above
    //   that is within specially labeled script tags
    var customMaterial = new THREE.ShaderMaterial( 
    {
        uniforms: customUniforms,
        vertexShader:   document.getElementById( 'vertexShader'   ).textContent,
        fragmentShader: document.getElementById( 'fragmentShader' ).textContent
    });

    var sunGeometry = new THREE.SphereGeometry( 400, 64, 64 );
    sun = new THREE.Mesh( sunGeometry, customMaterial );
    sun.position.set( 400, 200, -600 );
    scene.add( sun );

/*********************************************************** EARTH */

    var earthGeometry = new THREE.SphereGeometry(100, 32, 100);
    var earthMesh = new THREE.MeshPhongMaterial({
            map: THREE.ImageUtils.loadTexture('img/earth.jpg')
        });

    earth = new THREE.Mesh( earthGeometry, earthMesh);

    earth.position.set( -300, 0, -300 );
    earth.rotation.set( 0, 0, 0 );
    earth.scale.set( 1, 1, 1 );

    scene.add( earth );

/********************************************************** NEPTUNE */

    var waterTexture = new THREE.ImageUtils.loadTexture( 'img/neptune2.jpg' );
    var waterTexture2 = new THREE.ImageUtils.loadTexture( 'img/cloud.png' );

    waterTexture.wrapS = waterTexture.wrapT = THREE.RepeatWrapping;
    waterTexture2.wrapS = waterTexture2.wrapT = THREE.RepeatWrapping; 

    // use "this." to create global object
    this.customUniforms2 = {
        baseTexture:    { type: "t", value: waterTexture },
        baseSpeed:      { type: "f", value: 0.05 },
        repeatS:        { type: "f", value: 3 },
        repeatT:        { type: "f", value: 3 },
        noiseTexture:   { type: "t", value: waterTexture2 },
        noiseScale:     { type: "f", value: 1.05 },
        bumpTexture:    { type: "t", value: waterTexture },
        bumpSpeed:      { type: "f", value: bumpSpeed },
        bumpScale:      { type: "f", value: 0 },
        alpha:          { type: "f", value: 1.0 },
        time:           { type: "f", value: 1.0 }
    };

    // create custom material from the shader code above
    //   that is within specially labeled script tags
    var customMaterial2 = new THREE.ShaderMaterial( 
    {
        uniforms: customUniforms2,
        vertexShader:   document.getElementById( 'vertexShader'   ).textContent,
        fragmentShader: document.getElementById( 'fragmentShader' ).textContent
    });

    // other material properties
    customMaterial2.side = THREE.DoubleSide;

    // apply the material to a surface
    var neptuneGeometry = new THREE.SphereGeometry(200, 32, 100);
    neptune = new THREE.Mesh( neptuneGeometry, customMaterial2 );
    neptune.position.set( -1500, 0, -500 );
    neptune.rotation.set( 0, 0, 0 );
    neptune.scale.set( 1, 1, 1 );
    scene.add( neptune );


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

    renderer.shadowMapType = THREE.PCFSoftShadowMap;
    renderer.shadowMapEnabled = true;

    stats = new Stats();
    container.appendChild( stats.domElement );

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

}

function lensFlareUpdateCallback( object ) {

    var f, fl = object.lensFlares.length;
    var flare;
    var vecX = -object.positionScreen.x ;
    var vecY = -object.positionScreen.y ;


    for( f = 0; f < fl; f++ ) {

           flare = object.lensFlares[ f ];

           flare.x = object.positionScreen.x + vecX * flare.distance;
           flare.y = object.positionScreen.y + vecY * flare.distance;

           flare.rotation = 1;

    }

    object.lensFlares[ 2 ].y += 0.025;
    object.lensFlares[ 3 ].rotation = object.positionScreen.x * 0.5 + THREE.Math.degToRad( 45 );

}


function onWindowResize() {

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

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


function animate() {

    requestAnimationFrame( animate );

    render();
    update();

}


function update() {

    var delta = clock.getDelta(); // seconds.
    customUniforms.time.value += delta;
    customUniforms2.time.value += delta;


    stats.update();
}



function render() {

    sun.rotation.y += 0.1 / 100;
    earth.rotation.y += 0.1 / 50;
    neptune.rotation.y += 0.1 / 50;

    renderer.render( scene, camera );
}


</script>

    </body>

</html>
1

1 Answer 1

0

If you want to create a custom ShaderMaterial and access the lights in your scene graph, you must set the material lights property to true.

See, for example, this three.js example.

You also must include the code to handle the lights in your fragment shader.

There are several three.js fragment shader examples where this is done. See, for example, shaderSkin.js.

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.