three.js多个渲染

时间:2013-01-07 17:43:26

标签: javascript three.js webgl

我目前有一个应该在运行时创建一个3d行星球体的功能,但我似乎无法让我的功能多次渲染,如果我在页面上多次运行它只是完全忽略除了最后一次调用函数之外的所有函数,我知道我编写了一个糟糕的工作编码,它意味着用作概念证明,但我不想去优化任何东西,如果我无法弄清楚为什么我无法在同一页面上获得3种不同的效果图。

function makePlanet(planetContainer, texture){
        $this = this;

    $this.camera; 
    $this.scene;
    $this.sceneAtmosphere;
    $this.renderer;
    $this.primitive; 
    $this.material;
    $this.stats;

    $this.loop = function() {
        var angle = (Math.PI/180*0.1);

        cosRY = Math.cos(angle);
        sinRY = Math.sin(angle);

        var tempz = $this.camera.position.z;
        var tempx = $this.camera.position.x; 

        $this.camera.position.x = (tempx*cosRY)+(tempz*sinRY);
        $this.camera.position.z = (tempx*-sinRY)+(tempz*cosRY);

        $this.renderer.clear();
        $this.renderer.render( $this.scene, $this.camera );
        $this.renderer.render( $this.sceneAtmosphere, $this.camera );

        setTimeout(function(){
            $this.loop();
        }, 1000 / 60);
    }

        $this.Shaders = {

        'earth' : {

            uniforms: {

                "texture": { type: "t", value: 0, texture: null }

            },

            vertex_shader: [

                "varying vec3 vNormal;",
                "varying vec2 vUv;",

                "void main() {",

                    "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

                    "vNormal = normalize( normalMatrix * normal );",
                    "vUv = uv;",

                "}"

            ].join("\n"),

            fragment_shader: [

                "uniform sampler2D texture;",

                "varying vec3 vNormal;",
                "varying vec2 vUv;",

                "void main() {",

                    "vec3 diffuse = texture2D( texture, vUv ).xyz;",
                    "float intensity = 1.10 - dot( vNormal, vec3( 0.0, 0.0, 1.0 ) );",
                    "vec3 atmosphere = vec3( 0.75, 0.75, 2.0 ) * pow( intensity, 3.0 );",

                    "gl_FragColor = vec4( diffuse + atmosphere, 1.0 );",

                "}"

            ].join("\n")

        },

        'atmosphere' : {

            uniforms: {},

            vertex_shader: [

                "varying vec3 vNormal;",

                "void main() {",

                    "vNormal = normalize( normalMatrix * normal );",
                    "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",

                "}"

            ].join("\n"),

            fragment_shader: [

                "varying vec3 vNormal;",

                "void main() {",
                    // First float seems to affect opacity, and the last float affects size/strenth of the gradient
                    "float intensity = pow( 0.4 - dot( vNormal, vec3( 0.0, 0.0, 1.0 ) ), 5.0 );",
                    // This seems to just be a simple colour value
                    "gl_FragColor = vec4( 0.5, 1.0, 1.0, 0.8 ) * intensity;",

                "}"

            ].join("\n")

        }

    };

    $this.camera = new THREE.Camera(30, $(planetContainer).width() / $(planetContainer).height(), 1, 100000);
    $this.camera.position.z = 1000;

    $this.scene = new THREE.Scene();
    $this.sceneAtmosphere = new THREE.Scene();

    $this.texture = ImageUtils.loadTexture('img/planets/textures/'+texture, {}, function() {
        $this.renderer.render($this.scene);
    });
    $this.texture.needsUpdate = true;

    $this.material = new THREE.MeshBasicMaterial( { map: $this.texture });
    $this.geom = new Sphere( 200, 50, 50);

    $this.primitive = new THREE.Mesh($this.geom, $this.material );

    $this.scene.addObject( $this.primitive );

// Atmosphere
    $this.shader = $this.Shaders[ 'atmosphere' ];
    $this.uniforms = Uniforms.clone( $this.shader.uniforms );

    $this.material = new THREE.MeshShaderMaterial( {

        uniforms: $this.uniforms,
        vertex_shader: $this.shader.vertex_shader,
        fragment_shader: $this.shader.fragment_shader

    } );

    $this.primitive = new THREE.Mesh( $this.geom, $this.material );
    $this.primitive.scale.x = $this.primitive.scale.y = $this.primitive.scale.z = 1.12;
    $this.primitive.flipSided = true;
    $this.sceneAtmosphere.addObject( $this.primitive );


    $this.renderer = new THREE.WebGLRenderer();
    $this.renderer.autoClear = false;
    $this.renderer.setClearColorHex( 0x000000, 1.0 );
    $this.renderer.setSize($(planetContainer).width(), $(planetContainer).height());

    $(planetContainer).append($this.renderer.domElement);

    setTimeout(function(){
        $this.loop();
    }, 1000 / 60);
}

有人可以解释为什么我不能在页面上多次使用此功能吗?

当我在任何页面上多次运行该函数时,我只看到1个3D对象,其他应该渲染对象的地方没有出现,我想有3个部分,每个部分都意味着渲染不同的行星,如果我使用不同的参数运行此函数3次,我最后一次运行该函数是唯一显示的函数,其他两个地方不显示任何内容,只是一个空白点。

此外,我已经检查过,如果我删除第三个,第二个显示但不是第一个,所以这不是参数不正确的问题,我相信这是一个问题,three.js不想要创建渲染器的多个实例。

使用示例

$(document).ready(function(){
    var goldilocks = new makePlanet('.goldilocksplanet .planetRender','planet_Jinx1200.png');
    var ocean = new makePlanet('.oceanplanet .planetRender','planet_serendip_1600.jpg');
    var sulfur = new makePlanet('.sulfurplanet .planetRender','planet_Telos1200.png');
});

下面是一个网页示例,其中包含3个不同的渲染图,它们不在同一个场景中,或者我会在一个场景中将它们全部制作,它们被认为是网站中的不同块,这只是一个示例并不是函数需要工作的唯一方式,但函数确实需要将每个行星视为自己的场景,我们不能将它们全部放在一个场景中。

http://i.stack.imgur.com/tooOA.jpg

2 个答案:

答案 0 :(得分:2)

所以我想出了我自己的问题,显然是因为我在函数中使用了全局变量而不是局部变量。我所要做的就是改变

$this = this;

var $this = this;

这解决了我所有的问题...有时候我觉得自己像个白痴。

答案 1 :(得分:1)

您可能需要考虑替换:

    setTimeout(function(){
            $this.loop();
        }, 1000 / 60);

部分:

    function animate() {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
    }

主要原因是requestAnimationFrame在浏览器窗口不可见时不会浪费渲染能力。