ThreeJS is not casting shadows - javascript

I am building a basic Three JS application. Basically, I am learning Three JS and so that I am experimenting with it. Now, I am building a scene where there is a floor, an object and a light. I want to see the shadow of the object on the floor due to light. This is my code.
import * as THREE from 'three';
const scene = new THREE.Scene();
const aspect_ratio = window.innerWidth / window.innerHeight;
const camera = new THREE.PerspectiveCamera(75, aspect_ratio, 1, 10000);
camera.position.z = 500;
scene.add(camera);
const renderer = new THREE.WebGLRenderer();
renderer.shadowMapEnabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.append(renderer.domElement);
var shape = new THREE.TorusGeometry(100, 50, 8, 20);
var cover = new THREE.MeshPhongMaterial();
cover.emissive.setRGB(0.8, 0.1, 0.1);
cover.specular.setRGB(0.9, 0.9, 0.9);
var donut = new THREE.Mesh(shape, cover); scene.add(donut);
donut.castShadow = true;
var sunlight = new THREE.DirectionalLight();
sunlight.intensity = 0.5;
sunlight.position.set(100, 100, 100);
scene.add(sunlight);
sunlight.castShadow = true;
var shape = new THREE.PlaneGeometry(1500, 1500);
var cover = new THREE.MeshBasicMaterial();
var ground = new THREE.Mesh(shape, cover);
scene.add(ground);
ground.position.set(0, -180, 0);
ground.rotation.set(-Math.PI/2, 0, 0);
ground.receiveShadow = true;
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
I am supposed to see the shadow of the donut on the floor. But this is what I see instead without shadow.
What is wrong with my code and how can I fix it?

You have to make the ground to receive shadow
to do this:
ground.receiveShadow = true;

There are multiple issues in your code. The most important problem is that you do not configure your shadow frustum correctly. Besides, MeshBasicMaterial is not affected by light and thus can't receive shadows. Try it like so:
const scene = new THREE.Scene();
const aspect_ratio = window.innerWidth / window.innerHeight;
const camera = new THREE.PerspectiveCamera(75, aspect_ratio, 1, 10000);
camera.position.z = 500;
scene.add(camera);
const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.append(renderer.domElement);
const donutGeometry = new THREE.TorusGeometry(100, 50, 8, 20);
const donutMaterial = new THREE.MeshPhongMaterial();
donutMaterial.emissive.setRGB(0.8, 0.1, 0.1);
donutMaterial.specular.setRGB(0.9, 0.9, 0.9);
const donut = new THREE.Mesh(donutGeometry, donutMaterial);
scene.add(donut);
donut.castShadow = true;
var sunlight = new THREE.DirectionalLight();
sunlight.intensity = 0.5;
sunlight.position.set(100, 100, 100);
scene.add(sunlight);
sunlight.castShadow = true;
sunlight.shadow.camera.top = 200;
sunlight.shadow.camera.bottom = - 200;
sunlight.shadow.camera.left = - 200;
sunlight.shadow.camera.right = 200;
sunlight.shadow.camera.near = 1;
sunlight.shadow.camera.far = 1000;
//scene.add( new THREE.CameraHelper( sunlight.shadow.camera ) );
const groundGeometry = new THREE.PlaneGeometry(1500, 1500);
const groundMaterial = new THREE.MeshPhongMaterial();
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
scene.add(ground);
ground.position.set(0, -180, 0);
ground.rotation.set(-Math.PI/2, 0, 0);
ground.receiveShadow = true;
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.144/build/three.min.js"></script>

Related

I have having issues implementing procedural terrain generation on my three js project

