How to linke objects and move them relatively in three js? - three.js

I created kind of mannequin with three.js.
I want to make it possible to:
link all objects with connection child-parent
move objects relatively (if hand moved, than elbow whould be moved, but if wrist moved, than other parts should not be moved)
I wrote code below and made jsfiddle example. Not sure whether it is correct way.
var scene, camera, renderer, pivot;
//main
init();
animate();
//init
function init() {
//scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0xf0f0f0);
//camera
camera = new THREE.PerspectiveCamera(140, window.innerWidth / window.innerHeight, 0.1, 10000);
//neck
var geometry = new THREE.BoxBufferGeometry(2, 3, 1);
var material = new THREE.MeshNormalMaterial({
transparent: true,
opacity: 0.5
});
var figure = new THREE.Mesh(geometry, material);
figure.position.set(0, 1.5, 0);
//body
var geometry2 = new THREE.BoxBufferGeometry(0.5, 0.5, 0.5);
/* geometry2.rotateZ(THREE.Math.degToRad(90)); // ROTATE GEOMETRY SO IT'S IN THE CORRECT ORIENTATION */
var figure2 = new THREE.Mesh(geometry2, material);
figure2.position.set(0, 1.5, 0); // MOVE THE GEOMOETRY UP BY HALF SO PIVOT IS AT THE BOTTOM OF THE GEO
/* figure2.rotation.set(0, 0, Math.PI / 2); */
figure.add(figure2);
//head
var geometry3 = new THREE.SphereGeometry(0.75, 32, 32);
var material3 = new THREE.MeshBasicMaterial({
color: 0xffff00
});
var sphere3 = new THREE.Mesh(geometry3, material3);
sphere3.position.set(0, 2.5, 0);
figure.add(sphere3)
//right shoulder
var geometry4 = new THREE.SphereGeometry(0.25, 32, 32);
var material4 = new THREE.MeshBasicMaterial({
color: 0xffff00
});
var sphere4 = new THREE.Mesh(geometry4, material4);
sphere4.position.set(1.25, 1.25, 0);
figure.add(sphere4)
//right hand top
var geometry5 = new THREE.BoxBufferGeometry(0.5, 1.5, 0.5);
var figure5 = new THREE.Mesh(geometry5, material);
figure5.position.set(1.25, 0.25, 0);
figure.add(figure5);
//right elbow
var geometry6 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere6 = new THREE.Mesh(geometry6, material3);
sphere6.position.set(1.25, -0.75, 0);
figure.add(sphere6)
//right hand bottom
var geometry7 = new THREE.BoxBufferGeometry(0.5, 1.5, 0.5);
var figure7 = new THREE.Mesh(geometry7, material);
figure7.position.set(1.25, -1.75, 0);
figure.add(figure7);
//right hand bottom sphere
var geometry8 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere8 = new THREE.Mesh(geometry8, material3);
sphere8.position.set(1.25, -2.75, 0);
figure.add(sphere8);
//right wrist
var geometry9 = new THREE.BoxBufferGeometry(0.5, 0.5, 0.5);
var figure9 = new THREE.Mesh(geometry9, material);
figure9.position.set(1.25, -3.25, 0);
figure.add(figure9);
//left shoulder
var geometry10 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere10 = new THREE.Mesh(geometry10, material4);
sphere10.position.set(-1.25, 1.25, 0);
figure.add(sphere10)
//left hand top
var geometry11 = new THREE.BoxBufferGeometry(0.5, 1.5, 0.5);
var figure11 = new THREE.Mesh(geometry11, material);
figure11.position.set(-1.25, 0.25, 0);
figure.add(figure11);
//left elbow
var geometry12 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere12 = new THREE.Mesh(geometry12, material3);
sphere12.position.set(-1.25, -0.75, 0);
figure.add(sphere12)
//left hand bottom
var geometry13 = new THREE.BoxBufferGeometry(0.5, 1.5, 0.5);
var figure13 = new THREE.Mesh(geometry13, material);
figure13.position.set(-1.25, -1.75, 0);
figure.add(figure13);
//left hand bottom sphere
var geometry14 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere14 = new THREE.Mesh(geometry14, material3);
sphere14.position.set(-1.25, -2.75, 0);
figure.add(sphere14);
//left wrist
var geometry15 = new THREE.BoxBufferGeometry(0.5, 0.5, 0.5);
var figure15 = new THREE.Mesh(geometry15, material);
figure15.position.set(-1.25, -3.25, 0);
figure.add(figure15);
//left hip
var geometry16 = new THREE.SphereGeometry(0.5, 32, 32);
var sphere16 = new THREE.Mesh(geometry16, material3);
sphere16.position.set(-0.5, -2.25, 0);
figure.add(sphere16);
//left haunch
var geometry17 = new THREE.BoxBufferGeometry(1, 1.75, 1);
var figure17 = new THREE.Mesh(geometry17, material);
figure17.position.set(-0.5, -3.65, 0);
figure.add(figure17);
//left knee
var geometry18 = new THREE.SphereGeometry(0.5, 32, 32);
var sphere18 = new THREE.Mesh(geometry18, material3);
sphere18.position.set(-0.5, -5, 0);
figure.add(sphere18);
//left shin
var geometry19 = new THREE.BoxBufferGeometry(1, 1.75, 1);
var figure19 = new THREE.Mesh(geometry19, material);
figure19.position.set(-0.5, -6.35, 0);
figure.add(figure19);
//left ankle
var geometry20 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere20 = new THREE.Mesh(geometry20, material3);
sphere20.position.set(-0.5, -7.5, 0);
figure.add(sphere20);
//left foot
var geometry21 = new THREE.BoxBufferGeometry(1, 0.25, 1.5);
var figure21 = new THREE.Mesh(geometry21, material);
figure21.position.set(-0.5, -7.85, 0.25);
figure.add(figure21);
//right hip
var geometry22 = new THREE.SphereGeometry(0.5, 32, 32);
var sphere22 = new THREE.Mesh(geometry22, material3);
sphere22.position.set(0.5, -2.25, 0);
figure.add(sphere22);
//right haunch
var geometry23 = new THREE.BoxBufferGeometry(1, 1.75, 1);
var figure23 = new THREE.Mesh(geometry23, material);
figure23.position.set(0.5, -3.65, 0);
figure.add(figure23);
//right knee
var geometry24 = new THREE.SphereGeometry(0.5, 32, 32);
var sphere24 = new THREE.Mesh(geometry24, material3);
sphere24.position.set(0.5, -5, 0);
figure.add(sphere24);
//right shin
var geometry25 = new THREE.BoxBufferGeometry(1, 1.75, 1);
var figure25 = new THREE.Mesh(geometry25, material);
figure25.position.set(0.5, -6.35, 0);
figure.add(figure25);
//right ankle
var geometry26 = new THREE.SphereGeometry(0.25, 32, 32);
var sphere26 = new THREE.Mesh(geometry26, material3);
sphere26.position.set(0.5, -7.5, 0);
figure.add(sphere26);
//right foot
var geometry27 = new THREE.BoxBufferGeometry(1, 0.25, 1.5);
var figure27 = new THREE.Mesh(geometry27, material);
figure27.position.set(0.5, -7.85, 0.25);
figure.add(figure27);
//add figure
scene.add(figure);
scene.add(new THREE.AxesHelper());
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
//add grid
/* scene.add(new THREE.GridHelper(10, 20)) */
camera.position.z = 5;
//top view on object
/* camera.position.set(0, 10, 0);
camera.up.set(0, 0, -1);
camera.lookAt(0, 0, 0); */
//controls to rotate camera
controls2 = new THREE.OrbitControls(camera, renderer.domElement);
controls2.minPolarAngle = Math.PI/2;
controls2.maxPolarAngle = Math.PI/2;
//controls to drag object in 3d
/* var cubePoints = [];
cubePoints.push(figure2);
var controls = new THREE.DragControls(cubePoints, camera, renderer.domElement); */
}
//animate
function animate() {
requestAnimationFrame(animate);
render();
};
//render
function render() {
renderer.render(scene, camera);
};

