Three js: Create a vertical ruler with measurements - three.js

I want to create a vertical ruler with measurements like the image below. can anyone help me with it.
var material = new THREE.LineBasicMaterial({
color: 0x07E1E1,
linewidth: 3
});
var geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3( 0, 0, 0 ),
new THREE.Vector3( 0, 1100, 0 ),
new THREE.Vector3( 0, 0, 0 )
);
var line = new THREE.Line( geometry, material );
scene.add( line );
line.position.set(-550, -550, 200);
But it is not getting as the image and also the measurements…

You can use LineBasicMaterial and Line elements.
var camera, scene, renderer, object;
init();
function init() {
var container;
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
camera.target = new THREE.Vector3( 0, 0, 0 );
scene = new THREE.Scene();
object = new THREE.Object3D();
var lineMtr = new THREE.LineBasicMaterial({ color: 0xffffff, linewidth: 3, opacity: 1 });
var geo = new THREE.Geometry();
geo.vertices.push(new THREE.Vector3(0, 10 ,3));
geo.vertices.push(new THREE.Vector3(0, 0 ,3));
var line = new THREE.Line(geo, lineMtr);
var i = 0, l = 10;
object.add(line);
while (i <= l) {
var geoSegm = new THREE.Geometry();
geoSegm.vertices.push(new THREE.Vector3(0.1, i, 3));
geoSegm.vertices.push(new THREE.Vector3(0, i, 3));
var lineSegm = new THREE.Line(geoSegm, lineMtr);
object.add(lineSegm);
var textSprite = makeTextSprite((i * 10).toString(), {r: 255, g: 255, b: 255, a: 255}, new THREE.Vector3(0.2, i, 3), Math.PI);
object.add(textSprite);
i++;
}
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
You can create a texture for a SpriteMaterial, then use Sprite for ruler texts.
function makeTextSprite(label, fontColor, pos, rot) {
var fontface = "Arial";
var fontsize = 100;
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.font = "Bold " + fontsize.toString() + "px " + fontface;
var metrics = context.measureText(label);
context.rotate(-Math.PI);
context.translate(-canvas.width, -canvas.height);
context.fillStyle = "rgba(" + fontColor.r + "," + fontColor.g + "," + fontColor.b + "," + fontColor.a + ")";
context.fillText(label, 0, 100);
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
texture.center = new THREE.Vector2(0.5, 0.5);
texture.rotation = Math.PI;
var spriteMaterial = new THREE.SpriteMaterial({
map: texture, color: 0xffffff
});
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(0.25, 0.25, 0.25);
sprite.position.set(pos.x, pos.y, pos.z);
return sprite;
}
I used codes in that link http://jsfiddle.net/3mrzL75h/19/
In first look you can't seeing ruler, drag camera to right.

Related

How to project a texture to curved surface?

Screen capture
I tried to make a 3/4 cylinder surface, and I made it from extruting by a ellipe path,
but when I tried to load a texture to the surface, It does not as I exprected: uniformly painted to the surface, it's stretched
I know it's about texture projection, But I dont know how to set options.
class EllipseCurve3 extends THREE.Curve {
ellipse = null
constructor (ellipse) {
super()
this.ellipse = ellipse
}
getPoint(t, optionalTarget = new THREE.Vector3()) {
const point = this.ellipse.getPoint(t, optionalTarget)
return new THREE.Vector3(
point.x,
point.y,
0
)
}
}
// Scene
const scene = new THREE.Scene();
var shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.moveTo(0, 1);
shape.lineTo(50, 1);
shape.moveTo(50, 0);
shape.lineTo(0, 0);
// var curve = new THREE.CatmullRomCurve3([
// new THREE.Vector3(0, 0, 50),
// new THREE.Vector3(-50, 0, 0),
// new THREE.Vector3(0, 0, -50)
// ]);
const arc = new THREE.EllipseCurve(
0,
0, // ax, aY
100,
100, // xRadius, yRadius
0,
1.5 * Math.PI, // aStartAngle, aEndAngle
false, // aClockwise
0 // aRotation
),
path = new EllipseCurve3(arc)
geometry = new THREE.ExtrudeGeometry(shape, {
bevelEnabled: false,
extrudePath: path,
steps: 50,
depth: 5,
amount: 20,
material: 0,
extrudeMaterial: 1
});
// Set up lights
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const axesHelper = new THREE.AxesHelper(500);
scene.add(axesHelper);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.6);
directionalLight.position.set(100, 200, 100); // x, y, z
scene.add(directionalLight);
// Camera
const width = 200;
const height = width * (window.innerHeight / window.innerWidth);
const camera = new THREE.OrthographicCamera(
width / -2, // left
width / 2, // right
height / 2, // top
height / -2, // bottom
0.1, // near
1000 // far
);
camera.position.set(400, 400, 400);
camera.lookAt(0, 0, 0);
// Renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
renderer.render(scene, camera);
// Add it to HTML
document.body.appendChild(renderer.domElement);
var textureLoader = new THREE.TextureLoader();
textureLoader.crossOrigin = true;
const picture = 'https://threejs.org/examples/textures/uv_grid_opengl.jpg'
textureLoader.load(picture, function(texture) {
// repeat pattern
texture.wrapS = texture.wrapT = THREE.MirroredRepeatWrapping;
// zoom in on pattern
texture.repeat.set(.01, .01);
// assign texture via MeshBasicMaterial
var material = new THREE.MeshBasicMaterial({
map: texture,
needsUpdate: true,
// transparent: true,
// premultipliedAlpha: true,
// side: THREE.DoubleSide,
// blending: THREE.AdditiveBlending
});
// var material = new THREE.MeshPhongMaterial({ color: 0x0048ff });
var mesh = new THREE.Mesh(geometry, material)
mesh.rotation.x = Math.PI / 2
// mesh.rotation.z = Math.PI / 2
scene.add(mesh)
scene.add(cube)
})
function render() {
renderer.render(scene, camera);
// Rotate out group
// svgGroup.rotation.y -= 0.005
controls.update();
requestAnimationFrame(render);
}
render();
Code here
https://codepen.io/mike-xu/pen/RwQeEXJ
"I know it's about texture projection" - It's about computing UV, based on vertices coordinates.
CylinderGeometry also may help to achieve the result you described. With less code, and more convenient and predictable way.
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three#0.136.0";
import {OrbitControls} from "https://cdn.skypack.dev/three#0.136.0/examples/jsm/controls/OrbitControls.js";
console.clear();
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 10, 10);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", event => {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
});
let controls = new OrbitControls(camera, renderer.domElement);
scene.add(new THREE.AxesHelper(10));
let g = new THREE.CylinderGeometry(5, 5, 5, 100, 20, true, 0, Math.PI * 1.5);
let m = new THREE.MeshBasicMaterial({
side: THREE.DoubleSide,
map: new THREE.TextureLoader().load(
"https://threejs.org/examples/textures/uv_grid_opengl.jpg",
tex => {
tex.wrapS = tex.wrapT = THREE.MirroredRepeatWrapping;
tex.repeat.set(3, 1);
}
)
});
let c = new THREE.Mesh(g, m);
scene.add(c);
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
</script>

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)

