将场景灯添加到自定义顶点/片段着色器和着色器材质?

时间:2015-04-22 01:14:10

标签: three.js shader light

我一直在寻找解决方案。我一直在使用这个例子https://stemkoski.github.io/Three.js/Shader-Fireball.html来尝试建立一个太阳系。

我似乎无法理解如何将当前场景灯添加到着色器材质(在本例中为customMaterial2)并获得正确的阴影?这大致是我的代码的样子。我附上了所有这些!

非常感谢有关此事的一些意见。

    <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 个答案:

答案 0 :(得分:0)

如果您想创建自定义ShaderMaterial并访问场景图中的灯光,则必须将材料lights属性设置为true

例如,请参阅this three.js example

您还必须包含代码以处理片段着色器中的灯光。

有几个three.js片段着色器示例完成此操作。例如,请参阅shaderSkin.js