To link meshes in Three.js I usually use groups (see https://threejs.org/docs/#api/en/objects/Group), I also use them to change the pivot point of a mesh by placing the mesh in a group with the wanted pivot point in the center coordinates of the group.
Of course you can nest groups for your case, like a group with the hand mesh which can be inside another group with the forearm mesh and so on.
In order to move the elbow position according to the hand position (if I get what you say right), you should use Inverse Kinematics, there are implementations for Three.js like https://github.com/jsantell/THREE.IK but I never used it so I can't tell you more about it.
Hope you solve your problem.

Related

Rotate the camera around an object using the Buttons in ThreeJS?

I have STL model loaded in my scene.
I want to show Left, Right, Top, Bottom and Front, Back side of my model by rotating camera.
I want exactly like Reference this. Free movement of camera and set different views. another reference ThreeJS Reference Example but this code is not Open Source.
var camera, scene, renderer;
var geometry, material, mesh;
let controls;
init();
animate();
function init() {
let aspectRatio = window.innerWidth / window.innerHeight;
let frustumSize = 2;
camera = new THREE.OrthographicCamera(frustumSize * aspectRatio / -2,
frustumSize * aspectRatio / 2,
frustumSize / 2, frustumSize / -2,
-50,
50);
camera.position.z = 1;
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xD3D3D3);
document.body.appendChild(renderer.domElement);
let frontlight = new THREE.DirectionalLight(0x808080, .3);
scene.add(frontlight);
ambientLight = new THREE.AmbientLight(0xffffff, 0.7);
scene.add(ambientLight);
createControls();
loadSTL();
}
function createControls() {
controls = new THREE.TrackballControls(camera, renderer.domElement);
}
window.addEventListener('keydown', function(event) {
switch (event.keyCode) {
case 49: //Top View
// setView(new THREE.Vector3(0, 0, 1));
setView(new THREE.Vector3(0, 0, 1), new THREE.Vector3(0, 0, 0));
break;
case 50: //Bottom View
setView(new THREE.Vector3(0, 0, -1), new THREE.Vector3(Math.PI, 0, 0));
break;
case 51: //Left View
setView(new THREE.Vector3(-1, 0, 0), new THREE.Vector3(Math.PI / 2, (-Math.PI / 2), 0));
break;
case 52: //Right View
setView(new THREE.Vector3(1, 0, 0), new THREE.Vector3(Math.PI / 2, Math.PI / 2, 0));
break;
case 53: //Front View
setView(new THREE.Vector3(0, 1, 0), new THREE.Vector3(-(Math.PI / 2), 0, Math.PI));
break;
case 54: //Back View
setView(new THREE.Vector3(0, -1, 0), new THREE.Vector3(Math.PI / 2, 0, 0));
break;
}
});
function setView(offSetFactor, axisAngle) {
const offsetUnit = camera.position.length();
const offSet = new THREE.Vector3(offsetUnit * offSetFactor.x,
offsetUnit * offSetFactor.y,
offsetUnit * offSetFactor.z);
const center = new THREE.Vector3();
const finishPos = center.add(offSet);
const euler = new THREE.Euler(axisAngle.x, axisAngle.y, axisAngle.z);
const finishQuaterion = new THREE.Quaternion().copy(camera.quaternion).setFromEuler(euler);
/* let boundingBox = new THREE.Box3().setFromObject(scene);
let boxCenter = new THREE.Vector3();
boundingBox.getCenter(boxCenter); */
const duration = 400;
const start = performance.now();
const maxAlpha = 1;
function loop() {
const now = performance.now();
const delta = now - start;
const alpha = Math.min(delta / duration, maxAlpha);
camera.position.lerp(finishPos, alpha);
controls.update();
camera.quaternion.slerp(finishQuaterion, alpha);
camera.up.set(0, 1, 0);
controls.update();
if (alpha !== maxAlpha)
return requestAnimationFrame(loop)
/* camera.lookAt(boxCenter);
controls.target.set(boxCenter.x,boxCenter.y,boxCenter.z);
*/
}
loop();
}
function loadSTL() {
let material = new THREE.MeshPhongMaterial({
color: 0xffdead,
side: THREE.DoubleSide,
});
var stlLoader = new THREE.STLLoader();
stlLoader.load('https://cdn.glitch.global/3c40c6ea-d629-4a1b-8129-bd041944a124/monkey.stl?v=1659713089046',
function(geometry) {
var material = new THREE.MeshPhongMaterial({
color: 0xff5533
});
var meshSTL = new THREE.Mesh(geometry, material);
scene.add(meshSTL);
fitToScreen(scene, camera, controls);
});
}
function fitToScreen(group, camera, controls) {
let boundingBox = new THREE.Box3().setFromObject(group);
let distance = boundingBox.min.distanceTo(boundingBox.max) * 0.1;
let boxCenter = new THREE.Vector3();
boundingBox.getCenter(boxCenter);
camera.position.set(boxCenter.x, boxCenter.y, distance);
camera.lookAt(boxCenter);
controls.target.set(boxCenter.x, boxCenter.y, boxCenter.z);
camera.updateProjectionMatrix();
}
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
Here is JSFiddle link what I implemented so far use 1 to 6 keys to change Views. In am not able to set left, right and front view properly.
I am using Trackball controls and orthographic camera this is my need I cannot change camera and controls. There is one library Gizmo Library but this library work specifically for orbit controls
I want to rotate camera by clicking on button. I know once I know how to rotate camera properly I can hook up UI with this but just FYI. I will keep Six buttons to set this views.
Here is what I tried So far