Hello friends https://github.com/IceCreamYou/THREE.Terrain This is a great Library for procedural I want to add the procedural terrain generation in my code
Code goes here
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight,0.01, 100000);
camera.position.set(50, 10, 50)
camera.position.z = 10
const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.setClearColor(0xcccccc, 1.0);
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new THREE.OrbitControls( camera,renderer.domElement );
controls.screenSpacePanning = true;
const sceneMeshes = [];
const axesHelper = new THREE.AxesHelper( 1000 );
scene.add( axesHelper );
axesHelper.position.y = 0
const shadowLight = new THREE.DirectionalLight(0xffffff, 0.6);
// Set the direction of the light
shadowLight.position.set(150, 350, 350);
// Allow shadow casting
shadowLight.castShadow = true
// define the visible area of the projected shadow
shadowLight.shadow.camera.left = -400;
shadowLight.shadow.camera.right = 400;
shadowLight.shadow.camera.top = 400;
shadowLight.shadow.camera.bottom = -400;
shadowLight.shadow.camera.near = 1;
shadowLight.shadow.camera.far = 10000;
// define the resolution of the shadow; the higher the better,
// but also the more expensive and less performant
shadowLight.shadow.mapSize.width = 2048;
shadowLight.shadow.mapSize.height = 2048;
// to activate the lights, just add them to the scene
scene.add(shadowLight);
const animate = function (){
requestAnimationFrame( animate );
renderer.render( scene, camera );
};
animate();
Normal Scene
please help me for my project
Here is a live example based on your code using the default approach of THREE.Terrain for generating a terrain mesh:
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 100000);
camera.position.set(0, 250, 1000)
const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.setClearColor(0xcccccc, 1.0);
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.screenSpacePanning = true;
const sceneMeshes = [];
const axesHelper = new THREE.AxesHelper(1000);
scene.add(axesHelper);
axesHelper.position.y = 0
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.6);
scene.add(hemiLight);
const shadowLight = new THREE.DirectionalLight(0xffffff, 0.8);
// Set the direction of the light
shadowLight.position.set(0, 1000, 0);
// Allow shadow casting
shadowLight.castShadow = true
// define the visible area of the projected shadow
shadowLight.shadow.camera.left = -400;
shadowLight.shadow.camera.right = 400;
shadowLight.shadow.camera.top = 400;
shadowLight.shadow.camera.bottom = -400;
shadowLight.shadow.camera.near = 1;
shadowLight.shadow.camera.far = 10000;
// define the resolution of the shadow; the higher the better,
// but also the more expensive and less performant
shadowLight.shadow.mapSize.width = 2048;
shadowLight.shadow.mapSize.height = 2048;
// to activate the lights, just add them to the scene
scene.add(shadowLight);
//
// Generate a terrain
var xS = 63,
yS = 63;
terrainScene = THREE.Terrain({
easing: THREE.Terrain.Linear,
frequency: 2.5,
heightmap: THREE.Terrain.DiamondSquare,
material: new THREE.MeshLambertMaterial({
color: 0x654321
}),
maxHeight: 100,
minHeight: -100,
steps: 1,
xSegments: xS,
xSize: 1024,
ySegments: yS,
ySize: 1024,
});
// Assuming you already have your global scene, add the terrain to it
scene.add(terrainScene);
const animate = function() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.131.3/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.131.3/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three.terrain.js#2.0.0/build/THREE.Terrain.min.js"></script>

How to make two canvas with two separate javascript code?

