为地球日夜创建着色器也可以创建可点击的精灵

时间:2014-10-23 02:15:03

标签: click three.js shader

我的问题分为多个部分,请回答您可以了解的部分,每个部分都会提出自己独特的挑战。

首先:我需要创建一个在白天的地球和夜晚的地球之间混合的着色器(各个城市的夜间灯光)。我已经尝试过一种技术,我在之前回答过的关于这个话题的问题上看到了这个技术,但这对我来说并没有用。相关代码如下:

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

    uniform vec3 sunDirection;

    varying vec2 vUv;
    varying vec3 vNormal;

    void main( void ) {
        vec3 dayColor = texture2D( dayTexture, vUv ).rgb;
        vec3 nightColor = texture2D( nightTexture, vUv ).rgb;

        // compute cosine sun to normal so -1 is away from sun and +1 is toward sun.
        float cosineAngleSunToNormal = dot(normalize(vNormal), sunDirection);

        // sharpen the edge beween the transition
        cosineAngleSunToNormal = clamp( cosineAngleSunToNormal * 10.0, -1.0, 1.0);

        // convert to 0 to 1 for mixing
        float mixAmount = cosineAngleSunToNormal * 0.5 + 0.5;

        // Select day or night texture based on mix.
        vec3 color = mix( nightColor, dayColor, mixAmount );

        gl_FragColor = vec4( color, 1.0 );
        //gl_FragColor = vec4( mixAmount, mixAmount, mixAmount, 1.0 );
    }
</script>
<script id="vertexShader" type="x-shader/x-vertex">


        varying vec2 vUv;
        varying vec3 vNormal;

        void main()
        {
            vUv = uv;
            vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
            vNormal = normalMatrix * normal;
            gl_Position = projectionMatrix * mvPosition;
        }


</script>

<script>


uniforms = {
    sunDirection: { type: "v3", value: new THREE.Vector3(0,1,0) },
    dayTexture: { type: "t", value: 0, texture: THREE.ImageUtils.loadTexture( "images/Color_Map.jpg" ) },
    nightTexture: { type: "t", value: 1, texture: THREE.ImageUtils.loadTexture( "images/Night_Lights.jpg" ) }
};

uniforms.dayTexture.texture.wrapS = uniforms.dayTexture.texture.wrapT = THREE.Repeat;
uniforms.nightTexture.texture.wrapS = uniforms.nightTexture.texture.wrapT = THREE.Repeat;





