How to update MeshLine line coordinates? - three.js

When I try to update mesh line points(replace it with new) I got some weird geometry - like thin line
https://jsfiddle.net/benderlio/cL2810or/30/
var line2d = new THREE.Line3(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(100, 100, 0)
)
var center = line2d.getCenter();
var curve = new THREE.QuadraticBezierCurve3(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(center.x, center.y, 0.5),
new THREE.Vector3(100, 200, 0)
);
var points = curve.getPoints(50);
var geometry = new THREE.Geometry().setFromPoints(points);
var newMeshLine = new MeshLine();
newMeshLine.setGeometry(geometry);
console.log('!!!',meshLine.geometry.attributes.position.array, newMeshLine.geometry.attributes.position.array);
meshLine.geometry.attributes.position.array = newMeshLine.geometry.attributes.position.array
meshLine.geometry.attributes.position.needsUpdate = true
If you click update button and turn the line you will see that it is weird.
The problem is in update function, but not sure where exactly
Thanks

MeshLine has several attributes that you'd need to modify in order to successfully update to a new geometry, it's not just position. It would be much simpler if you just use the .setGeometry() method again on the same object, and let it take care of updating its geometry, instead of doing it manually:
var points = curve.getPoints(50);
var geometry = new THREE.Geometry().setFromPoints(points);
meshLine.setGeometry(geometry);
See the new simplified updateGeometry function below, I also had to make the meshLine variable global on line 3 to get access to it across functions.
var scene, renderer, camera;
var controls;
var meshLine;
init();
animate();
document.querySelector("#update").addEventListener("click",()=>{
updateGeometry()
})
function makeLine (meshLine, colorName, width) {
let material = new MeshLineMaterial({
useMap: false,
color: new THREE.Color(colorName),
opacity: 1,
resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),
sizeAttenuation: false,
lineWidth: width,
near: camera.near,
far: camera.far
});
let mesh = new THREE.Mesh (meshLine.geometry, material)
return mesh;
}
function MyAxesHelper(size = 10, width = 5) {
let axes = new THREE.Object3D();
let geometry;
meshLine = new MeshLine();
geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3());
geometry.vertices.push(new THREE.Vector3(size, 0, 0));
meshLine.setGeometry(geometry);
axes.add (makeLine (meshLine, 'red', width))
meshLine = new MeshLine();
geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3());
geometry.vertices.push(new THREE.Vector3(0, size, 0));
meshLine.setGeometry(geometry);
axes.add (makeLine (meshLine, 'green', width))
meshLine = new MeshLine();
geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3());
geometry.vertices.push(new THREE.Vector3(0,0,size));
meshLine.setGeometry(geometry);
axes.add (makeLine (meshLine, 'blue', width))
return axes;
}
function updateGeometry() {
var line2d = new THREE.Line3(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(100, 100, 0)
)
var center = line2d.getCenter();
var curve = new THREE.QuadraticBezierCurve3(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(center.x, center.y, 0.5),
new THREE.Vector3(100, 200, 0)
);
var points = curve.getPoints(50);
var geometry = new THREE.Geometry().setFromPoints(points);
meshLine.setGeometry(geometry);
}
function init() {
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x888888);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 500;
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.autoRotate = false;
controls.autoRotateSpeed = .1;
controls.enablePan = false;
var gridXZ = new THREE.GridHelper(200, 20, 'red', 'white');
scene.add(gridXZ);
window.addEventListener('resize', onWindowResize, false);
/////////////////////////////////////////
//scene.add(MyAxesHelper(50, 35.3));
// make a circle
meshLine = new MeshLine();
var line2d = new THREE.Line3(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(100, 100, 0)
)
var center = line2d.getCenter();
var curve = new THREE.QuadraticBezierCurve3(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(center.x, center.y, 0.5),
new THREE.Vector3(100, 100, 0)
);
var points = curve.getPoints(50);
geometry = new THREE.Geometry().setFromPoints(points);
meshLine.setGeometry(geometry);
let material = new MeshLineMaterial({
color: new THREE.Color('white'),
transparent:true,
opacity: 1,
repeat: new THREE.Vector2(16,1),
resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),
sizeAttenuation: false,
lineWidth: 40,
near: camera.near,
far: camera.far
});
let mesh = new THREE.Mesh (meshLine.geometry, material)
scene.add (mesh)
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
controls.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
#info {
position: absolute;
top: 2%;
width: 100%;
padding: 10px;
text-align: center;
color: #ffff00
}
#update{
position:absolute;
top:20px;
left:20px;
z-index:1000;
}
body {
margin: 0;
overflow: hidden;
}
<div id="info">MeshLine (AxesHelper)
</div>
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://rawgit.com/spite/THREE.MeshLine/master/src/THREE.MeshLine.js"></script>
<button id="update">Update</button>