ThreeJS: How to clone the rotation of one object to another

I have two canvas where two canvas has two different objects. I'm trying to set the rotation of one object to another. Here the second canvas object acts as a viewcube where it should only rotate when the object_1 gets rotated.
I have tried by set the rotation of the one camera to another but I can't seem to achieve it.
Here's the fiddle link https://jsfiddle.net/jvy396x8/2/
var cube = document.querySelector('.cube');
// var container = document.getElementById('container');
var scene_1Rotation;
var scene = new THREE.Scene();
var scene_1 = new THREE.Scene();
var object;
var w = window.innerWidth;
var h = window.innerHeight;
var viewSize = h;
var aspectRatio = w / h;
_viewport = {
viewSize: viewSize,
aspectRatio: aspectRatio,
left: (-aspectRatio * viewSize) / 2,
right: (aspectRatio * viewSize) / 2,
top: viewSize / 2,
bottom: -viewSize / 2,
near: -10000,
far: 10000
}
var camera = new THREE.OrthographicCamera(
_viewport.left,
_viewport.right,
_viewport.top,
_viewport.bottom,
_viewport.near,
_viewport.far
);
camera.zoom = 25;
var camera_1 = new THREE.PerspectiveCamera(100, window.innerWidth / window.innerHeight, 0.001, 1000000);
// var camera = new THREE.OrthographicCamera(window.innerWidth / -30, window.innerWidth / 30, window.innerHeight / 30, window.innerHeight / -30, 1, 1000)
camera.position.set(20, 0, 0);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
var renderer_1 = new THREE.WebGLRenderer({
antialias: true
});
$('#container').append(renderer_1.domElement);
$('#scene').html(renderer_1.domElement);
// var zoom = orthoWidth / meshWidth;
// _Camera.setZoom(zoom);
object = new THREE.Group();
scene.background = new THREE.Color(0xffffff0);
console.log(scene);
scene_1.background = new THREE.Color(0xffffff);
console.log(scene_1);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var controls_1 = new THREE.OrbitControls(camera_1, renderer_1.domElement);
var geometry_1 = new THREE.BoxGeometry();
var material_1 = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var cube_1 = new THREE.Mesh(geometry_1, material_1);
scene_1.add(cube_1);
var geometry_2 = new THREE.BoxGeometry();
var material_2 = new THREE.MeshBasicMaterial({ color: 0x00fff0 });
var cube_2 = new THREE.Mesh(geometry_2, material_2);
cube_2.position.x = 1;
scene_1.add(cube_2);
controls_1.noPan = true;
controls_1.noZoom = true;
camera_1.position.z = 2;
var material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
var geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0, 7, 0),
new THREE.Vector3(0, 0, 0)
);
var line = new THREE.Line(geometry, material);
object.add(line)
scene.add(object);
var material = new THREE.LineBasicMaterial({
color: 0xcc0000
});
var geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(7, 0, 0)
);
var line = new THREE.Line(geometry, material);
object.add(line)
scene.add(object);
var material = new THREE.LineBasicMaterial({
color: 0x008900
});
var geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(0, 0, 7),
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0, 0, 0)
);
var line = new THREE.Line(geometry, material);
object.add(line)
scene.add(object);
// ' X ' AXIS dashed material |
var xPlaneDashedMaterial = new THREE.LineDashedMaterial({ color: 0x00008b, dashSize: Math.PI * 2 / 20, gapSize: Math.PI * 2 / 20, linewidth: 10 }),
xPlaneDashedCircleGeometry = new THREE.CircleGeometry(7, 75, 69.9, 5);
xPlaneDashedCircleGeometry.vertices.shift();
var xPlaneDashedGeomtry = new THREE.Line(xPlaneDashedCircleGeometry, xPlaneDashedMaterial);
xPlaneDashedGeomtry.computeLineDistances();
object.add(xPlaneDashedGeomtry)
scene.add(object);
var xPlanePlainMaterial = new THREE.MeshBasicMaterial({ color: 0x00008b });
var xplanePlainCirleGeometry = new THREE.CircleGeometry(7, 75, 18.3, 1.3);
xplanePlainCirleGeometry.vertices.shift();
var xPlanePlainGeomtry = new THREE.Line(xplanePlainCirleGeometry, xPlanePlainMaterial);
object.add(xPlanePlainGeomtry)
scene.add(object);
// ' Y ' AXIS dashed material -
var yPlaneDashedMaterial = new THREE.LineDashedMaterial({ color: 0xcc0000, dashSize: Math.PI * 2 / 20, gapSize: 1 * Math.PI * 2 / 20, linewidth: 10 });
var yPlaneDashedCircleGeometry = new THREE.CircleGeometry(7, 30, 7., 4.8);
yPlaneDashedCircleGeometry.vertices.shift();
var yPlaneDashedGeomtry = new THREE.Line(yPlaneDashedCircleGeometry, yPlaneDashedMaterial);
yPlaneDashedGeomtry.computeLineDistances();
yPlaneDashedGeomtry.rotation.x = 17.27;
object.add(yPlaneDashedGeomtry)
scene.add(object);
var yPlanePlainMaterial = new THREE.MeshBasicMaterial({ color: 0xcc0000 });
var yPlanePlainCirleGeometry = new THREE.CircleGeometry(7, 75, 18.1, 1.5);
yPlanePlainCirleGeometry.vertices.shift();
var yPlanePlainGeomtry = new THREE.Line(yPlanePlainCirleGeometry, yPlanePlainMaterial);
yPlanePlainGeomtry.rotation.x = 17.27;
object.add(yPlanePlainGeomtry)
scene.add(object);
// ' Z ' AXIS material /
var zPlanePlainMaterial = new THREE.LineDashedMaterial({ color: 0x008900, dashSize: 1 * Math.PI * 4 / 40, gapSize: 1 * Math.PI * 4 / 40, linewidth: 10 });
var zPlanePlainCirleGeometry = new THREE.CircleGeometry(7, 75, 69.9, 10);
zPlanePlainCirleGeometry.vertices.shift();
var zPlanePlainGeomtry = new THREE.Line(zPlanePlainCirleGeometry, zPlanePlainMaterial);
zPlanePlainGeomtry.computeLineDistances();
zPlanePlainGeomtry.rotation.y = 17.27;
object.add(zPlanePlainGeomtry)
scene.add(object);
// ' X 'CONE geomtry|
var xPlaneConeGeometry = new THREE.ConeGeometry(0.2, 1, 32);
var xPlaneConeGeomtryMaterial = new THREE.MeshBasicMaterial({ color: 0x00008b });
var xPlaneConeGeometryLeft = new THREE.Mesh(xPlaneConeGeometry, xPlaneConeGeomtryMaterial);
object.add(xPlaneConeGeometryLeft)
scene.add(object);
//' X ' CONE
xPlaneConeGeometryLeft.position.y = 6.5;
//' Y 'CONE geomtry
var yPlaneConeGeometry = new THREE.ConeGeometry(0.2, 1, 32);
var yPlaneConeGeomtryMaterial = new THREE.MeshBasicMaterial({ color: 0xcc0000 });
var zPlaneConeGeometry = new THREE.ConeGeometry(0.2, 1, 32);
var zPlaneConeGeomtryMaterial = new THREE.MeshBasicMaterial({ color: 0x008900 });
var yPlaneConeGeometryLeft = new THREE.Mesh(yPlaneConeGeometry, yPlaneConeGeomtryMaterial);
object.add(yPlaneConeGeometryLeft);
scene.add(object);
var zPlaneConeGeometryRight = new THREE.Mesh(zPlaneConeGeometry, zPlaneConeGeomtryMaterial);
object.add(zPlaneConeGeometryRight)
scene.add(object);
console.log("object");
console.log(object.children.rotation);
// ' Y ' CONE
yPlaneConeGeometryLeft.position.x = 6.5;
yPlaneConeGeometryLeft.rotation.z = 4.7;
zPlaneConeGeometryRight.position.z = 6.5;
zPlaneConeGeometryRight.rotation.x = 1.6;
var mat = new THREE.Matrix4();
renderer_1.setAnimationLoop(() => {
mat.extractRotation(camera_1.matrixWorldInverse);
renderer_1.render(scene_1, camera_1);
camera_1.updateProjectionMatrix();
});
renderer.setAnimationLoop(() => {
mat.extractRotation(camera.matrixWorldInverse);
renderer.render(scene, camera);
camera.updateProjectionMatrix();
});
I have tried by set the rotation of the one camera to another by I can't able to achieve it.
To replicate the intended behavior in the second scene, it's not sufficient to just copy the rotation. Orbiting also transforms the position of the camera. Hence I suggest that you use a single camera for both scenes.
Also note that it's not necessary to update the projection matrix of your camera per frame. In your use case, do it once right after changing the zoom property.
Updated fiddle: https://jsfiddle.net/s0wzdm32/1/

