Related
I have a simple 3d cube (BoxGeometry of 100, 100, 100) and I am trying to rotate it. If we call all 100x100x100 a tile - when I rotate it I can see it's overlapping the below tile.
(by changing color, now I totally understand the behaviour).
tl.to(this.cube4.rotation, 0.5, {z: -45* Math.PI/180});
[
What if I want to rotate it based on an anchor point of right bottom? So instead of overflowing inside the below tile, it will overflow that portion to above tile.
So it will look like the green example and not the red example:
The red example here is achieved by
tl.to(this.cube4.rotation, 0.5, {z: -45* Math.PI/180});
tl.to(this.cube4.position, 0.5, {x: 50 }, 0.5);
I am very new to three.js so if any terminology is wrong, please warn me
Add the ("red") cube to a THREE.Group, in that way that the rotation axis (the edge) is in the origin of the group. This means the cube has to be shifted by the half side length.
If you rotate the group object, then the cube (which is inside the group) will rotate around the edge and not around its center.
e.g.
var bbox = new THREE.Box3().setFromObject(cube);
cube.position.set(bbox.min.x, bbox.max.y, 0);
var pivot = new THREE.Group();
pivot.add(cube);
scene.add(pivot);
See also the answer to How to center a group of objects?, which uses this solution to rotate a group of objects.
(function onLoad() {
var camera, scene, renderer, orbitControls, pivot;
var rot = 0.02;
init();
animate();
function init() {
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 100);
camera.position.set(4, 1, 2);
//camera.lookAt( -1, 0, 0 );
loader = new THREE.TextureLoader();
loader.setCrossOrigin("");
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
scene.add(camera);
window.onresize = function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
orbitControls = new THREE.OrbitControls(camera, container);
var ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
directionalLight.position.set(1,2,-1.5);
scene.add( directionalLight );
addGridHelper();
createModel();
}
function createModel() {
var material = new THREE.MeshPhongMaterial({color:'#80f080'});
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var cube1 = new THREE.Mesh(geometry, material);
cube1.position.set(0,-0.5,-0.5);
var cube2 = new THREE.Mesh(geometry, material);
cube2.position.set(0,0.5,-0.5);
var cube3 = new THREE.Mesh(geometry, material);
cube3.position.set(0,-0.5,0.5);
var material2 = new THREE.MeshPhongMaterial({color:'#f08080'});
var cube4 = new THREE.Mesh(geometry, material2);
var bbox = new THREE.Box3().setFromObject(cube4);
cube4.position.set(bbox.min.x, bbox.max.y, 0);
pivot = new THREE.Group();
pivot.add(cube4);
pivot.position.set(-bbox.min.x, 0.5-bbox.max.y, 0.5);
scene.add(cube1);
scene.add(cube2);
scene.add(cube3);
scene.add(pivot);
}
function addGridHelper() {
var helper = new THREE.GridHelper(100, 100);
helper.material.opacity = 0.25;
helper.material.transparent = true;
scene.add(helper);
var axis = new THREE.AxesHelper(1000);
scene.add(axis);
}
function animate() {
requestAnimationFrame(animate);
orbitControls.update();
pivot.rotation.z += rot;
if (pivot.rotation.z > 0.0 || pivot.rotation.z < -Math.PI/2) rot *= -1;
render();
}
function render() {
renderer.render(scene, camera);
}
})();
<!--script src="https://threejs.org/build/three.js"></!--script-->
<script src="https://rawcdn.githack.com/mrdoob/three.js/r124/build/three.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r124/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.js"></script>
<div id="container"></div>
From the first image, it appears that the pivot of your red tile is at its center.
For the rotation you want, you would ideally change the pivot to the lower right of the cube. This is impossible without modifying the geometry of the cube.
BUT a simple trick is to create an empty node at that pivot point, parent your cube to that empty, and apply your rotation to the empty. (Don't forget to remove your translation, you don't need it anymore)
Here is some pseudo code, assuming your red box is centered at (0,0,0) and has a width and height of 100:
// create an empty node at desired rotation pivot
var empty = new Object3D or group
empty.position = (50, -50, 0)
// parent your cube to the empty
var cube = your box
empty.add(cube)
// you may need to change the local position of your cube to bring it back to its global position of (0,0,0)
cube.position = (-50, 50, 0)
rotate empty by 45°
I think you can get the bounds of the rotated object like this:
bounds = new THREE.Box3().setFromObject( theRedObject )
Then reposition the object.y based on its bounds.min.y
let scene, camera, controls, ambient, point, loader, renderer, container, stats;
const targetRotation = 0;
const targetRotationOnMouseDown = 0;
const mouseX = 0;
const mouseXOnMouseDown = 0;
const windowHalfX = window.innerWidth / 2;
const windowHalfY = window.innerHeight / 2;
init();
animate();
var box, b1, b2, b3;
function init() {
// Create a scene which will hold all our meshes to be rendered
scene = new THREE.Scene();
// Create and position a camera
camera = new THREE.PerspectiveCamera(
60, // Field of view
window.innerWidth / window.innerHeight, // Aspect ratio
/*window.innerWidth / -8,
window.innerWidth / 8,
window.innerHeight / 8,
window.innerHeight / -8,
*/
0.1, // Near clipping pane
1000 // Far clipping pane
);
scene.add(camera)
// Reposition the camera
camera.position.set(0, 5, 10);
// Point the camera at a given coordinate
camera.lookAt(new THREE.Vector3(0, 0, 0));
// Add orbit control
controls = new THREE.OrbitControls(camera);
controls.target.set(0, -0.5, 0);
controls.update();
// Add an ambient lights
ambient = new THREE.AmbientLight(0xffffff, 0.2);
scene.add(ambient);
// Add a point light that will cast shadows
point = new THREE.PointLight(0xffffff, 1);
point.position.set(25, 50, 25);
point.castShadow = true;
point.shadow.mapSize.width = 1024;
point.shadow.mapSize.height = 1024;
scene.add(point);
group = new THREE.Group();
group.position.y = 0;
scene.add(group);
rotationAnchor = new THREE.Object3D()
group.add(rotationAnchor);
box = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshStandardMaterial({
color: 'grey'
}))
b1 = box.clone();
b2 = box.clone();
b3 = box.clone();
b3.material = b3.material.clone()
b3.material.color.set('red')
group.add(box);
group.add(b1);
b1.position.y += 1
group.add(b2);
b2.position.z += 1
rotationAnchor.add(b3);
rotationAnchor.position.set(0.5, 0.5, 1.5)
b3.position.set(-.5, -.5, -.5)
// Create a renderer
renderer = new THREE.WebGLRenderer({
antialias: true
});
// Set size
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Set color
renderer.setClearColor(0xf8a5c2);
renderer.gammaOutput = true;
// Enable shadow mapping
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Append to the document
container = document.createElement("div");
document.body.appendChild(container);
document.body.appendChild(renderer.domElement);
// Add resize listener
window.addEventListener("resize", onWindowResize, false);
// Enable FPS stats
stats = new Stats();
container.appendChild(stats.dom);
var gui = new dat.GUI({
height: 5 * 32 - 1
});
let params = {
'test': 4,
'bevelThickness': 1,
'bevelSize': 1.5,
'bevelSegments': 3
}
gui.add(params, 'test', 0, 10).onChange(val => {
test = val
})
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
rotationAnchor.rotation.z = (Math.cos(performance.now() * 0.001) * Math.PI * 0.25) + (Math.PI * 1.25)
requestAnimationFrame(animate);
// Re-render scene
renderer.render(scene, camera);
// Update stats
stats.update();
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.2/dat.gui.min.js"></script>
I have a sphere with an earth texture on it using three.js. Although the earth rotates on the y axis on it's own (horizontally), I'm not sure how to rotate the sphere on its vertical x axis based on the mouse position. The earth should show the north pole when the mouse is positioned at the top of the browser window, and the south pole when the mouse is positioned at the bottom of the screen. It should rotate to show the earth between the poles based on the vertical mouse position as the mouse moves vertically within the browser window.
How can this type of rotation be accomplished?
This code sets up the three.js scene, but the math for the rotation is not quite correct:
<html>
<head>
<title>Earth Rotation</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var geometry = new THREE.SphereGeometry(1, 100, 100);
var material = new THREE.MeshPhongMaterial();
var earthMesh = new THREE.Mesh(geometry, material);
material.map = THREE.ImageUtils.loadTexture('images/earth.jpg');
var light = new THREE.AmbientLight( 0xcccccc );
scene.add(light);
scene.add(earthMesh);
camera.position.z = 1.5;
document.addEventListener('mousemove', function(event){
if(event.clientY < window.innerHeight / 2) {
earthMesh.rotation.x = ((window.innerHeight / 2) - (event.clientY * .0001));
} else if(event.clientY > window.innerHeight / 2) {
earthMesh.rotation.x = ((window.innerHeight / 2) + (event.clientY * .0001));
}
}, false)
var animate = function () {
requestAnimationFrame( animate );
earthMesh.rotation.y -= 0.0005;
renderer.render( scene, camera );
};
animate();
</script>
</body>
</html>
Possibly, you can achieve the same thing, using THREE.OrbtiControls() with some modifications.
Just an option with moving the camera over the rotating globe.
r96
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 10;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var globe = new THREE.Mesh(new THREE.SphereGeometry(4, 32, 16), new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load("https://c1.staticflickr.com/3/2521/3884071286_edb50f8137_b.jpg")
}));
scene.add(globe);
window.addEventListener("mousemove", onMouseMove, false);
function onMouseMove(event) {
camera.position.setFromSphericalCoords(10, Math.PI * -event.clientY / window.innerHeight, 0);
camera.lookAt(globe.position);
}
render();
function render() {
requestAnimationFrame(render);
globe.rotation.y -= 0.005;
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
I am trying to learn three.js, and was looking up some examples.
I was trying to run this code https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_cube.html
however, all it displayed was a black screen.
I modified the three.js source to my directory, and I also modified the material to the following, because I don't have the crate texture.
var material = new THREE.MeshStandardMaterial({metalness: 0, roughness: 0.5});
material.color.setHex(0xc23560)
Some code with explanations:
var camera, scene, renderer;
var mesh;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 400;
scene = new THREE.Scene();
light = new THREE.PointLight(0xffffff, 1, 1000); // increase the distance
light.position.set(300,300,300); // [50,50,50] - inside the cube
scene.add(light);
var geometry = new THREE.BoxBufferGeometry(200, 200, 200);
var material = new THREE.MeshStandardMaterial({
color: 0xc23560,
metalness: 0,
roughness: 0.5
});
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
//
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
I figured it out, it just turned out that the material of my box is metallic, and I added the light source wrongly.
I am trying to set up image background for my scene with globe in three.js, but unfortunately, when I did it the main object of my scene also became black (the same colour with background.
I used method:
renderer = new THREE.WebGLRenderer({ antialias: false, alpha:true });
Which makes default background transparent. And then I added image-background in CSS part.
My whole script for the scene looks like this:
var container, stats;
var camera, scene, renderer;
var group;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 2000 );
//closer
camera.position.z = 500;
scene = new THREE.Scene();
group = new THREE.Group();
scene.add( group );
// earth
var loader = new THREE.TextureLoader();
loader.load( 'textures/mapnew1.jpg', function ( texture ) {
var geometry = new THREE.SphereGeometry( 180, 32, 32 );
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
var mesh = new THREE.Mesh( geometry, material );
group.add( mesh );
} );
// shadow
var canvas = document.createElement( 'canvas' );
canvas.width = 128;
canvas.height = 128;
var context = canvas.getContext( '2d' );
var gradient = context.createRadialGradient(
canvas.width / 2,
canvas.height / 2,
0,
canvas.width / 2,
canvas.height / 2,
canvas.width / 2
);
gradient.addColorStop( 0.1, '#000000' );
gradient.addColorStop( 1, '#000000' );
context.fillStyle = gradient;
context.fillRect( 0, 0, canvas.width, canvas.height );
var texture = new THREE.CanvasTexture( canvas );
var geometry = new THREE.PlaneBufferGeometry( 300, 300, 3, 3 );
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.y = - 200;
mesh.rotation.x = - Math.PI / 2;
group.add( mesh );
renderer = new THREE.CanvasRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer = new THREE.WebGLRenderer({ antialias: false, alpha:true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor(0x000000, 0);
container.appendChild( renderer.domElement );
stats = new Stats();
container.appendChild( stats.dom );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
mouseX = ( event.clientX - windowHalfX );
mouseY = ( event.clientY - windowHalfY );
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
camera.position.x += ( mouseX - camera.position.x ) * 0.08;
camera.position.y += ( - mouseY - camera.position.y ) * 0.08;
camera.lookAt( scene.position );
group.rotation.y -= 0.003;
renderer.render( scene, camera );
}
</script>
This is my CSS:
body {
color: #ffffff;
font-family:'Futura';
font-size:20px;
text-align: center;
background-image: url(textures/starfield.png);
background-color: black;
margin: 0px;
overflow: hidden;
}
Do you have any ideas how to fix it and make globe visible?
Thank you very much!
Regarding the background image, you are setting the alpha value for WebGLRenderer, which is correct. You didn't post your CSS, but ensure you're setting the background image on your container, not on the canvas.
Also, comment out this line:
renderer.setClearColor(0x000000, 0);
You don't need to set a clear color, since you are clearing to transparency, not a color. That should resolve the background image issue.
Regarding the all-black model, you need a light in your scene. Try adding this to your init method:
var light = new THREE.PointLight(0xffffff, 1, Infinity);
camera.add(light);
This will add a light source at the location of your camera (and will follow the camera as it moves).
Edit to add snippet:
var container, stats;
var camera, scene, renderer;
var group;
var mouseX = 0,
mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.getElementById('container');
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
//closer
camera.position.z = 500;
var light = new THREE.PointLight(0xffffff, 1, Infinity);
camera.add(light);
scene = new THREE.Scene();
group = new THREE.Group();
scene.add(group);
// earth
var loader = new THREE.TextureLoader();
loader.crossOrigin = '';
loader.load('https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Equirectangular_projection_SW.jpg/640px-Equirectangular_projection_SW.jpg', function(texture) {
var geometry = new THREE.SphereGeometry(180, 32, 32);
var material = new THREE.MeshBasicMaterial({
map: texture,
overdraw: 0.5
});
var mesh = new THREE.Mesh(geometry, material);
group.add(mesh);
});
// shadow
var canvas = document.createElement('canvas');
canvas.width = 128;
canvas.height = 128;
var context = canvas.getContext('2d');
var gradient = context.createRadialGradient(
canvas.width / 2,
canvas.height / 2,
0,
canvas.width / 2,
canvas.height / 2,
canvas.width / 2
);
gradient.addColorStop(0.1, '#000000');
gradient.addColorStop(1, '#000000');
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
var texture = new THREE.CanvasTexture(canvas);
var geometry = new THREE.PlaneBufferGeometry(300, 300, 3, 3);
var material = new THREE.MeshBasicMaterial({
map: texture,
overdraw: 0.5
});
var mesh = new THREE.Mesh(geometry, material);
mesh.position.y = -200;
mesh.rotation.x = -Math.PI / 2;
group.add(mesh);
renderer = new THREE.WebGLRenderer({
antialias: false,
alpha: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
//renderer.setClearColor(0x000000, 0);
container.appendChild(renderer.domElement);
stats = new Stats();
container.appendChild(stats.dom);
document.addEventListener('mousemove', onDocumentMouseMove, false);
//
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function onDocumentMouseMove(event) {
mouseX = (event.clientX - windowHalfX);
mouseY = (event.clientY - windowHalfY);
}
//
function animate() {
requestAnimationFrame(animate);
render();
stats.update();
}
function render() {
camera.position.x += (mouseX - camera.position.x) * 0.08;
camera.position.y += (-mouseY - camera.position.y) * 0.08;
camera.lookAt(scene.position);
group.rotation.y -= 0.003;
renderer.render(scene, camera);
}
body {
color: #ffffff;
font-family: 'Futura';
font-size: 20px;
text-align: center;
background-image: url(https://upload.wikimedia.org/wikipedia/commons/6/62/Starsinthesky.jpg);
background-color: black;
margin: 0px;
overflow: hidden;
}
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/renderers/Projector.js"></script>
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<div id="container"></div>
three.js r86
Since a while, there is:
var texture = new THREE.TextureLoader().load( "textures/bg.jpg" );
scene.background = texture;
I'm using three.js v 0.87
There are two ways to do it
1) Load a image using TextureLoader and set it as background. This will result into static background which may not look very realistic.
var texture = new THREE.TextureLoader().load(
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
);
scene.background = texture;
2) Use skybox to load images for top, left, right bottom, front back sides. Then set them inside a cube or sphere geometry
var urls = [
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg"
];
var materialArray = [];
for (var i = 0; i < 6; i++)
materialArray.push(
new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load(urls[i]),
side: THREE.BackSide
})
);
var skyGeometry = new THREE.SphereGeometry(400, 32, 32);
var skyMaterial = new THREE.MeshFaceMaterial(materialArray);
var skybox = new THREE.Mesh(skyGeometry, skyMaterial);
scene.add(skybox);
This will give a sphere with images as texture on backside. Just replace THREE.SphereGeometry with THREE.CubeGeometry and you can emulate envMap.
The previous solutions didn't work for me,
they miss the using of callback so at least from v.0.124 of the library,
this is how you can set the background image for the scene:
var texture_bg = new THREE.TextureLoader().load("img/bg.jpg", () => {
scene.background = texture_bg;
});
http://jsfiddle.net/wp6E3/3/
var camera, scene, renderer;
var cubes = [];
init();
animate();
function init() {
scene = new THREE.Scene();
scene.add(new THREE.AmbientLight(0x212223));
for (var i = 0; i < 10; i++) {
var cubeGeometry = new THREE.CubeGeometry(1, 1.5, 1);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 0x1ec876 });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(i*1.2, 0, 0.5);
cube.castShadow = true;
scene.add(cube);
cubes.push(cube);
}
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
camera.position.x = -4;
camera.position.y = -4;
camera.position.z = 20;
camera.lookAt(cubes[5].position);
scene.add(camera);
var terrainGeo = new THREE.PlaneGeometry(50, 50);
var terrainMaterial = new THREE.MeshLambertMaterial({ color: 0xc0c0a0 });
var terrain = new THREE.Mesh(terrainGeo, terrainMaterial);
terrain.receiveShadow = true;
scene.add(terrain);
var light = new THREE.DirectionalLight(0xffffff, 1);
light.castShadow = true;
light.shadowCameraVisible = true;
light.position.set(-3, 1, 5);
scene.add(light);
scene.add( new THREE.DirectionalLightHelper(light, 0.2) );
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = false;
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
for (var i = 0; i < cubes.length; i++) {
cubes[i].rotation.x += 0.01 * i;
cubes[i].rotation.y += 0.02 * i;
}
renderer.render(scene, camera);
}
Why shadows doesn't work?
I've looked related questions and three.js references but don't understand what I do wrong.
Three.js shadows not working properly
How to create directional light shadow in Three.JS?
ThreeJS shadow not rendering
http://threejs.org/docs/#Reference/Lights/DirectionalLight
http://learningthreejs.com/blog/2012/01/20/casting-shadows/
First of all, add a camera controller to your scene so you can see what you are doing. Now you can rotate the camera for different views.
controls = new THREE.OrbitControls( camera, renderer.domElement );
Second, when using a jsfiddle, be sure to link to the recent version of the three.js library.
<script src="http://threejs.org/build/three.min.js"></script>
For proper resolution, is important that your shadow camera is positioned tight around your scene. You do that by setting the following:
light.shadowCameraLeft = -20; // or whatever value works for the scale of your scene
light.shadowCameraRight = 20;
light.shadowCameraTop = 20;
light.shadowCameraBottom = -20;
For directional lights, only the "direction to" the light's position matters. However, when shadow maps are involved, the actual position of the light is important, since it controls the shadow camera, too.
light.position.set( -60, 20, 100 );
Here is an updated fiddle. Rotate the camera with the mouse.
http://jsfiddle.net/wp6E3/4/
three.js r.66
Add these to your light definition:
light.shadowMapWidth =
light.shadowMapHeight = 1024;
light.shadowCameraNear = 1;
light.shadowCameraFar = 100;