How to animate a threeJS object using GSAP?

I have been learning threeJS just recently and can't get passed a problem. I tried to animate a extruded triangle using the GSAP library. It is just a simple animation to have the triangle move to the right but it seems I did something wrong. Any help is much appreciated.
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Create Triangles
var material = new THREE.MeshPhongMaterial({
color: 0xf6c12a,
shininess: 70
});
var shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.lineTo(2, 3);
shape.lineTo(4, 0);
shape.lineTo(0, 0);
var extrudeSettings = {
steps: 5,
depth: 1,
bevelEnabled: true,
bevelThickness: 0.3,
bevelSize: 0.5,
bevelOffset: 0,
bevelSegments: 1
};
var geometry = new THREE.ExtrudeBufferGeometry(shape, extrudeSettings);
// Sets the origin to the center of geometry for rotation
geometry.center();
var mesh = new THREE.Mesh(geometry, material);
mesh.position.x = 0;
mesh.position.y = 0;
mesh.position.z = -5;
mesh.scale.set(1.5, 1.5, 1.5);
scene.add(mesh);
gsap.to(mesh, { duration: 2, x: 300 });
camera.position.z = 5;
// Background
var geometry = new THREE.PlaneGeometry(1000, 1000, 1);
var material = new THREE.MeshPhysicalMaterial({ color: 0x444444 });
var plane = new THREE.Mesh(geometry, material);
plane.position.z = -50;
scene.add(plane);
// Lighting
var ambientLight = new THREE.AmbientLight(0xffffff, 0.55);
scene.add(ambientLight);
var pointLight1 = new THREE.PointLight(0xf9eac8, 1, 100);
pointLight1.position.set(5, 10, 0);
pointLight1.castShadow = true;
pointLight1.shadow.camera.top = 20;
scene.add(pointLight1);
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
render();
Here is the link to Codepen
Tried to put the gsap code into different position but maybe that's not the problem.
gsap.to(mesh.position, { duration: 2, x: 300 });
the value that you want to change is mesh.position.x not mesh.x
just add .position it will work

