three.js: Bright edges in shadows - three.js

It seems that when an object casts and receives shadows you get this bright edge that looks like light bleeding through. Is there any way to overcome this? In the snippet I give here you can see that the shadow from the cylinder on the two cubes doesn't have the issue in the picture, but on the back is where you see the line happening.
width = window.innerWidth
height = window.innerHeight
renderer = new THREE.WebGLRenderer({antialias: true})
renderer.setClearColor(0xeeeeee)
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(width, height)
document.body.appendChild(renderer.domElement)
scene = new THREE.Scene()
camera = new THREE.PerspectiveCamera(35, width / height, 0.1, 3000)
camera.position.set(-45, 47, 75)
controls = new THREE.OrbitControls(camera, renderer.domElement)
controls.minDistance = 40
controls.maxDistance = 1300
material = new THREE.MeshPhongMaterial({color: 0xFF0000, specular: 0x111111, shininess: 75})
scene.add(camera, new THREE.AmbientLight(0xffffff, 0.4))
light = new THREE.PointLight(0xffffff, 0.8)
renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.PCFShadowMap
light.castShadow = true
light.shadow.mapSize.width = 3072
light.shadow.mapSize.height = 3072
light.shadow.camera.left = 500
function shadow(w) {
w.castShadow = true
w.receiveShadow = true
}
camera.add(light)
light.position.y += 60
light.position.x += 70
requestAnimationFrame(function animate(){
requestAnimationFrame(animate)
renderer.render(scene, camera)
})
b = new THREE.Mesh(new THREE.BoxGeometry(20, 20, 20), material)
shadow(b)
scene.add(b)
c = new THREE.Mesh(new THREE.CylinderGeometry(5,5,10,32), material)
c.position.set(3,15,3)
shadow(c)
scene.add(c)
d = new THREE.Mesh(new THREE.BoxGeometry(20, 10, 1), material)
d.position.set(3,15,-5)
shadow(d)
scene.add(d)
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Related

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)

three.js: Cylinder with negative thetaLength