Related

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)

How to draw Shape geometry with 3d points(x,y,z) using threejs which is not flat shape(surface)

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 10, 300);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.TrackballControls(camera, renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(100);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
var closedSpline = new THREE.CatmullRomCurve3([
new THREE.Vector3(-60, -100, -10),
new THREE.Vector3(-60, 20, 0),
new THREE.Vector3(-60, 120, -20),
new THREE.Vector3(60, 120, 0),
new THREE.Vector3(60, -100, 10)
]);
closedSpline.curveType = 'catmullrom';
closedSpline.closed = true;
var closedSpline1 = new THREE.CatmullRomCurve3([
new THREE.Vector3(-50, -90, -10),
new THREE.Vector3(-50, 10, 0),
new THREE.Vector3(-50, 110, -20),
new THREE.Vector3(50, 110, 0),
new THREE.Vector3(50, -90, 10)
]);
closedSpline1.curveType = 'catmullrom';
closedSpline1.closed = true;
var tubeGeometry = new THREE.TubeBufferGeometry(closedSpline, 100, 1, 5, true);
var material = new THREE.MeshLambertMaterial({
color: 0xb00000,
wireframe: false
});
var mesh = new THREE.Mesh(tubeGeometry, material);
scene.add(mesh);
var tubeGeometry1 = new THREE.TubeBufferGeometry(closedSpline1, 100, 1, 5,true);
var material1 = new THREE.MeshLambertMaterial({
color: 0xb00000,
wireframe: false
});
var mesh1 = new THREE.Mesh(tubeGeometry1, material1);
scene.add(mesh1);
// magic starts here
var shape = new THREE.Shape(closedSpline1.getPoints(100)); // make a shape
shape.holes.push(new THREE.Path(closedSpline1.getPoints(100))); // add a hole
var shapeGeometry = new THREE.ShapeGeometry(shape); // create a geometry
var track = new THREE.Mesh(shapeGeometry, new THREE.MeshLambertMaterial({
color: "yellow",
side:THREE.DoubleSide,
})); // create a track from the geometry
scene.add(track);
render();
function render() {
requestAnimationFrame(render);
controls.update();
renderer.render(scene, camera);
}
Above is my code which draw two tube geometry using THREE.CatmullRomCurve3 points and surface between those two tubes. Issue i am facing is surface between those two tubes(Track in above code) is always flat(2d) instead of 3d. I think THREE.Shape() are not using z axis values to draw surface. Can anybody guide me to right direction or some related samples. Thanks
You can do the trick, using concatenated sets of points from curves and THREE.PlaneGeometry():
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 10, 300);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(100);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
var closedSpline = new THREE.CatmullRomCurve3([
new THREE.Vector3(-60, -100, -10),
new THREE.Vector3(-60, 20, 0),
new THREE.Vector3(-60, 120, -20),
new THREE.Vector3(60, 120, 0),
new THREE.Vector3(60, -100, 10)
]);
closedSpline.curveType = 'catmullrom';
closedSpline.closed = true;
var closedSpline1 = new THREE.CatmullRomCurve3([
new THREE.Vector3(-50, -90, -10),
new THREE.Vector3(-50, 10, 0),
new THREE.Vector3(-50, 110, -20),
new THREE.Vector3(50, 110, 0),
new THREE.Vector3(50, -90, 10)
]);
closedSpline1.curveType = 'catmullrom';
closedSpline1.closed = true;
var tubeGeometry = new THREE.TubeBufferGeometry(closedSpline, 100, 1, 5, true);
var material = new THREE.MeshLambertMaterial({
color: 0xb00000,
wireframe: false
});
var mesh = new THREE.Mesh(tubeGeometry, material);
scene.add(mesh);
var tubeGeometry1 = new THREE.TubeBufferGeometry(closedSpline1, 100, 1, 5,
true);
var material1 = new THREE.MeshLambertMaterial({
color: 0xb00000,
wireframe: false
});
var mesh1 = new THREE.Mesh(tubeGeometry1, material1);
scene.add(mesh1);
// magic starts here
var points1 = closedSpline.getPoints(100); // get the first set of points
var points2 = closedSpline1.getPoints(100); // get the second set of points
var allPoints = points1.concat(points2); // concatenate them
var planeGeom = new THREE.PlaneGeometry(1, 1, 100, 1); // create a plane geometry
planeGeom.vertices = allPoints; // replace its vertices with the previously concatenated array of points
planeGeom.computeFaceNormals();
planeGeom.computeVertexNormals();
var track = new THREE.Mesh(planeGeom, new THREE.MeshLambertMaterial({
color: "yellow",
wireframe: false
}));
scene.add(track);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Verifying if a point is inside a cube in three.js

