Issue with three.js and shadows - javascript

I am trying to make an opaque box with three.js, but the light is still going thought the box:
I have one "THREE.SpotLight" and 2 objects in my scene: the sphere is projecting the shadow onto the box.
There are 2 shadows (I think there should be only one):
the first, at the top of the box seems correct,
the second is weird (as if the box where transparent).
Illustration here: http://i.stack.imgur.com/ZNmI3.png
var scene, camera, renderer;
var material;
init();
function init() {
//Renderer
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.shadowMapEnabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
scene = new THREE.Scene();
//Camera
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 20, 20);
camera.lookAt(new THREE.Vector3(0, 15, 0));
//Material
material = new THREE.MeshLambertMaterial({
color: 0xffffff
});
//Box
var box = new THREE.Mesh(new THREE.BoxGeometry(7, 16, 7), material);
box.position.y = 8;
box.castShadow = true;
box.receiveShadow = true;
scene.add(box);
//Sphere
geometry = new THREE.SphereGeometry(.8, 48, 48);
var sphere = new THREE.Mesh(geometry, material);
sphere.position.set(-5, 17, -3);
sphere.castShadow = true;
sphere.receiveShadow = true;
scene.add(sphere);
// Lights
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-50, 40, -50);
spotLight.target.position.set(-5, 17, -3);
spotLight.castShadow = true;
spotLight.shadowMapWidth = 2048;
spotLight.shadowMapHeight = 2048;
spotLight.shadowCameraVisible = true;
scene.add(spotLight);
var ambientLight = new THREE.AmbientLight(0x444444);
scene.add(ambientLight);
document.body.appendChild(renderer.domElement);
}
renderer.render(scene, camera);
My question is:
How can i make the box opaque?
Jsfiddle here: http://jsfiddle.net/v81gs6u1/4/

It is not the light that is going through the box but the shadow. Try playing with the shadow bias.
In your case adding:
spotLight.shadowBias = 0.001;
takes care of the artifact.

Related

Problem rendering first 2 objects in three.js

everything works fine but sphere and box geometry dont show, plane works fine too! does anyone have a clue? i suspect something wrong maybe in the render function or animation frame, im fairly new to three.js and cant seem to know why the scene wont show the other geometry, i tried different materials, rotation, clear color, etc
var renderer,
scene,
camera,
myCanvas = document.getElementById('myCanvas');
//RENDERER
renderer = new THREE.WebGLRenderer({
canvas: myCanvas,
antialias: true,
});
renderer.setClearColor(0x000000);
renderer.setPixelRatio(window.devicePixelRatio); //device pixel ratio
renderer.setSize(window.innerWidth, window.innerHeight); //canvas size
//CAMERA
var camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 300, 10000)
//SCENE
var scene = new THREE.Scene();
//LIGHT
var light = new THREE.AmbientLight(0xffff, 0.5)
scene.add(light);
var light1 = new THREE.PointLight(0xffff, 0.5)
scene.add(light1);
//MATERIAL
var material = new THREE.MeshLambertMaterial({
color: 0xF3FFE2,
lightMap: null,
lightMapIntensity: 1,
emissive: 0x000000,
emissiveMap: null,
emissiveIntensity: 1,
specularMap: null
});
//GEOMETRY
var geometry = new THREE.BoxGeometry(100, 100, 100);
var mesh = new THREE.Points(geometry, material);
mesh.position.z = -1000;
mesh.position.x = -100;
scene.add(mesh);
var geometry2 = new THREE.SphereGeometry(50, 20, 20);
var mesh2 = new THREE.Points(geometry2, material);
mesh2.position.z = -1000;
mesh2.position.x = 100;
scene.add(mesh2);
var geometry3 =  new THREE.PlaneGeometry(10000, 10000, 100, 100);
var mesh3 = new THREE.Mesh(geometry3, material);
mesh3.rotation.x = -90 * Math.PI / 180;
mesh3.position.y = -100;
scene.add(mesh3);
//RENDER LOOP
render();
function render() {
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
Tried your code, everything is ok but the 2 objects need to be THREE.Mesh
var geometry = new THREE.BoxGeometry(100, 100, 100);
var mesh = new THREE.Mesh(geometry, material);
mesh.position.z = -1000;
mesh.position.x = -100;
scene.add(mesh);
var geometry2 = new THREE.SphereGeometry(50, 20, 20);
var mesh2 = new THREE.Mesh(geometry2, material);
mesh2.position.z = -1000;
mesh2.position.x = 100;
scene.add(mesh2);

ThreeJs different Text on each face of cube

I'm working on Threejs to animate a cube with different text on each cube faces. I used DynamicTexture to place text on cube faces, but it places same text on each side of cube. I don't know how to place different text on each side. Is there any way to do is and place text on runtime by user inputs? Thanks.
Main.js
var scene = new THREE.Scene();
scene.background = new THREE.Color('white');
var camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 1, 1000);
camera.position.set(4, 4, 4);
camera.lookAt(0, 0, 0);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('display').appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera);
var dynamictexture = new THREEx.DynamicTexture(512, 512);
dynamictexture.context.font = "bolder 90px verdana";
dynamictexture.texture.needsUpdate = true;
dynamictexture.clear('#d35400').drawText('Text', undefined, 256, 'green');
var geometry = new THREE.BoxGeometry(2, 2, 2);
var material = new THREE.MeshBasicMaterial({color: 0xffffff, map: dynamictexture.texture, opacity:1,
transparent: true});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
function animate() {
requestAnimationFrame(animate);
controls.update();
dynamictexture.texture
renderer.render(scene, camera);
};
animate();
You can use THREE.MeshFaceMaterial(materials) to accomplish this. All you need to do is pass an array containing the materials and specifying the map for each of the faces.
var face_textures = [];
function createFaceTextures() {
var i;
for(i = 0; i < 6; i++) {
var dynamictexture = new THREEx.DynamicTexture(512, 512);
dynamictexture.context.font = "bolder 90px verdana";
dynamictexture.texture.needsUpdate = true;
dynamictexture.clear('#d35400').drawText(i.toString(), undefined, 256, 'green');
face_textures.push(dynamictexture);
}
}
createFaceTextures();
var scene = new THREE.Scene();
scene.background = new THREE.Color('white');
var camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 1, 1000);
camera.position.set(4, 4, 4);
camera.lookAt(0, 0, 0);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('display').appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera);
var dynamictexture = new THREEx.DynamicTexture(512, 512);
dynamictexture.context.font = "bolder 90px verdana";
dynamictexture.texture.needsUpdate = true;
dynamictexture.clear('#d35400').drawText('Text', undefined, 256, 'green');
var geometry = new THREE.BoxGeometry(2, 2, 2,);
var material = new THREE.MeshBasicMaterial({color: 0xffffff, map: dynamictexture.texture, opacity:1, transparent: true});
var materials = [
new THREE.MeshBasicMaterial({map: face_textures[0].texture}),
new THREE.MeshBasicMaterial({map: face_textures[1].texture}),
new THREE.MeshBasicMaterial({map: face_textures[2].texture}),
new THREE.MeshBasicMaterial({map: face_textures[3].texture}),
new THREE.MeshBasicMaterial({map: face_textures[4].texture}),
new THREE.MeshBasicMaterial({map: face_textures[5].texture})
];
var cube = new THREE.Mesh(geometry, materials);
scene.add(cube);
function animate() {
requestAnimationFrame(animate);
controls.update();
dynamictexture.texture
renderer.render(scene, camera);
}
animate();