I am using Three.js to develop a cube that translates and rotate in 3D space using data from accelerometer and gyroscope data.
So far I have one canvas that shows the accelerometer movement. Now I need to have another canvas that shows the gyroscope data on a separate canvas, I prefer to have two JS code for each canvas, so they are independent of each other. I wasn't able to make two separate canvases, and I don't know if it is even possible to use two different javascript codes in the html.
Below is how my HTML is structured:
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<canvas id="canvas" width="500" height="800" style="border:1px solid #eb1c1c;"></canvas>
<div id="info">
<div>t = <span id="time">0</span> s</div>
<div>accX = <span id="accX">0</span></div>
<div>accY = <span id="accY">0</span></div>
<div>accZ = <span id="accZ">0</span></div>
</div>
</body>
</html>
and this is the javascript:
import * as THREE from "three";
import data from "../data/data.json"
import "./style.css"
var width = window.innerWidth;
var height = window.innerHeight;
const canvas = document.querySelector('#canvas');
const renderer = new THREE.WebGLRenderer({ canvas });
renderer.setSize (width, height);
var planeSize = 100000
const fov = 70;
const aspect = 2; // the canvas default
const near = 20;
const far = 500;
const camera = new THREE.PerspectiveCamera(70, width/height, 1, 10000);
camera.position.y = 3;
camera.position.z = 30;
camera.lookAt (new THREE.Vector3(0,0,0));
// camera.position.set(0, 40, 1.5);
// camera.up.set(0, 10, 1);
// camera.lookAt(0, 10, 0);
const scene = new THREE.Scene();
{
const color = 0x00afaf;
const intensity = 10;
const size = 10;
const divisions = 10;
const gridHelper = new THREE.GridHelper( planeSize, 5000 );
gridHelper.setColors( new THREE.Color(0xff0000), new THREE.Color(0xffffff) );
scene.add(gridHelper);
const light = new THREE.PointLight(color, intensity);
scene.add(light);
// scene.add( gridHelper );
}
// // label the axis
// var textGeo = new THREE.TextGeometry('Y', {
// size: 5,
// height: 2,
// curveSegments: 6,
// font: "helvetiker",
// style: "normal"
// });
// var color = new THREE.Color();
// color.setRGB(255, 250, 250);
// var textMaterial = new THREE.MeshBasicMaterial({ color: color });
// var text = new THREE.Mesh(textGeo , textMaterial);
// text.position.x = axis.geometry.vertices[1].x;
// text.position.y = axis.geometry.vertices[1].y;
// text.position.z = axis.geometry.vertices[1].z;
// text.rotation = camera.rotation;
// scene.add(text);
const boxGeometry = new THREE.BoxGeometry();
const boxMaterial = new THREE.MeshBasicMaterial({ color: "green", wireframe: false });
const object = new THREE.Mesh(boxGeometry, boxMaterial);
var cubeAxis = new THREE.AxesHelper(3);
object.add(cubeAxis);
object.scale.set(5, 5, 5)
scene.add(object);
scene.background = new THREE.Color(0.22, 0.23, 0.22);
let currentIndex = 0
let time = data[currentIndex].time
let velocity = new THREE.Vector3()
requestAnimationFrame(render);
function render(dt) {
dt *= 0.0001 // in seconds
time += dt
document.querySelector("#time").textContent = time.toFixed(2)
// Find datapoint matching current time
while (data[currentIndex].time < time) {
currentIndex++
if (currentIndex >= data.length) return
}
const { rotX, rotY, rotZ, accX, accY, accZ } = data[currentIndex]
document.querySelector("#accX").textContent = accX* 10;
document.querySelector("#accY").textContent = accY* 10;
document.querySelector("#accZ").textContent = accZ* 10;
const acceleration = new THREE.Vector3()
// object.rotation.set( rotX, rotY, rotZ)
object.position.x = accX * 30;
// object.position.add(velocity.clone().multiplyScalar(dt)).add(acceleration.clone().multiplyScalar(50 * dt ** 2))
// object.position.add(accZ)
// velocity.add(acceleration.clone().multiplyScalar(dt))
var relativeCameraOffset = new THREE.Vector3 (0,10,10);
var cameraOffset = relativeCameraOffset.applyMatrix4( object.matrixWorld );
camera.position.x = cameraOffset.x;
camera.position.y = cameraOffset.y;
camera.position.z = cameraOffset.z;
camera.lookAt( object.position );
resizeToClient();
renderer.render(scene, camera);
requestAnimationFrame(render);
}
function resizeToClient() {
const needResize = resizeRendererToDisplaySize()
if (needResize) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
}
function resizeRendererToDisplaySize() {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
this is how I want the canvas to look like:
Good news is it is possible, you just have to put all your code(at least animations) in separate functions :
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const scene1 = new THREE.Scene();
const camera1 = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
scene.background = new THREE.Color( 0xf0000f);
scene1.background = new THREE.Color( 0x0000ff );
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
const renderer1 = new THREE.WebGLRenderer();
renderer1.setSize( window.innerWidth, window.innerHeight );
renderer1.domElement.width=500;
renderer1.domElement.height=300;
renderer1.domElement.style.position="absolute";
renderer1.domElement.style.top=0;
renderer1.domElement.style.height=150+"px";
renderer1.domElement.style.width=200+"px";
renderer.domElement.width=500;
renderer.domElement.height=300;
renderer.domElement.style.position="absolute";
renderer.domElement.style.top=0;
document.body.appendChild( renderer.domElement );
document.body.appendChild( renderer1.domElement );
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
const geometry1 = new THREE.BoxGeometry(3,3,3);
const material1 = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube1 = new THREE.Mesh( geometry1, material1 );
scene1.add( cube1 );
camera.position.z = 5;
camera1.position.z = 5;
const animate = function () {
requestAnimationFrame( animate );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
};
const animate1 = function () {
requestAnimationFrame( animate1 );
cube1.rotation.x += 0.01;
cube1.rotation.y += 0.01;
renderer1.render( scene1, camera1 );
};
animate();
animate1();
<script src="http://threejs.org/build/three.min.js"></script>

Light behind solid geometry

I'm creating an HTML file integrating ThreeJs, basically I have created 4 Spheres, 1 of them projects the light, other 3 spheres turn in a wall. When the Spheres is behind the wall they should not reflect the light, what I supposed to do to solve this?
I've already try changing the materials of the Spheres which turns around the wall to Lambert and Phong, setting up castShadow to true, and recieveShadow to False
(function onLoad() {
var camera, scene, renderer, orbitControls;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 30, -100);
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
scene.add(camera);
orbitControls = new THREE.OrbitControls(camera);
escena = scene;
esferaLuz = new THREE.SphereBufferGeometry(0.5, 16, 16);
luzUno = new THREE.SpotLight(0xFFFFFF, 1);
luzUno.angle = Math.PI / 12;
luzUno.penumbra = 0.05;
luzUno.decay = 2;
luzUno.position.set(-30, 40, -5);
mtLuzUno = new THREE.MeshBasicMaterial({color: 0xFFFFFF});
mallaLuzUno = new THREE.Mesh(esferaLuz, mtLuzUno);
luzUno.add(mallaLuzUno);
escena.add(luzUno);
luzUno.castShadow = true;
luzUno.shadow.mapSize.width = 1024;
luzUno.shadow.mapSize.height = 1024;
luzUno.shadow.camera.near = 10;
luzUno.shadow.camera.far = 200;
luzMap = new THREE.SpotLightHelper(luzUno);
escena.add(luzMap);
sombraMap = new THREE.CameraHelper(luzUno.shadow.camera);
escena.add(sombraMap);
var luzAmbiente = new THREE.AmbientLight( 0xffffff, 0.1 );
escena.add(luzAmbiente);
geometriaPlana = new THREE.CubeGeometry(100, 100, 2, 2);
mtPlano = new THREE.MeshLambertMaterial({color: 0x000000});
mtPlano.transparent = false;
mtPlano.depthWrite = true;
mallaPlano = new THREE.Mesh(geometriaPlana, mtPlano);
mallaPlano.rotation.x = -0.5*Math.PI;
mallaPlano.position.x = 15;
mallaPlano.position.y = 0;
mallaPlano.position.z = 0;
mallaPlano.receiveShadow = true;
escena.add(mallaPlano);
objEsfera = new THREE.SphereGeometry(5, 100, 100);
mtObjEsfera = new THREE.MeshPhongMaterial({color: 0xFFFFFF, specular:0xFFFFFF, shininess: 1024});
mallaObjEsfera3 = new THREE.Mesh(objEsfera, mtObjEsfera);
mallaObjEsfera3.position.set(20, 0, 0);
mallaObjEsfera3.castShadow = true;
mallaObjEsfera3.receiveShadow = false;
escena.add(mallaObjEsfera3);
objEsfera = new THREE.SphereGeometry(5, 100, 100);
mtObjEsfera = new THREE.MeshPhongMaterial({color: 0xF90E0E, specular:0xF90E0E, shininess: 512});
mallaObjEsfera2 = new THREE.Mesh(objEsfera, mtObjEsfera);
mallaObjEsfera2.position.set(5, 0, 0);
mallaObjEsfera2.castShadow = true;
mallaObjEsfera2.receiveShadow = false;
escena.add(mallaObjEsfera2);
objEsfera = new THREE.SphereGeometry(5, 100, 100);
mtObjEsfera = new THREE.MeshLambertMaterial({color: 0xF2E406});
mallaObjEsfera = new THREE.Mesh(objEsfera, mtObjEsfera);
mallaObjEsfera.position.set(-10, 0, 0);
mallaObjEsfera.castShadow = true;
mallaObjEsfera.receiveShadow = false;
escena.add(mallaObjEsfera);
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio( window.devicePixelRatio);
renderer.setClearColor(0xEEEEEE);
renderer.shadowMap.enabled = true;
renderer.shadowMap.renderReverseSided = false;
renderer.sortObjects = false
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize( window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.gammaInput = true;
renderer.gammaOutput = true;
window.onresize = function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
}
function animate() {
requestAnimationFrame(animate);
orbitControls.update();
render();
}
function render() {
renderer.render(scene, camera);
}
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/103/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
I expect that when the spheres is behind the wall, don't show any type of reflects of light but when is on the front reflect the light .
One way to achieve your intended result is to work with shadows. So you have to set Object3D.castShadow and Object3D.receiveShadow to true for your spheres and your ground like in the following live example:
https://jsfiddle.net/85q3sfeg/
Also keep in mind that three.js does not support selective lighting so far. This issue was already discussed at github right here: https://github.com/mrdoob/three.js/issues/5180
Assuming all objects of your scene have a lit material applied, you can't define what light sources should affect what objects.
three.js R103

Preserve constant size regardless of perspective in Three.js

How can I preserve constant size of meshes regardless of perspective using Three.js?
Lets assume I have multiple meshes of the same size. I want them to always have the same on screen size. I also have to use perspective camera.
I have found some related answers, but seems that I miss something:
First approach is to use Euclidean distance to objects from
camera and scale them respectively every animation frame.
Three JS Keep Label Size On Zoom
I have tried to modify jsfiddle given in the answer to apply scale to meshes instead of sprites, but that doesn't work for me. The result looks as follows https://jsfiddle.net/a2ogz9vx/258/
var camera, scene, renderer, controls;
var planets = [];
var timestamp = 0;
var scaleVector = new THREE.Vector3();
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 100, 100);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
var createPlanet = function(name, radius, orbit, speed) {
var geom = new THREE.SphereGeometry(radius, 32, 16);
var mat = new THREE.MeshBasicMaterial({
color: Math.random() * 0xFFFFFF,
});
var planet = new THREE.Mesh(geom, mat);
planet.userData.orbit = orbit;
planet.userData.speed = speed;
var canvas = document.createElement('canvas');
canvas.width = 256;
canvas.height = 256;
var tex = new THREE.Texture(canvas);
tex.needsUpdate = true;
var spriteMat = new THREE.SpriteMaterial({
map: tex
});
var sprite = new THREE.Sprite(spriteMat);
planet.add(sprite);
planets.push(planet);
scene.add(planet);
};
createPlanet("One", 11, -10, 5);
createPlanet("Two", 11, 5, 5);
createPlanet("Three", 11, 10, 5);
}
function animate() {
requestAnimationFrame(animate);
planets.forEach(function(planet) {
var scaleFactor = 100;
var scale = scaleVector.subVectors(planet.position, camera.position).length() / scaleFactor;
planet.scale.set(scale, scale, scale);
var orbit = planet.userData.orbit;
var speed = planet.userData.speed;
planet.position.x = speed * orbit;
planet.position.z = speed * orbit;
});
render();
}
function render() {
renderer.render(scene, camera);
}
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>
Second approach is to use on screen width calculation. https://stackoverflow.com/a/13351534/8465699
Result also doesn't look right https://jsfiddle.net/a2ogz9vx/260/
var camera, scene, renderer, controls;
var planets = [];
var timestamp = 0;
var scaleVector = new THREE.Vector3();
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 100, 100);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
var createPlanet = function(name, radius, orbit, speed) {
var geom = new THREE.SphereGeometry(radius, 32, 16);
var mat = new THREE.MeshBasicMaterial({
color: Math.random() * 0xFFFFFF,
});
var planet = new THREE.Mesh(geom, mat);
planet.userData.orbit = orbit;
planet.userData.speed = speed;
var canvas = document.createElement('canvas');
canvas.width = 256;
canvas.height = 256;
var tex = new THREE.Texture(canvas);
tex.needsUpdate = true;
var spriteMat = new THREE.SpriteMaterial({
map: tex
});
var sprite = new THREE.Sprite(spriteMat);
planet.add(sprite);
planets.push(planet);
scene.add(planet);
};
createPlanet("One", 11, -10, 5);
createPlanet("Two", 11, 0, 5);
createPlanet("Three", 11, 10, 5);
}
function animate() {
requestAnimationFrame(animate);
planets.forEach(function(planet) {
const dist = planet.position.distanceTo(camera.position);
const vFOV = THREE.Math.degToRad(camera.fov);
const size = 2 * Math.tan(vFOV / 2) * dist;
const scaleFactor = 130;
const scale = size / scaleFactor;
planet.scale.set(scale, scale, scale);
var orbit = planet.userData.orbit;
var speed = planet.userData.speed;
planet.position.x = speed * orbit;
planet.position.z = speed * orbit;
});
render();
}
function render() {
renderer.render(scene, camera);
}
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>
Any suggestions how to fix the code or other approaches are welcome!

