0

I currently have a function that is supposed to create a 3d planet sphere when ran, but I seem to be unable to get my function to render more than one time, if I run it more than once on a page it just completely ignores all but the last call to the function, I know I did a horrible job coding this, it is meant to be used as a proof of concept, but I don't want to go and optimize anything if I cannot figure out why I cannot get 3 different renderings on the same page.

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);
}

Can anyone explain why I would not be able to use this function more than once on a page?

When I run the function more than once on any page, I only see 1 3D object, the other places that were supposed to render an object do not appear, think I have 3 sections, each meant to render a different planet, if I run this function 3 times with different arguments, the last time I run the function is the only one that displays, the other two places do not display anything, just an empty spot.

Also, I have checked and if I remove the 3rd one, the second one displays but not the first, so it is not an issue with the parameters not being correct, I believe it is an issue with three.js not wanting to create more than one instance of a renderer.

Example of Use

$(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');
});

Below is a sample of a webpage that will contain the 3 different renderings, they are not in the same scene, or I would have made them all in one scene, they are considered different blocks in the website, this is just an example and is by no means the only way that the function will need to work, but the function does need to treat each planet as its own scene, we cannot put them all in one scene together.

https://i.sstatic.net/tooOA.jpg

4
  • "if I run it more than once on a page it just completely ignores all but the last call to the function" Huh? What does that mean? What function? How do you run what "more than once"? What do you expect to see? What do you see instead?
    – Alex Wayne
    Commented Jan 7, 2013 at 17:57
  • @AlexWayne When I run the function more than once on any page, I only see 1 3D object, the other places that were supposed to render an object do not appear, think I have 3 sections, each meant to render a different planet, if I run this function 3 times with different arguments, the last time I run the function is the only one that displays, the other two places do not display anything, just an empty spot.
    – Cory Evans
    Commented Jan 7, 2013 at 18:34
  • @AlexWayne Also, I have checked and if I remove the 3rd one, the second one displays but not the first, so it is not an issue with the parameters not being correct, I believe it is an issue with three.js not wanting to create more than one instance of a renderer.
    – Cory Evans
    Commented Jan 7, 2013 at 18:35
  • 1
    @AlexWayne I have added an edit to the original question to show you what I mean by running the function more than once.
    – Cory Evans
    Commented Jan 7, 2013 at 18:40

2 Answers 2

2

So I figured out my own problem, apparently it was because I was using global variables and not local variables within the function. All I had to do was change

$this = this;

to

var $this = this;

and that fixed all of my problems... sometimes I feel like such an idiot.

1

You might want to consider replacing the:

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

part for:

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

The main reason is that requestAnimationFrame doesn't waste rendering power when the browser window isn't visible.

3
  • Do you know if it will also not waste rendering power if the canvas is not viewable? (IE: It is on a different tab, I change the tab to a different tab, so the canvas is no longer viewable?) The reason I was using setTimeout was because I intend to add checks if the tab is currently viewable).
    – Cory Evans
    Commented Jan 9, 2013 at 1:31
  • @CoryEvans I don't know if all browsers work the same way but in Google Chrome it does stop updating when you switch tabs. On my laptop, the temperature controlled fan spins up to hi speed when I render heavy 3D scenes. When I switch tabs, the fan spins down. =o)
    – Aycox
    Commented Jan 9, 2013 at 10:03
  • Not "Window Tabs" I mean if I set the parent container to display:none, would requestAnimationFrame stop running?
    – Cory Evans
    Commented Jan 9, 2013 at 15:35

Not the answer you're looking for? Browse other questions tagged or ask your own question.