How to rotate object with offset by orbit control in three.js?

I want to control object like this:
Now camera is move around Y coordinate, but need to be move around NEW Y. Code is here:
var material = new THREE.MeshLambertMaterial({color: 0x00ff00});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
var controls = new THREE.OrbitControls(camera);
cube.position.x = 300;
// controls.target = THREE.Vector3(300, 0, 0);
I found that target option can set the focus point of the controls, but if I add this code: controls.target = THREE.Vector3(300, 0, 0); the object back to the center of the screen, but it should be at the right edge.
More over, when I set new THREE.OrbitControls(camera); to new THREE.OrbitControls(cube); and add controls.target = THREE.Vector3(300, 0, 0); control doesn't work, but when I set controls.target = THREE.Vector3(301, 0, 0); it is managed but not like a camera
OrbitControls.target set the focus point of the controls and the .object orbits around this. But it is a manually manipulation. As mentioned in the documentation OrbitControls.update() must be called after any manual changes to the camera's transform.
e.g.
controls.target = new THREE.Vector3(1, 0, 0)
controls.update();
See the example:
(function onLoad() {
var container, camera, scene, renderer, controls;
init();
animate();
function init() {
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({
antialias: 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(0, 1.0, -4);
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
scene.add(camera);
window.onresize = resize;
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 );
controls = new THREE.OrbitControls(camera, container);
controls.target = new THREE.Vector3(3, 0, 0)
controls.update();
controls.autoRotate = true;
controls.autoRotateSpeed = 5.0
var axis = new THREE.AxesHelper(1000);
scene.add(axis);
var material = new THREE.MeshPhongMaterial({color:'#b090b0'});
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
}
function resize() {
var aspect = window.innerWidth / window.innerHeight;
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = aspect;
camera.updateProjectionMatrix();
}
function animate() {
requestAnimationFrame(animate);
controls.update();
render();
}
function render() {
renderer.render(scene, camera);
}
})();
<script src="https://cdn.jsdelivr.net/npm/three#0.115/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.115/examples/js/controls/OrbitControls.js"></script>
<div id="container"></div>

Three.js: draw a octahedron

I want to draw a Octahedron,but the shape of the result is below expectation.I dont know the reason and next step I want to draw a Dodecahedron, any suggestions?The result of the Octahedron
My code:
var mesh, renderer, scene, camera, controls;
init();
animate();
function init() {
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera(40, window.innerWidth /
window.innerHeight, 1, 10000);
camera.position.set(20, 20, 20);
// controls
controls = new THREE.OrbitControls(camera);
// ambient
scene.add(new THREE.AmbientLight(0x222222));
// light
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(20, 20, 0);
scene.add(light);
// axes
scene.add(new THREE.AxisHelper(20));
// geometry
//var geometry = new THREE.SphereGeometry(5, 12, 8);
var vertices = [
0.5,0,0, 0,0.3,0, -0.5,0,0, 0,-0.3,0, 0,0,0.3, 0,0,-0.3
];
var faces = [
0,1,4, 1,2,4, 2,3,4, 3,0,4, 0,1,5, 1,2,5, 2,3,5, 3,0,5
];
var geometry = new THREE.PolyhedronGeometry(vertices, faces, 5, 1);
// material
var material = new THREE.MeshPhongMaterial({
color: 0x00ffff,
shading: THREE.FlatShading,
wireframe:true,
transparent: true,
opacity: 0.7,
});
// mesh
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
}
function animate() {
requestAnimationFrame(animate);
//controls.update();
renderer.render(scene, camera);
}
Use
var geometry = new THREE.OctahedronGeometry( 5, 0 ); // or DodecahedronGeometry
Read and understand the source code of OctahedronGeometry.js if you want to use PolyhedronGeometry directly.
If wireframe is true, use MeshBasicMaterial, instead.
three.js r.85

ThreeJS - Intersection of a line and sphere

I have two objects on my scene: a red line and a sphere.
While camera rotating/zooming/moving, I need to check the following:
Does the line intersects with the sphere looking from the current position of the camera (please see images below)? Please use this JS fiddle that creates the scene on the images.
I know how to find the intersection between the current mouse position and objects on the scene (just like this example shows).
But how to do this in my case?
JS Fiddle Code:
/**
* PREPARE SCENE
*/
var mouse = {
x : 0,
y : 0
};
var projector = new THREE.Projector();
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75,
window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = -5;
camera.position.y = 5;
camera.position.z = 30;
var renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.TrackballControls(camera,
renderer.domElement);
controls.rotateSpeed = 3.0;
controls.zoomSpeed = 1.5;
controls.panSpeed = 1.0;
controls.staticMoving = true;
var grid = new THREE.GridHelper(20, 5);
scene.add(grid);
/**
* CREATE SPHERE
*/
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(5, 10, 10),
new THREE.MeshNormalMaterial());
sphere.overdraw = true;
scene.add(sphere);
/**
* CREATE LINE
*/
var lineMaterial = new THREE.LineBasicMaterial({
color : 0xFF0000
});
var lineGeometry = new THREE.Geometry();
lineGeometry.vertices.push(new THREE.Vector3(8, 8, 8));
lineGeometry.vertices.push(new THREE.Vector3(8, 8, 20));
var line = new THREE.Line(lineGeometry, lineMaterial);
scene.add(line);
renderer.domElement.addEventListener('mousemove', render, false);
render();
function render(event) {
var mouse = {};
/*
* INTERSECTION
*/
if (event != null) {
//intersection job???
}
controls.update();
renderer.render(scene, camera);
}
So, I found the solution that is pretty simple (of course). See new JS Fiddle that checks intersection of the line and sphere and visualizes the ray for debugging.
The JS Fiddle code:
var camera, controls, scene, renderer;
init();
animate();
render();
function init() {
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 800;
controls = new THREE.TrackballControls(camera);
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 4;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.addEventListener('change', render);
// world
scene = new THREE.Scene();
sceneTarget = new THREE.Scene();
var grid = new THREE.GridHelper(500, 50);
scene.add(grid);
/**
* CREATE LINE
*/
var lineMaterial = new THREE.LineBasicMaterial({
color : 0xFF0000
});
var lineGeometry = new THREE.Geometry();
lineGeometry.vertices.push(new THREE.Vector3(100, 200, 100));
lineGeometry.vertices.push(new THREE.Vector3(300, 200, 200));
var line = new THREE.Line(lineGeometry, lineMaterial);
sceneTarget.add(line);
/*
* CREARE SPHERE
*/
var sphere = new THREE.Mesh(new THREE.SphereGeometry(150, 100, 100), new THREE.MeshNormalMaterial());
sphere.overdraw = true;
scene.add(sphere);
// renderer
renderer = new THREE.WebGLRenderer({
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.autoClear = false;
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
}
function render() {
renderer.render(scene, camera);
renderer.render(sceneTarget, camera);
intersect();
}
function intersect() {
var direction = new THREE.Vector3(100, 200, 100);
var startPoint = camera.position.clone();
var directionVector = direction.sub( startPoint );
var ray = new THREE.Raycaster(startPoint, directionVector.clone(). normalize());
scene.updateMatrixWorld(); // required, since you haven't rendered yet
var rayIntersects = ray.intersectObjects(scene.children, true);
if (rayIntersects[0]) {
//inersection is found
console.log(rayIntersects[0]);
//visualize the ray for debugging
var material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(ray.ray.origin.x, ray.ray.origin.y, ray.ray.origin.z));
geometry.vertices.push(new THREE.Vector3(100, 200, 100));
var line = new THREE.Line(geometry, material);
sceneTarget.add( line );
}
}

Categories

Resources