Trouble Casting Shadows with THREE.JS

Okay. I'm clearly missing something here. I'm simply trying to get this code to cast shadows. I've turned on receive shadows and cast shadows for the cube and the floor but it still isn't showing. This shouldn't be this hard. I've used casting shadows before however I'm clearing missing something here. Any ideas would help. I'm at a loss because I know casting shadows isn't that hard. I must be missing something obvious.
Thanks in advance.
var camera, scene, renderer;
var RED = 0xff3300;
init();
render();
function init() {
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(window.innerWidth, window.innerHeight);
-
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 15000);
camera.position.set(1000, 500, 1000);
camera.lookAt(new THREE.Vector3(0, 200, 0));
scene = new THREE.Scene();
scene.background = new THREE.Color(0xcccccc);
var light = new THREE.SpotLight(0xdddddd, 1);
light.position.set(50, 600, 50);
scene.add(light);
var coloredCube = createCube(100, 100, 100, 0, 300, 0, 0, RED);
coloredCube.castShadow = true;
coloredCube.receiveShadow = true;
scene.add(coloredCube);
//create floor
var planeFloor = createSizedPlane(1000, 1000);
planeFloor = preparePlaneForScene(planeFloor, Math.PI / -2, 0, 0, 0, 0, 0);
planeFloor.castShadow = true;
planeFloor.receiveShadow = true;
scene.add(planeFloor);
}
function render() {
renderer.render(scene, camera);
}
function createSizedPlane(xSize, zSize, numberOfSegments) {
var planeGeometry = new THREE.PlaneGeometry(xSize, zSize, numberOfSegments);
planeGeometry.receiveShadow = true;
planeGeometry.castShadow = true;
var material = new THREE.MeshStandardMaterial({
roughness: 0.8,
color: 0xffffff,
metalness: 0.2,
bumpScale: 0.0005,
opacity: 1, transparent: false
}
);
return new THREE.Mesh(planeGeometry, material);
}
function preparePlaneForScene(plane, xRotation, yRotation, zRotation, xPosition, yPosition, zPosition) {
plane.rotation.x = xRotation;
plane.rotation.y = yRotation;
plane.rotation.z = zRotation;
plane.position.x = xPosition;
plane.position.y = yPosition;
plane.position.z = zPosition;
return plane;
}
function createCube(xSize, ySize, zSize, xPosition, yPosition, zPosition, yRotation, color) {
var cubeGeometry = new THREE.BoxGeometry(xSize, ySize, zSize);
var cubeMaterial = new THREE.MeshLambertMaterial({color: color});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.x = xPosition;
cube.position.y = yPosition;
cube.position.z = zPosition;
cube.rotation.y = yRotation;
cube.castShadow = true;
cube.receiveShadow = true;
return cube;
}
Enable shadowMap for renderer and casting shadow for light:
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
spotLight.castShadow = true;
spotLight.shadow = new THREE.LightShadow(new THREE.PerspectiveCamera(60, 1, 1, 2500));
spotLight.shadow.bias = 0.0001;
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
THREE.SpotLightShadow should work too.
For directional light you would need orthographic projection (or use THREE.DirectionalLightShadow).

Categories