I have created a cube as:
var cubeGeometry = new THREE.BoxGeometry( 1, 1, 1 );
var cubeMaterial = new THREE.MeshLambertMaterial( { color:
0xffff00,wireframe: true } );
var cube = new THREE.Mesh( cubeGeometry, cubeMaterial );
cube.position.x = p.x;
cube.position.y = p.y;
cube.position.z = p.z;
scene.add(cube);
p is a input point to my function. So this code creates a cube at position p and adds it to the scene.
How can I check that some point,say A, lies inside this cube? I couldn't find any helper function like containsPoint etc for Three.Mesh. I may do some additional checks to verify, but I am looking for a Three.js function.
You can create THREE.Box3() instance, using its .setFromObject() the cube as the parameter, then call .containsPoint(), passing the point you want to check as the parameter to this method:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(2, 5, 10);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
scene.add(new THREE.GridHelper(10, 10));
var cube = new THREE.Mesh(new THREE.BoxGeometry(2, 2, 2), new THREE.MeshBasicMaterial({
color: "aqua",
wireframe: true
}));
cube.position.set(0, 1, 0);
scene.add(cube);
var pointA = new THREE.Vector3(0, 1, 0);
var pointB = new THREE.Vector3(2, 1, 0);
point(pointA, 0x00ff00);
point(pointB, "yellow");
function point(point, color) {
p = new THREE.Mesh(new THREE.SphereGeometry(0.25, 4, 2), new THREE.MeshBasicMaterial({
color: color
}));
p.position.copy(point);
scene.add(p);
}
var bb = new THREE.Box3(); // for re-use
bb.setFromObject(cube);
console.log(bb);
console.log(bb.containsPoint(pointA), bb.containsPoint(pointB));
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
cube.updateMatrixWorld(); //Make sure the object matrix is current with the position/rotation/scaling of the object...
var localPt = cube.worldToLocal(yourPoint.clone()); //Transform the point from world space into the objects space
if(Math.abs(localPt.x)<=0.5&&Math.abs(localPt.y)<=0.5&&Math.abs(localPt.z)<=0.5)
console.log("Point is inside!"); //Check if all the axis are within the size of the cube.. if your cube sizes arent 1,1,1, you'll have to adjust these checks to be half of width/height/depth..
Something like that?
#prisoner849
Your solution doesn't work if the box is rotated.
Here's an illustration of the problem. I render both solutions and you can see where the Box3 version breaks with the rotated cube, whereas the analytical once works.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(2, 5, 10);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
scene.add(new THREE.GridHelper(10, 10));
var boxDimensions = new THREE.Vector3(2,2,2);
var cube = new THREE.Mesh(new THREE.BoxGeometry(boxDimensions.x,boxDimensions.y,boxDimensions.z), new THREE.MeshBasicMaterial({
color: "aqua",
wireframe: true
}));
cube.position.set(0, 1, 0);
cube.rotation.y = Math.PI*0.25;
scene.add(cube);
var pointA = new THREE.Vector3(0.95, 0.95, 0.95);
var pointC = new THREE.Vector3(-0.65, 0.65, -0.65);
var pa = point(pointA, 0x00ff00);
var pc = point(pointC, 0x00ff00);
function point(point, color) {
p = new THREE.Mesh(new THREE.SphereGeometry(0.25, 4, 2), new THREE.MeshBasicMaterial({
color: color
}));
p.position.copy(point);
scene.add(p);
return p;
}
var bb = new THREE.Box3(); // for re-use
bb.setFromObject(cube);
console.log(bb);
function correctPointInBox(pt,cube,boxDim){
cube.updateMatrixWorld(); //Make sure the object matrix is current with the position/rotation/scaling of the object...
var localPt = cube.worldToLocal(pt.clone()); //Transform the point from world space into the objects space
if(Math.abs(localPt.x)<=boxDim.x*0.5&&Math.abs(localPt.y)<=boxDim.y*0.5&&Math.abs(localPt.z)<=boxDim.z*0.5)
return true;
else
return false;
}
render();
function render() {
pa.position.x = Math.sin(performance.now()*0.001)*2;
pc.position.z = Math.cos(performance.now()*0.001)*2;
if(bb.containsPoint(pa.position))
pa.material.color.set("red")
else
pa.material.color.set("green")
if(correctPointInBox(pc.position,cube,boxDimensions))
pc.material.color.set("red")
else
pc.material.color.set("green")
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Three js - moving rotation axis

Using threejs I created a simple cylinder object and rotating it in z-axis. The object rotates around the center axis, both the ends of the cylinder rotate around the axis which is at the center of the cylinder.
How can I make it rotate in a different axis? I would like the cylinder to rotate by having one end in a fixed point while the other end goes around in circles. My code is below.
init();
function init() {
renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('myCanvas'), antialias: true });
renderer.setClearColor(0xeaebed);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
camera = new THREE.PerspectiveCamera(5, window.innerWidth / window.innerHeight, 0.1, 4000);
scene = new THREE.Scene();
//LIGHTS
var light = new THREE.AmbientLight(0xffffff, 1);
scene.add(light);
var light1 = new THREE.PointLight(0xffffff, 0.3);
scene.add(light1);
//Gun holder
var gunHolder = new THREE.Object3D();
var gunHolderColour = 0x0f4207;
var gunHolderBaseCylinderGeometry = new THREE.CylinderGeometry(10, 10, 50, 32);
var gunHolderBaseCylinderMaterial = new THREE.MeshStandardMaterial({
color: gunHolderColour,
metalness: 0.5,
roughness: 0.5
});
var gunHolderBaseCylinderMesh = new THREE.Mesh(gunHolderBaseCylinderGeometry, gunHolderBaseCylinderMaterial);
gunHolderBaseCylinderMesh.position.set(0, -8, -3000);
scene.add(gunHolderBaseCylinderMesh);
requestAnimationFrame(render);
function render() {
gunHolderBaseCylinderMesh.rotation.z += 0.01;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
}
You can use .translate() method of your geometry:
var gunHolderBaseCylinderGeometry = new THREE.CylinderGeometry(10, 10, 50, 32); // height is 50
gunHolderBaseCylinderGeometry.translate(0, 25, 0); // move upwards at half of height, 25
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor(0xeaebed);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(5, window.innerWidth / window.innerHeight, 0.1, 4000);
scene = new THREE.Scene();
//LIGHTS
var light = new THREE.AmbientLight(0xffffff, 1);
scene.add(light);
var light1 = new THREE.PointLight(0xffffff, 0.3);
scene.add(light1);
//Gun holder
var gunHolder = new THREE.Object3D();
var gunHolderColour = 0x0f4207;
var gunHolderBaseCylinderGeometry = new THREE.CylinderGeometry(10, 10, 50, 32);
gunHolderBaseCylinderGeometry.translate(0, 25, 0);
var gunHolderBaseCylinderMaterial = new THREE.MeshStandardMaterial({
color: gunHolderColour,
metalness: 0.5,
roughness: 0.5
});
var gunHolderBaseCylinderMesh = new THREE.Mesh(gunHolderBaseCylinderGeometry, gunHolderBaseCylinderMaterial);
gunHolderBaseCylinderMesh.position.set(0, -8, -3000);
scene.add(gunHolderBaseCylinderMesh);
requestAnimationFrame(render);
function render() {
requestAnimationFrame(render);
gunHolderBaseCylinderMesh.rotation.z += 0.01;
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.js"></script>

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.

Resources