Question

I am working on a project in html 5 canvas. For this I use the three.js library to draw some simple cubes in the shape of a simple cupboard. I have already added ambient lighting, anti-aliasing and textures. If all goes well it renders the cupboard and you can use your mouse to move it around.

Current issues:

var textureMap = map: THREE.ImageUtils.loadTexture("wood1.jpg")
textureMap.wrapS = THREE.RepeatWrapping;
textureMap.wrapT = THREE.RepeatWrapping;
textureMap.repeat.x = 100;
textureMap.repeat.y = 100;
material = new THREE.MeshLambertMaterial(textureMap);
  1. The texture is currently stretched over each surface. I prefer tiling but can't seem to get it working. The code above was the best guess I came up with based on what I found on a site (sorry, can't share more links with my current reputation). It is commented out because it stops the script from running at all.

  2. I used to have some lag issues. After a quick search I found a site (sorry, can't share more links with my current reputation) that told me I had to put a timeout in the main loop and that I should use a second canvas for buffering. Adding the timeout worked like a charm but I'm still curious about the buffering canvas. I'm unsure how to go about this since I'm dealing with a renderer and a canvas. I don't even know if I should still bother with a buffer, since it seems to work just fine now, although that may change in the future when I try to render more meshes at a time.

  3. My code currently only runs in firefox for me. Chrome and Internet explorer both just show a blank screen. Any ideas what I need to change in order to fix this?

  4. When I run the code in firefox the cupboard is completely black at first. When I move it (at all) it immediately changes to the texture. Any ideas? I could come up with a dirty fix that moves the camera up and down 1 pixel in the setup but I'd rather not.

I tried uploading the code to jsfiddle (importing the texture from tinypic) but that doesn't go so well. Either I'm importing the texture wrong or jsfiddle just doesn't like it when I use external pictures. However, if you download the texture and put it in the same folder as the code you should be able to open it in firefox (only works in firefox (see issue 4)). So if you want to see what's going on: copy the code into a .html file and download the texture.

<!DOCTYPE HTML>
<html>
<head>
<title>Canvas demo</title>
<script type="text/javascript" src="http://www.html5canvastutorials.com/libraries/Three.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
</head> 
<body>  
<script type="text/javascript">

//three.js vars
var camera;
var scene;
var renderer;
var material;
var directionalLight;

//input vars
var lastX = 0;
var lastY = 450;
var clickX;
var clickY;
var mousedown;


function rerender(){
    //draw
    renderer.render(scene, camera); 
    //redraw after 25 ms (the 25 ms delay reduces lag)
    setTimeOut( requestAnimFrame(function(){rerender()}), 25);    
}

$(document).ready(function() {  
    //initialize renderer
    renderer = new THREE.WebGLRenderer({antialias : true});
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.domElement.id = "visiblecanvas";
    document.body.appendChild(renderer.domElement); 

    //camera
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.y = -450;
    camera.position.z = 400;
    camera.rotation.x = 45.2;

    //scene
    scene = new THREE.Scene();

    //material

    //non-working tiled texture
    /*
    var textureMap = map: THREE.ImageUtils.loadTexture("wood1.jpg")
    textureMap.wrapS = THREE.RepeatWrapping;
    textureMap.wrapT = THREE.RepeatWrapping;
    textureMap.repeat.x = 100;
    textureMap.repeat.y = 100;
    */

    //workingg stretched texture
    material = new THREE.MeshLambertMaterial({map: THREE.ImageUtils.loadTexture("wood1.jpg")});

    //the cupboard

    //cube
    var cube1 = new THREE.Mesh(new THREE.CubeGeometry(300,50,10), material);
    cube1.overdraw = true;
    scene.add(cube1);

    //cube
    var cube2 = new THREE.Mesh(new THREE.CubeGeometry(300,10,300), material);
    cube2.overdraw = true;
    cube2.position.z += 150;
    cube2.position.y += 20;
    scene.add(cube2);   

    //cube
    var cube3 = new THREE.Mesh(new THREE.CubeGeometry(10,50,300), material);
    cube3.overdraw = true;
    cube3.position.z += 150;
    cube3.position.x += 145;
    scene.add(cube3);   

    //cube
    var cube4 = new THREE.Mesh(new THREE.CubeGeometry(10,50,300), material);
    cube4.overdraw = true;
    cube4.position.z += 150;    
    cube4.position.x -= 145;
    scene.add(cube4);   

    //cube
    var cube5 = new THREE.Mesh(new THREE.CubeGeometry(300,50,10), material);
    cube5.overdraw = true;
    cube5.position.z += 300;
    scene.add(cube5);

    // add subtle ambient lighting
    var ambientLight = new THREE.AmbientLight(0x555555);
    scene.add(ambientLight);

    // add directional light source
    directionalLight = new THREE.DirectionalLight(0xffffff);
    directionalLight.position.set(1, 1, 1).normalize();
    scene.add(directionalLight);

    //mousedown event
    $('#visiblecanvas').mousedown(function(e){
      clickX = e.pageX - this.offsetLeft + lastX;    
      clickY = e.pageY - this.offsetLeft + lastY;
      mousedown = true;
    });

    //mousemove event, act if mousedown
    $('#visiblecanvas').mousemove(function(e){
        if(mousedown) {
            var xDiff = e.pageX - this.offsetLeft - clickX;
            var yDiff = e.pageY - this.offsetLeft - clickY;

            lastX = -xDiff;
            lastY = -yDiff;

            camera.position.x = lastX;
            camera.position.y = -lastY;

            rerender();
        }
        delay(5);
    });

    //mouseup event
    $('#visiblecanvas').mouseup(function(e){
      mousedown = false;
    });

    //mouseleave event (mouse leaves canvas, stop moving cupboard)
    $('#visiblecanvas').mouseleave(function(e){
      mousedown = false;
    });        
    rerender();
});

//request new frame
window.requestAnimFrame = (function (callback){
        return window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function(callback){
            window.setTimeout(callback, 1000 / 60);
        };
})();

</script>
</body>
</html>

Thanks for taking a look! hope you can answer any of my questions.

Was it helpful?

Solution

1) Use JavaScript console to debug the code.

2) The jsfiddle is missing jQuery.

3) This line:

var textureMap = map: THREE.ImageUtils.loadTexture("wood1.jpg")

must be:

var textureMap = THREE.ImageUtils.loadTexture("wood1.jpg");

See the extra map: and the missing semicolon.

4) The repeat texture parameters are too big. Default value is 1, to repeat the texture one time. Try to change that values to 2, 3, ... and so.

5) delay function is undefined, remove it

6) setTimeOut function is undefined (setTimeout?, JavaScript is case sensitive)

7) Rewrite the rendererer function to this:

function rerender(){
    requestAnimFrame(rerender);

    renderer.render(scene, camera); 
}

Take a look at this: http://paulirish.com/2011/requestanimationframe-for-smart-animating/

8) Remove the call to the rerender function inside the mousemove event

9) IE and WebGL?

OTHER TIPS

Try:

function rerender(){
    requestAnimFrame(rerender);

    renderer.render(scene, camera); 
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top