material = new THREE.ShaderMaterial( {

    uniforms: uniforms,
    vertexShader: document.getElementById( 'vertexShader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent
    });

var controls = new THREE.TrackballControls(camera);

webglEl.appendChild(renderer.domElement);

render();

function render() {
    controls.update();
    lexington_line.rotation.y += 0.0005;  //0.0005
    florida_line.rotation.y += 0.0005; // 0.0005
    sphere.rotation.y += 0.0005; //0.0005
    clouds.rotation.y += 0.0007; //0.0007       
    var t = Date.now() * 0.001;
    uniforms.sunDirection.value.x = Math.sin(t);
    uniforms.sunDirection.value.y = Math.cos(t);
    requestAnimationFrame(render);
    renderer.render(scene, camera);
}

function createSphere(radius, segments, material) {
    return new THREE.Mesh(
        new THREE.SphereGeometry(radius, segments, segments),
        new THREE.MeshPhongMaterial({
            map:         THREE.ImageUtils.loadTexture('images/Color_Map.jpg'),
            bumpMap:     THREE.ImageUtils.loadTexture('images/elev_bump_4k.jpg'),
            bumpScale:   0.005,
            specularMap: THREE.ImageUtils.loadTexture('images/water_4k.png'),
            specular:    new THREE.Color('grey')                        
        })
    );
}

</script>

我的第二个问题我需要创建一个你可以点击它的精神它它会变成相机所以它看到图片(未实现)我有代码所以它点击但是当我看到控制台它似乎没有好好工作。最接近的点击仅在表面准确面向您时才正确,但如果您尝试以某个角度或不在其上方的某个位置单击它,则不会给出正确的单击(相交[0])。相关代码如下:

//Normal Lines. 


//Not sure if this is needed, Further testing required.
//document.body.appendChild(renderer.domElement);


//Lexington KY Location: Normal Line.
var lex_normal = new THREE.Geometry();

var vertex = new THREE.Vector3( 0.1, 1.0, 1.3 );
vertex.normalize();
vertex.multiplyScalar( 0.5 );
lex_normal.vertices.push( vertex );
var vertex2 = vertex.clone();
vertex2.multiplyScalar( 2 );
lex_normal.vertices.push( vertex2 );
var lexington_line = new THREE.Line( lex_normal, new THREE.LineBasicMaterial( { color: 0xffffff, opacity:12 } ) );
lexington_line.rotation.y = rotation;
scene.add( lexington_line );
lexington_line.onClick = function(){
    console.log('Target Normal: Lexington, KY USA');

    }

//Miami FL:: TEST!  
var mia_normal = new THREE.Geometry();

var vertex = new THREE.Vector3( 0.26, 1.0, 1.72 );
vertex.normalize();
vertex.multiplyScalar( 0.3 );
mia_normal.vertices.push( vertex );
var vertex2 = vertex.clone();
vertex2.multiplyScalar( 2 );
mia_normal.vertices.push( vertex2 );
var florida_line = new THREE.Line( mia_normal, new THREE.LineBasicMaterial( { color: 0xffffff, opacity:12 } ) );
florida_line.rotation.y = rotation;
scene.add( florida_line );
florida_line.rotation.y = rotation;
florida_line.onClick = function(){
    console.log('Target Normal: Miami, FL USA');
}

// Projector to generate the 3D coordinates from the click
var projector = new THREE.Projector();

// push all the clickable objects into this array
var clickableObjects = [];    
clickableObjects.push(lexington_line,florida_line);

// Bind the mousedown handler
document.addEventListener( 'mousedown', onDocumentMouseDown, false );

function onDocumentMouseDown( event ) {
  event.preventDefault();

  // transforms the 2D click coordinates into a THREE.Vector3 for 3D coordinates
  var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - (     event.clientY / window.innerHeight ) * 2+1, 0.2 );
        projector.unprojectVector( vector, camera );

  // casts a ray from the camera position directly to the calculated vector
  var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position     ).normalize() );


  // iterates through the clickable objects and checks if they intersect with the ray
  var intersects = raycaster.intersectObjects( clickableObjects );

  if ( intersects.length > 0 ) {
    // The intersects array contains all the elements,
    // that intersect with the casted ray. intersects[0] is the nearest object.
    intersects[0].object.onClick();
  }


}

}());

如果问题不明确请说出来,如果必须,我会尝试改写。

谢谢!

编辑: 我在第一个问题中得到的结果是什么。我将材料传递给了函数,但无论我在哪里放置材料,它似乎都没有达到预期的效果。例如,如果我像这样传递它:

function createSphere(radius, segments, material) {
    return new THREE.Mesh(
        new THREE.SphereGeometry(radius, segments, segments),
        new THREE.MeshPhongMaterial({
            map:         THREE.ImageUtils.loadTexture('images/Color_Map.jpg'),
            bumpMap:     THREE.ImageUtils.loadTexture('images/elev_bump_4k.jpg'),
            bumpScale:   0.005,
            specularMap: THREE.ImageUtils.loadTexture('images/water_4k.png'),
            specular:    new THREE.Color('grey')                        
        }), material
    );
}

它完全改变了行星的颜色 或者像这样:

function createSphere(radius, segments, material) {
    return new THREE.Mesh(
        new THREE.SphereGeometry(radius, segments, segments), material,
        new THREE.MeshPhongMaterial({
            map:         THREE.ImageUtils.loadTexture('images/Color_Map.jpg'),
            bumpMap:     THREE.ImageUtils.loadTexture('images/elev_bump_4k.jpg'),
            bumpScale:   0.005,
            specularMap: THREE.ImageUtils.loadTexture('images/water_4k.png'),
            specular:    new THREE.Color('grey')                        
        })
    );
}

它再次改变颜色但不同于上面。我不能让它只是在夜间显示夜间灯光(不在某个区域的灯光下)。

我在重铸中修正了0.2到0.5,但它似乎没有解决太多问题。这个问题仍然存在,除非你正确在线上,否则它不会正确点击。

1 个答案:

答案 0 :(得分:0)

1)如果您有不同的问题,请打开不同的主题。

2)你在Querstion 1中得到的结果是什么?只是说它不起作用并不多。

3)在光线投射中有0.2,它应该是0.5。

var vector = new THREE.Vector3((event.clientX / window.innerWidth)* 2 - 1, - (event.clientY / window.innerHeight)* 2 + 1,0.2);

我认为这应该是:

var vector = new THREE.Vector3((event.clientX / window.innerWidth)* 2 - 1, - (event.clientY / window.innerHeight)* 2 + 1,0.5);