I want to use an "inverted" cylinder with the thetaLength set to -6.3 so that the inside will be classed as the FrontSide, so then that cylinder can go inside another normal cylinder with rings on the top and bottom to form a tube.
The reason I want to do all this is so the whole object can be combined into one mesh with a single material. If you don't set the thetaLength to negative you have to have a duplicate material with the side set to BackSide, so you can't have it all as one mesh.
I've done what I'm talking about in the example below (you can zoom and move with the mouse). The negative theta cylinder is on the left and the normal one is on the right.
The problem that I'm having is, you can see that cylinder in question (the inside) of the left one is much darker than on the right one. The right one looks much more realistic.
I'm thinking maybe it's because it thinks the light is coming from a different direction to where it's actually coming from.
Is there any way to fix this and make the inverted cylinder appear like the BackSide one so that I can have a tube like this as a single mesh?
width = window.innerWidth
height = window.innerHeight
renderer = new THREE.WebGLRenderer({antialias: true})
renderer.setClearColor(0x8e8ed7)
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(width, height)
document.body.appendChild(renderer.domElement)
scene = new THREE.Scene()
camera = new THREE.PerspectiveCamera(35, width / height, 0.1, 3000)
camera.position.set(0, 50, 100)
controls = new THREE.OrbitControls(camera)
controls.minDistance = 40
controls.maxDistance = 1300
scene.add(camera, new THREE.AmbientLight(0xffffff, 0.48))
light = new THREE.PointLight(0xffffff, 0.55)
light.position.copy( camera.position );
light.position.y -= 80
light.position.x += 100
camera.add(light)
requestAnimationFrame(function animate(){
requestAnimationFrame(animate)
renderer.render(scene, camera)
})
material = new THREE.MeshPhongMaterial({color: 0xFF7E14, specular: 0x111111, shininess: 75})
material2= new THREE.MeshPhongMaterial({color: 0xFF7E14, specular: 0x111111, shininess: 75, side: THREE.BackSide})
tube_a = new THREE.Mesh(new THREE.CylinderGeometry(6,6,20,32,1,true,0,-6.3), material)
tube_aa = new THREE.Mesh(new THREE.CylinderGeometry(6,6,20,32,1,true,0,6.3), material2)
tube_b = new THREE.Mesh(new THREE.CylinderGeometry(8.1375,8.1375,20,32,1,true), material)
ring = new THREE.Mesh(new THREE.RingGeometry(6,8.1375,32), material)
group1 = new THREE.Group()
ta1 = tube_a.clone()
group1.add(ta1)
tb1 = tube_b.clone()
group1.add(tb1)
r = ring.clone()
r.position.y -= 10
r.rotateX((9*Math.PI)/18)
group1.add(r)
r = ring.clone()
r.position.y += 10
r.rotateX((27*Math.PI)/18)
group1.add(r)
group1.position.x -= 15
scene.add(group1)
group2 = new THREE.Group()
ta2 = tube_aa.clone()
group2.add(ta2)
tb2 = tube_b.clone()
group2.add(tb2)
r = ring.clone()
r.position.y -= 10
r.rotateX((9*Math.PI)/18)
group2.add(r)
r = ring.clone()
r.position.y += 10
r.rotateX((27*Math.PI)/18)
group2.add(r)
group2.position.x += 15
scene.add(group2)
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
The problem that I'm having is, you can see that cylinder in question (the inside) of the left one is much darker than on the right one. The right one looks much more realistic.
You have to update the vertex normal vectors by Geometry.computeVertexNormals() after generating the mesh, to solve this issue:
tube_a = new THREE.Mesh(new THREE.CylinderGeometry(6,6,20,32,1,true,0,-6.3), material)
tube_a.geometry.computeVertexNormals();
width = window.innerWidth
height = window.innerHeight
renderer = new THREE.WebGLRenderer({antialias: true})
renderer.setClearColor(0x8e8ed7)
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(width, height)
document.body.appendChild(renderer.domElement)
scene = new THREE.Scene()
camera = new THREE.PerspectiveCamera(35, width / height, 0.1, 3000)
camera.position.set(0, 50, 100)
controls = new THREE.OrbitControls(camera)
controls.minDistance = 40
controls.maxDistance = 1300
scene.add(camera, new THREE.AmbientLight(0xffffff, 0.48))
light = new THREE.PointLight(0xffffff, 0.55)
light.position.copy( camera.position );
light.position.y -= 80
light.position.x += 100
camera.add(light)
requestAnimationFrame(function animate(){
requestAnimationFrame(animate)
renderer.render(scene, camera)
})
material = new THREE.MeshPhongMaterial({color: 0xFF7E14, specular: 0x111111, shininess: 75})
material2= new THREE.MeshPhongMaterial({color: 0xFF7E14, specular: 0x111111, shininess: 75, side: THREE.BackSide})
tube_a = new THREE.Mesh(new THREE.CylinderGeometry(6,6,20,32,1,true,0,-6.3), material)
tube_a.geometry.computeVertexNormals();
tube_aa = new THREE.Mesh(new THREE.CylinderGeometry(6,6,20,32,1,true,0,6.3), material2)
tube_b = new THREE.Mesh(new THREE.CylinderGeometry(8.1375,8.1375,20,32,1,true), material)
ring = new THREE.Mesh(new THREE.RingGeometry(6,8.1375,32), material)
group1 = new THREE.Group()
ta1 = tube_a.clone()
group1.add(ta1)
tb1 = tube_b.clone()
group1.add(tb1)
r = ring.clone()
r.position.y -= 10
r.rotateX((9*Math.PI)/18)
group1.add(r)
r = ring.clone()
r.position.y += 10
r.rotateX((27*Math.PI)/18)
group1.add(r)
group1.position.x -= 15
scene.add(group1)
group2 = new THREE.Group()
ta2 = tube_aa.clone()
group2.add(ta2)
tb2 = tube_b.clone()
group2.add(tb2)
r = ring.clone()
r.position.y -= 10
r.rotateX((9*Math.PI)/18)
group2.add(r)
r = ring.clone()
r.position.y += 10
r.rotateX((27*Math.PI)/18)
group2.add(r)
group2.position.x += 15
scene.add(group2)
function resize() {
var aspect = window.innerWidth / window.innerHeight;
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = aspect;
camera.updateProjectionMatrix();
//controls.handleResize();
}
window.onresize = resize;
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>