How to build a perpendicular in three.js?

I need to build a perpendicular (line at an angle of 90 degrees to the original line) across the mid point of a straight line.
line = new THREE.Line( geometry, material );
geometry.vertices.push(
new THREE.Vector3( 100, 200, 0 ),
new THREE.Vector3( 300, 500, 0 ) );
In the manual I was not found information about it.
https://threejs.org/docs/#api/en/objects/Line
Thank you!
You can find the normal of a line by subtracting its start point from its end point (thus you'll get its direction), then rotate the resulted vector at 90 degrees (Math.PI * 0.5), then normalize it, and this is it, you've got the normal.
In the code snippet, the line itself is blueish (aqua), its normal is red.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var grid = new THREE.GridHelper(10, 10);
grid.rotation.x = -Math.PI * 0.5;
scene.add(grid);
var lineVertices = [
new THREE.Vector3(1, 2),
new THREE.Vector3(3, 5)
];
var lineGeom = new THREE.BufferGeometry().setFromPoints(lineVertices);
var lineMat = new THREE.LineBasicMaterial({color: 0x00ffff});
var line = new THREE.Line(lineGeom, lineMat);
scene.add(line);
var midPoint = new THREE.Vector3()
.subVectors(lineVertices[1], lineVertices[0])
.multiplyScalar(0.5)
.add(lineVertices[0]);
var normal = new THREE.Vector3()
.subVectors(lineVertices[1], lineVertices[0])
.applyAxisAngle(new THREE.Vector3(0, 0, 1), Math.PI * 0.5)
.normalize();
var normalVertices = [
normal.clone().setLength(2).add(midPoint),
normal.clone().negate().setLength(2).add(midPoint)
];
var normalGeom = new THREE.BufferGeometry().setFromPoints(normalVertices);
var normalMat = new THREE.LineBasicMaterial({color: 0xff0000 });
var normal = new THREE.Line(normalGeom, normalMat);
scene.add(normal);
renderer.setAnimationLoop(()=>{renderer.render(scene, camera)});
body {
overflow:hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>

how to have the shadow of a lightshade on surrounding walls in three.js

I have created a scene with a light shade, walls surrounding it, and few light sources. I want the spotlights inside the lamp shade cast shadow on the walls.I played with parameters of the spotlight, but I could not achieve having shadow on the walls. here is my code:
<html>
<head>
<title>Lightshade</title>
<script src="three.js"> </script>
<script src="TrackballControls.js"></script>
</head>
<body>
<script>
//declaring variables
var camera, scene, renderer;
var controls;
var cone, coneGeometry;
scene = new THREE.Scene();
var camera = new THREE.OrthographicCamera( -window.innerWidth / 25, window.innerWidth / 25, window.innerHeight / 25, -window.innerHeight / 25, -10000, 1000000);
camera.position.set( 0, 2.0, 5.0);
camera.lookAt(scene.position);
//adding the renderer to the screen
renderer = new THREE.WebGLRenderer( { antialias: true} );
renderer.setClearColor( 0xeeeeee , 0); //eeeeee
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMapEnabled = true;
document.body.appendChild( renderer.domElement );
//adding the camera interactive method
controls = new THREE.TrackballControls( camera, renderer.domElement );
controls.noKeys = true;
//creating materials for lightshade
BlightshadeMaterial = new THREE.MeshBasicMaterial({color:0xffeb00,wireframe:false, side:THREE.DoubleSide, ambient: 0xffffff});
lightshadeMaterial = new THREE.MeshPhongMaterial({color:0xffeb00,transparent: true,opacity: 0.6,wireframe:false, side:THREE.DoubleSide, ambient: 0xffffff});
// adding some light to the screen
var light3 = new THREE.PointLight( 0xffffff, 1, 100);
light3.position.set( 0, 30.0, 0 );
scene.add( light3 );
var light1 = new THREE.PointLight( 0xffffff,0.7, 100 );
light1.position.set( 0, 4.0, 0 );
scene.add( light1 );
var light2 = new THREE.PointLight( 0xffffff, 0.7, 100 );
light2.position.set( 0, -1.0, 0 );
scene.add( light2 );
var light4 = new THREE.PointLight( 0xffffff, 1, 100);
light4.position.set( 30.0, 16.0, 30.0 );
scene.add( light4 );
var light5 = new THREE.PointLight( 0xffffff, 1, 100);
light5.position.set( -30.0, 16.0, 30.0 );
scene.add( light5 );
coneGeometry = new THREE.CylinderGeometry( 5, 12.5, 15.0, 30, 20 , true);
cone = new THREE.Mesh(coneGeometry,lightshadeMaterial);
cone.castShadow = true;
scene.add(cone);
innerConeGeometry = new THREE.CylinderGeometry( 4.5, 12.0, 15.0, 30,20 , true);
innerCone = new THREE.Mesh(innerConeGeometry,lightshadeMaterial);
innerCone.castShadow = true;
scene.add(innerCone);
upGeometry = new THREE.RingGeometry( 4.5, 5.0, 30 ,3 );
upSide = new THREE.Mesh( upGeometry, BlightshadeMaterial );
scene.add( upSide );
upSide.geometry.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI/2));
upSide.geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0,7.5,0));
downGeometry = new THREE.RingGeometry( 12.0, 12.5, 30 ,3 );
downSide = new THREE.Mesh( downGeometry, BlightshadeMaterial );
scene.add( downSide );
downSide.geometry.applyMatrix(new THREE.Matrix4().makeRotationX(Math.PI/2));
downSide.geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0,-7.5,0));
//Creating the shadow
var point = new THREE.Mesh(new THREE.SphereGeometry(0.2), new THREE.MeshBasicMaterial( {color: 0xffff00 } ));
point.position.set(0,2.5,-1.0);
scene.add( point );
var spotlight = new THREE.SpotLight(0xffffff ,3, 800 , Math.PI/4);
spotlight.target = point;
//to cast the light horizontally to the light shade
spotlight.position.set(0,2.5,0);
spotlight.shadowCameraVisible = true;
spotlight.shadowDarkness = 0.95;
// must enable shadow casting ability for the light
spotlight.castShadow = true;
spotlight.shadowMapWidth = 512;
spotlight.shadowMapHeight = 512;
spotlight.shadowCameraFov = 300;
scene.add(spotlight);
var point = new THREE.Mesh(new THREE.SphereGeometry(0.2), new THREE.MeshBasicMaterial( {color: 0xffff00} ));
point.position.set(1.0,2.5,0);
scene.add( point );
var spotlight = new THREE.SpotLight(0xffffff ,3, 800, Math.PI/4);
spotlight.target = point;
//to cast the light horizontally to the light shade
spotlight.position.set(0,2.5,0);
spotlight.shadowDarkness = 0.95;
// must enable shadow casting ability for the light
spotlight.castShadow = true;
spotlight.shadowMapWidth = 512;
spotlight.shadowMapHeight = 512;
spotlight.shadowCameraFov = 30.0;
scene.add(spotlight);
var point = new THREE.Mesh(new THREE.SphereGeometry(0.2), new THREE.MeshBasicMaterial( {color: 0xffff00} ));
point.position.set(-1.0,2.5,0);
scene.add( point );
var spotlight = new THREE.SpotLight(0xffffff ,3, 800, Math.PI/4);
spotlight.target = point;
//to cast the light horizontally to the light shade
spotlight.position.set(0,2.5,0);
spotlight.shadowDarkness = 0.95;
// must enable shadow casting ability for the light
spotlight.castShadow = true;
spotlight.shadowMapWidth = 512;
spotlight.shadowMapHeight = 512;
spotlight.shadowCameraFov = 30.0;
scene.add(spotlight);
var point = new THREE.Mesh(new THREE.SphereGeometry(0.2), new THREE.MeshBasicMaterial( {color: 0xffff00} ));
point.position.set(1.0,2.5,-1.0);
scene.add( point );
var spotlight = new THREE.SpotLight(0xffffff ,3, 800, Math.PI/4);
spotlight.target = point;
//to cast the light horizontally to the light shade
spotlight.position.set(0,2.5,0);
spotlight.shadowDarkness = 0.95;
// must enable shadow casting ability for the light
spotlight.castShadow = true;
spotlight.shadowMapWidth = 512;
spotlight.shadowMapHeight = 512;
spotlight.shadowCameraFov = 300;
scene.add(spotlight);
var point = new THREE.Mesh(new THREE.SphereGeometry(0.2), new THREE.MeshBasicMaterial( {color: 0xffff00} ));
point.position.set(-1.0,2.5,-1.0);
scene.add( point );
var spotlight = new THREE.SpotLight(0xffffff ,3, 800, Math.PI/4);
spotlight.target = point;
//to cast the light horizontally to the light shade
spotlight.position.set(0,2.5,0);
spotlight.shadowDarkness = 0.95;
// must enable shadow casting ability for the light
spotlight.castShadow = true;
spotlight.shadowMapWidth = 512;
spotlight.shadowMapHeight = 512;
spotlight.shadowCameraFov = 30.0;
scene.add(spotlight);
//create walls and floor
var floorMaterial = new THREE.MeshPhongMaterial({side: THREE.DoubleSide} );
var floorGeometry = new THREE.PlaneBufferGeometry(170, 170, 100, 100);
var floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
floor.position.y = -70;
// Note the mesh is flagged to receive shadows
floor.castShadow= false;
floor.receiveShadow = true;
scene.add(floor);
//front wall
var frontMaterial = new THREE.MeshPhongMaterial( {side: THREE.DoubleSide } );
var frontGeometry = new THREE.PlaneBufferGeometry(170, 100, 100, 100);
var front = new THREE.Mesh(frontGeometry, frontMaterial);
front.position.z = -85;
front.position.y = -20;
//front.rotation.x = Math.PI / 2;
// Note the mesh is flagged to receive shadows
front.castShadow= false;
front.receiveShadow = true;
scene.add(front);
//right wall
var rightMaterial = new THREE.MeshPhongMaterial( {side: THREE.DoubleSide} );
var rightGeometry = new THREE.PlaneBufferGeometry(170, 100, 100, 100);
var right = new THREE.Mesh(rightGeometry, rightMaterial);
right.rotation.y = Math.PI / 2;
right.position.x = 85;
right.position.y = -20;
// Note the mesh is flagged to receive shadows
right.castShadow= false;
right.receiveShadow = true;
scene.add(right);
//left wall
var leftMaterial = new THREE.MeshPhongMaterial( {side: THREE.DoubleSide} );
var leftGeometry = new THREE.PlaneBufferGeometry(170, 100, 100, 100);
var left = new THREE.Mesh(leftGeometry, leftMaterial);
left.rotation.y = Math.PI / 2;
left.position.x = -85;
left.position.y = -20;
// Note the mesh is flagged to receive shadows
left.castShadow= false;
left.receiveShadow = true;
scene.add(left);
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
controls.update();
renderer.render( scene, camera );
}
animate();
</script>
</body>
</html>
Alternatively, do you know any other better way to have the shadow of the light shade on the walls. Thank you in advance.
This seems similar to an issue I had: Three.js DoubleSided material doesn't cast shadow on both sides of planar parametric geometry
In particular, "The material.side property is not taken into consideration when casting shadows."

Resources