1
votes

I'm attempting to display a list of renderer/scene/camera "groups" on the same html page. I ran into problems when trying to implement a render loop on all of them, using requestAnimationFrame. I am, however, unable to successfully render even a single frame by looping over the list.

calling renderer.render on each of the "groups" in the same function that I instantiate them in works fine. I refactored the code to allow calling render on each of the renderers outside of said function, and my blue spheres disappear;

I have some elements...

 <div class="1"></div>
 <div class="2"></div>
 <div class="3"></div>
 <div class="4"></div>

that I add some threeJs things to

$(document).ready(function(){
    addResizeandCenterListener(window, $("#container"), 4/3);
    addResizeListener($("#container"), $(".playerhalf"), 2/1);
    for (let item of [".1", ".2", ".3", ".4", ".5", ".6", ".7", ".8"]) {
        var threeDetails = addThreeRendererToElem($(item), item);
        var scene = threeDetails["scene"];
        addClickListenerToElem($(item), scene);
    }
});
threeList = [];

//this adds a renderer/scene/camera to the element "elem"
function addThreeRendererToElem(elem, name){
    var width = elem.innerWidth();
    var height = elem.innerHeight();
    var scene = newScene();
    scene.name = name;
    addDefaultLight(scene);
    addBlueBall(scene);
    var camera = addDefaultCamera(scene, width, height);
    var renderer = newRenderer(width, height);
    elem[0].appendChild(renderer.domElement);
    //this works fine regardless of how many renderer/scene/camera groups I have placed in the DOM
    //renderer.render(scene, camera);
    var threeDict = {"renderer":renderer, "scene":scene, "camera":camera}
    threeList.push(threeDict)
    //this does not work, even if I only place a single renderer/scene camera group in the DOM
    renderList();
}

function renderList() {
    var tlist = threeList;
    for (var i = 0; i< tlist;i++) {
        var threeDict = tlist[i];
        threeDict["renderer"].render(threeDict["scene"], 
                                     threeDict["camera"]);
    }
}

function newScene(){
    scene = new THREE.Scene();
    return scene;
}

function newCamera(w, h){
    camera = new THREE.PerspectiveCamera(45, w / h, 0.1, 100);
    return camera;
}

function newRenderer(w, h){
    renderer = new THREE.WebGLRenderer({alpha:true, antialias:true});
    renderer.setSize(w, h);
    return renderer;
}

function addObjectToScene(obj, scene){    
    scene.add(obj);
}

function ballObj(color){
    var ballGeometry = new THREE.SphereGeometry(3, 16, 16);
    var ballMaterial = new THREE.MeshPhongMaterial({color: 0x33aaff});
    var ball = new THREE.Mesh(ballGeometry, ballMaterial);
    return ball;
}

function spotLightObj(){
    var spot = new THREE.SpotLight(0xffffff);
    return spot;
}

function addDefaultCamera(scene, width, height){
    var camera = newCamera(width, height);    
    camera.position.set(1,1,20);
    camera.lookAt(scene.position);
    return camera;
}

function addDefaultLight(scene){    
    var spot = spotLightObj();
    spot.position.set(1, 10, 4);
    addObjectToScene(spot, scene);
}

function addBlueBall(scene){
    var hexcolor = "0x33aaff";
    bball = ballObj(hexcolor);
    addObjectToScene(bball, scene);
}

I expect to see some blue spheres, like when I am calling render from inside addThreeRendererToElem, but I don't. Instead, the canvases are all blank. The canvases are in the correct places on the web page, inspecting threeList in the console shows that all the objects are indeed there. There are no error messages.

1
FYI I suggest you probably want to use one renderer. It will load faster, use less memory, and be more performant. See this article - gman
@gman I have read the article in my quest to do what I'm trying to do. I will most likely move to that pattern later, but it was faster for me to have each of the scenes in its own canvas, since getting the canvas to resize with it's parent element is trivial. positioning each of the scenes on the canvas isn't something I am terribly familiar with at present, so I opted do it this way initially. - moshy

1 Answers

0
votes

Incorrect ending condition on your for-loop inside the renderList function.

You are missing .length. Should be:

function renderList() {
    var tlist = threeList;
    for ( var i = 0; i < tlist.length; i++ ) {
        var threeDict = tlist[i];
        threeDict["renderer"].render( threeDict["scene"], threeDict["camera"] );
    }
}