three.js: At a certain distance the entire scene goes dark in shadow

In this example you can zoom in and out with the mouse wheel. If you keep zooming out and keep making the scene smaller it eventually goes completely dark. Is there any way to stop it doing that?
I thought maybe the range of the light is the problem but the default is set to go on forever so I don't know what's causing it.
width = window.innerWidth
height = window.innerHeight
renderer = new THREE.WebGLRenderer({antialias: true})
renderer.setClearColor(0xeeeeee)
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(width, height)
document.body.appendChild(renderer.domElement)
scene = new THREE.Scene()
camera = new THREE.PerspectiveCamera(35, width / height, 0.1, 3000)
camera.position.set(-45, 47, 75)
controls = new THREE.OrbitControls(camera)
controls.minDistance = 40
controls.maxDistance = 1300
material = new THREE.MeshPhongMaterial({color: 0xFF0000, specular: 0x111111, shininess: 75})
scene.add(camera, new THREE.AmbientLight(0xffffff, 0.4))
light = new THREE.PointLight(0xffffff, 0.8)
renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.PCFShadowMap
light.castShadow = true
light.shadow.mapSize.width = 3072
light.shadow.mapSize.height = 3072
light.shadow.camera.left = 500
function shadow(w) {
w.castShadow = true
w.receiveShadow = true
}
camera.add(light)
light.position.y += 60
light.position.x += 70
requestAnimationFrame(function animate(){
requestAnimationFrame(animate)
renderer.render(scene, camera)
})
b = new THREE.Mesh(new THREE.BoxGeometry(20, 20, 20), material)
shadow(b)
scene.add(b)
c = new THREE.Mesh(new THREE.CylinderGeometry(5,5,10,32), material)
c.position.set(3,15,3)
shadow(c)
scene.add(c)
d = new THREE.Mesh(new THREE.BoxGeometry(20, 10, 1), material)
d.position.set(3,15,-5)
shadow(d)
scene.add(d)
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
You can solve the problem by increasing the far property of the light`s internal shadow camera. Try something like:
light.shadow.camera.far = 3000

three.js transparent sphere glitch

I have a transparent sphere and a spot light and that's about it. My sphere displays visual glitches, like striations.
see: http://jsfiddle.net/blwoodley/tvcogqkg/3/
(Note the grid is not necessary to manifest the bug. I just put it in there to show that transparency is working otherwise fine).
Any thoughts on how to get rid of these glitches? They seem to depend on the relative position of the camera and spot light.
Using three.js, r71.
Here is the code from the fiddle since SO seems to want it:
var SCREEN_WIDTH = window.innerWidth - 100;
var SCREEN_HEIGHT = window.innerHeight - 100;
var camera, scene, _planeMesh;
var canvasRenderer, webglRenderer;
var container, mesh, geometry, plane;
container = document.createElement('div');
document.body.appendChild(container);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 100000);
camera.position.set( 380, 80, 100 );
var spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( 180, 160, 0 );
var grid = new THREE.GridHelper(400, 40);
grid.position.y = -20;
scene.add(grid);
scene.add(spotLight);
camera.lookAt( scene.position );
var material = new THREE.MeshPhongMaterial( {
color: 0xaaaa00,
emissive: 0xaa0000,
specular: 0xaa00aa,
shininess: 10,
side: THREE.DoubleSide,
shading: THREE.SmoothShading,
opacity: .8, transparent: true } );
var size = 16.0;
var sphereGeo = new THREE.SphereGeometry( size, 32, 16 );
var mesh = new THREE.Mesh( sphereGeo, material);
scene.add(mesh);
var mesh = new THREE.Mesh( sphereGeo, material);
mesh.position.y = 40;
scene.add(mesh);
var mesh = new THREE.Mesh( sphereGeo, material);
mesh.position.x = 60;
scene.add(mesh);
// RENDERER
webglRenderer = new THREE.WebGLRenderer();
webglRenderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
webglRenderer.domElement.style.position = "relative";
container.appendChild(webglRenderer.domElement);
animate();
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
webglRenderer.render(scene, camera);
}
Remove the attribute side: THREE.DoubleSide. Since you are drawing spheres, you don't need it.

Resources