I need to use the data from first picture to draw cylinder,put two cylinders point B is not coincide(like second picture)

**I need to use the data from first picture to draw cylinder,put two cylinders point B is not coincide(like second picture) **
var geometry = new THREE.CylinderGeometry(10, 10,151.02648774304458, 20, 1, false);
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(1,75.5,1);
scene.add(mesh);
var material1 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var geometry1 = new THREE.CylinderGeometry(10, 10,158.8741640418605, 20, 1, false);
var mesh1 = new THREE.Mesh(geometry1, material1);
mesh1.position.set(-30,217,32.5);
mesh1.rotation.set(2,151,2);
scene.add(mesh1);
You have to add the red cylinder to a Group. Set the position in that way, that the bottom of the cylinder is at (0, 0, 0). Set the position of the group in that way, that it's origin is at the top of the black cylinder.
Finally you have to rotate the group:
let height = 151.02648774304458;
let height1 = 158.8741640418605;
var geometry = new THREE.CylinderGeometry(10, 10, height, 20, 1, false);
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(1, 75.5, 1);
scene.add(mesh);
var material1 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var geometry1 = new THREE.CylinderGeometry(10, 10, height1, 20, 1, false);
var mesh1 = new THREE.Mesh(geometry1, material1);
mesh1.position.set(0, height1/2, 0);
group = new THREE.Group();
group.position.set(mesh.position.x, mesh.position.y + height/2, mesh.position.z);
group.add(mesh1);
group.rotation.set(...);
scene.add(group);
(function onLoad() {
var container, camera, scene, renderer, orbitControls;
init();
animate();
function init() {
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({
canvas: my_canvas,
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, 10000);
camera.position.set(0, 200, -400);
camera.lookAt( 0, 0, 0 );
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);
createModel();
}
var group;
function createModel() {
var material = new THREE.MeshPhongMaterial({color:'#ff0000'});
var material1 = new THREE.MeshPhongMaterial({color:'#000000'});
let height = 151.02648774304458;
let height1 = 158.8741640418605;
var geometry = new THREE.CylinderGeometry(10, 10, height, 20, 1, false);
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(1, 75.5, 1);
scene.add(mesh);
var material1 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var geometry1 = new THREE.CylinderGeometry(10, 10, height1, 20, 1, false);
var mesh1 = new THREE.Mesh(geometry1, material1);
mesh1.position.set(0, height1/2, 0);
group = new THREE.Group();
group.position.set(mesh.position.x, mesh.position.y + height/2, mesh.position.z);
group.add(mesh1);
//group.rotation.set(2, 151, 2);
scene.add(group);
}
var rotate = 0.0;
function animate() {
group.rotation.set(0, 0, rotate);
rotate += 0.01;
requestAnimationFrame(animate);
orbitControls.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"><canvas id="my_canvas"> </canvas></div>
To set a specific rotation by a specific vector, I recommend to set the rotation by a .setRotationFromQuaternion.
The Quaternion defines how to rotate from the upwards direction (0, 1, 0) to the target direction. The Target direction is the vector form the joint to the endpoint of the upper cylinder (-62-1, 283-151, 61-1):
For instance:
let upVector = new THREE.Vector3(0, 1, 0);
let targetVector = new THREE.Vector3(-62 - 1, 283 - height, 61 - 1);
let quaternion = new THREE.Quaternion().setFromUnitVectors(
upVector, targetVector.normalize());
group.setRotationFromQuaternion(quaternion)

Custom plane does not cast/ receive shadows in THREE js

I am trying to create a box (a wall) using six planes. I have created planes but shadows are not there.
This is how I create custom planes.
function createWall(vertices) {
var geometry = new THREE.Geometry(), i;
for (i = 0; i < vertices.length; i = i + 1) {
geometry.vertices.push(vertices[i]);
}
geometry.faces.push(new THREE.Face3(0, 1, 2));
geometry.faces.push(new THREE.Face3(0, 2, 3));
geometry.computeVertexNormals();
geometry.computeFaceNormals();
var material = new THREE.MeshStandardMaterial({
emissive: 0x708090,
emissiveIntensity: 1,
side: THREE.DoubleSide,
color: 0xD3D3D3
});
var mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
return mesh;
}
Here is the complete code.
var camera, scene, renderer;
function addFloor() {
var material = new THREE.MeshStandardMaterial({
roughness: 0.8,
color: 0x696969,
metalness: 0.2,
bumpScale: 0.0005
});
var geometry = new THREE.PlaneBufferGeometry(2000, 2000);
var mesh = new THREE.Mesh(geometry, material);
mesh.receiveShadow = true;
mesh.rotation.x = -Math.PI / 2.0;
scene.add(mesh);
}
function createWall(vertices) {
var geometry = new THREE.Geometry(), i;
for (i = 0; i < vertices.length; i = i + 1) {
geometry.vertices.push(vertices[i]);
}
geometry.faces.push(new THREE.Face3(0, 1, 2));
geometry.faces.push(new THREE.Face3(0, 2, 3));
geometry.computeVertexNormals();
geometry.computeFaceNormals();
var material = new THREE.MeshStandardMaterial({
emissive: 0x708090,
emissiveIntensity: 1,
side: THREE.DoubleSide,
color: 0xD3D3D3
});
var mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
return mesh;
}
function addBulb(location) {
var geometry = new THREE.SphereGeometry(2, 20, 20);
var light = new THREE.PointLight(0xffffff, 1, 100, 2);
var material = new THREE.MeshStandardMaterial({
emissive: 0xffffee,
emissiveIntensity: 1,
color: 0x000000
});
light.add(new THREE.Mesh(geometry, material));
light.position.set(location.x, location.y, location.z);
light.shadow.camera.near = 0.0001;
light.castShadow = true;
//light.shadow.darkness = 0.5;
//light.shadow.camera.vsible = true;
return light;
}
function addWalls() {
var wall1 = createWall([
new THREE.Vector3(0, 0, 0), //vertex0
new THREE.Vector3(200, 0, 0), //1
new THREE.Vector3(200, 100, 0), //2
new THREE.Vector3(0, 100, 0) //3
]);
var wall2 = createWall([
new THREE.Vector3(0, 0, 5), //vertex0
new THREE.Vector3(200, 0, 5), //1
new THREE.Vector3(200, 100, 5), //2
new THREE.Vector3(0, 100, 5) //3
]);
scene.add(wall1);
scene.add(wall2);
}
function addCamera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(50, 100, 300);
scene.add(camera);
}
function init() {
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.shadowMap.renderSingleSided = false;
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);
addCamera();
addFloor();
addWalls();
scene.add(addBulb({x: 100, y: 50, z: 25}));
var ambientLight = new THREE.AmbientLight(0x999999, 0.6);
scene.add(ambientLight);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
}
function animate() {
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
init();
animate();
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
I may have done something wrong while creating custom plane. I do not understand what is wrong here.
UPDATED:
renderer.shadowMap.renderSingleSided = false;
It seems shadows are working but lighting has strange square effect.
Here I have tried BoxGeometry which has little depth as suggested in three-js-plane-doesnt-cast-shadow ,
As I noted this occurs only for small values for depth. (depth < 1)
var camera, scene, renderer;
function addFloor() {
var material = new THREE.MeshStandardMaterial({
roughness: 0.9,
color: 0xffffff,
metalness: 0.1,
bumpScale: 0.0005
});
var geometry = new THREE.PlaneBufferGeometry(2000, 2000);
var mesh = new THREE.Mesh(geometry, material);
mesh.receiveShadow = true;
mesh.rotation.x = -Math.PI / 2.0;
scene.add(mesh);
}
function createWall(location) {
var geometry = new THREE.BoxGeometry(200, 100, 0.1);
geometry.translate((location.x1 + location.x2) / 2, 150 / 2, location.z);
var material = new THREE.MeshStandardMaterial({
emissive: 0x708090,
emissiveIntensity: 1,
side: THREE.DoubleSide,
color: 0xD3D3D3,
roughness: 0.9,
metalness: 0.1
});
var mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
return mesh;
}
function addBulb(options) {
var geometry = new THREE.SphereGeometry(2, 20, 20);
var light = new THREE.PointLight(options.color, 1, 500, 2);
var material = new THREE.MeshStandardMaterial({
emissive: options.color,
emissiveIntensity: 1,
color: options.color
});
light.add(new THREE.Mesh(geometry, material));
light.position.set(options.x, options.y, options.z);
light.shadow.camera.near = 0.0001;
light.castShadow = true;
light.shadow.darkness = 0.5;
light.shadow.camera.vsible = true;
return light;
}
function addWalls() {
var wall1 = createWall({ x1: 0, x2: 200, z: 0});
var wall2 = createWall({ x1: 0, x2: 200, z: 5});
scene.add(wall1);
//scene.add(wall2);
}
function addCamera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(100, 100, 300);
scene.add(camera);
}
function init() {
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.shadowMap.renderSingleSided = false;
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);
addCamera();
addFloor();
addWalls();
scene.add(addBulb({x: 0, y: 100, z: 25, color: 0xff0000 }));
scene.add(addBulb({x: 100, y: 100, z: 25, color: 0x00ff00 }));
scene.add(addBulb({x: 200, y: 100, z: 25, color: 0x0000ff }));
var ambientLight = new THREE.AmbientLight(0x999999, 0.6);
scene.add(ambientLight);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
}
function animate() {
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
init();
animate();
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
You're facing Z fighting. Since the thickness of the wall is so small, the 2 faces are nearly touching each other, so they cast shadows on each other.
You can either remove the casting/receiving of shadows on the wall or, better, increase the z value in the geometry, like so:
var geometry = new THREE.BoxGeometry(200, 100, 1);
Also, since you changed to a box from a plane, the line side: THREE.DoubleSide, in the wall material is no longer needed. In fact, it's part of the self-shadowing problem. Changing those two lines should solve your problem.
Here's a working Fiddle.

Smooth Ring 3D in three.js

I want to draw a ring with the help of ExtrudeGeometry.
Ring3D = function(innerRadius, outerRadius, heigth, Segments) {
var extrudeSettings = {
amount: heigth,
bevelEnabled: false,
curveSegments: Segments
};
var arcShape = new THREE.Shape();
arcShape.moveTo(outerRadius, 0);
arcShape.absarc(0, 0, outerRadius, 0, Math.PI * 2, false);
var holePath = new THREE.Path();
holePath.moveTo(innerRadius, 0);
holePath.absarc(0, 0, innerRadius, 0, Math.PI * 2, true);
arcShape.holes.push(holePath);
var geometry = new THREE.ExtrudeGeometry(arcShape, extrudeSettings);
var material = new THREE.MeshPhongMaterial({
color: 0x00ffff
});
var mesh = new THREE.Mesh(geometry, material);
mesh.rotation.x = Math.PI / 2;
mesh.position.y = heigth / 2;
var object = new THREE.Object3D;
object.add(mesh);
return object;
}
The resulting figure has visible scars. And the cylinder and torus such scars not. How to get rid of them? Example here.
with geometry.computeVertexNormals();
var shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.lineTo(0, 10);
shape.quadraticCurveTo(35, 30, 0, 50);
shape.lineTo(0, 60);
shape.quadraticCurveTo(48, 30, 0, 0);
var extrudeSettings = {
amount : 20,
steps : 10,
bevelEnabled: false,
curveSegments: 8
};
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( { color: '0x804000' ,transparent: true,opacity: 0.2} ) );
scene.add( mesh );
You need to .computeVertexNormals() from your geometry. But it seems there is some issue (with a solution) explained here: https://github.com/mrdoob/three.js/issues/323. I am not sure if it will work in your case.
I have found a comment in the code of ExtrudeGeometry:
this.computeFaceNormals();
// can't really use automatic vertex normals
// as then front and back sides get smoothed too
// should do separate smoothing just for sides
//this.computeVertexNormals();
So it seems it is not supported now :(

Resources