I want to create a grid of geometries (ROWS * COLUMNS) and wanna rotate each individual mesh around it's own center.
I generate the grid through two for loops, translate the single elements to there correct position and push them into an array to use them again in the animation function. In the animation function I iterate again over all the elements and rotate every single one.
the problem is that even though I address each element individually and I have translated each element to the right place, each element still revolves around the center of the page and not its own center (see the screenshot)
Here is my current attempt:
const main = () => {
const ROWS = 4;
const COLUMNS = 4;
const ITEMS = [];
const canvas = document.querySelector('#canvas');
const renderer = new THREE.WebGLRenderer({canvas, antialias: true});
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(1, window.innerWidth/window.innerHeight, 0.1, 1000);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor('#e5e5e5');
camera.position.z = 500;
// GEOMETRY
for (let x = 0; x < COLUMNS; x++) {
for (let y = 0; y < ROWS; y++) {
const geometry = new THREE.BoxGeometry(1, 1, 0.5);
const edges = new THREE.EdgesGeometry(geometry);
const edgesMaterial = new THREE.LineBasicMaterial({ color: 0x1940EB });
const edgesMesh = new THREE.LineSegments(edges, edgesMaterial);
ITEMS.push(edgesMesh);
edges.translate(x*1.5, y*1.5, 0);
scene.add(edgesMesh);
}
}
scene.position.set(-COLUMNS/2, -ROWS/2, 0);
const animation = () => {
requestAnimationFrame(animation);
ITEMS.map(item => {
item.rotation.x += 0.01;
item.rotation.y += 0.01;
})
camera.updateMatrixWorld();
renderer.render(scene, camera);
}
const onWindowResize = () => {
const w = window.innerWidth;
const h = window.innerHeight;
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize(w, h);
}
animation();
onWindowResize();
window.addEventListener('resize', onWindowResize, false);
};
window.addEventListener('load', main, false);
body {
padding: 0;
margin: 0;
height: 100vh;
}
canvas {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.js"></script>
<canvas id="canvas"></canvas>
Can someone explain to me why the elements individually addressed in the animation function still do not revolve around themselves?
Thanks for your help
Because the code is moving the geometry itself so that it's center is no longer in the middle of the box.
change
edges.translate(x*1.5, y*1.5, 0);
to
edgesMesh.position.set(x*1.5, y*1.5, 0);
This will move the Object3D in the scenegraph instead of the vertices of the geometry data.
const main = () => {
const ROWS = 4;
const COLUMNS = 4;
const ITEMS = [];
const canvas = document.querySelector('#canvas');
const renderer = new THREE.WebGLRenderer({canvas, antialias: true});
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(1, window.innerWidth/window.innerHeight, 0.1, 1000);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor('#e5e5e5');
camera.position.z = 500;
// GEOMETRY
for (let x = 0; x < COLUMNS; x++) {
for (let y = 0; y < ROWS; y++) {
const geometry = new THREE.BoxGeometry(1, 1, 0.5);
const edges = new THREE.EdgesGeometry(geometry);
const edgesMaterial = new THREE.LineBasicMaterial({ color: 0x1940EB });
const edgesMesh = new THREE.LineSegments(edges, edgesMaterial);
ITEMS.push(edgesMesh);
edgesMesh.position.set(x*1.5, y*1.5, 0);
scene.add(edgesMesh);
}
}
scene.position.set(-COLUMNS/2, -ROWS/2, 0);
const animation = () => {
requestAnimationFrame(animation);
ITEMS.map(item => {
item.rotation.x += 0.01;
item.rotation.y += 0.01;
})
camera.updateMatrixWorld();
renderer.render(scene, camera);
}
const onWindowResize = () => {
const w = window.innerWidth;
const h = window.innerHeight;
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize(w, h);
}
animation();
onWindowResize();
window.addEventListener('resize', onWindowResize, false);
};
window.addEventListener('load', main, false);
body {
padding: 0;
margin: 0;
height: 100vh;
}
canvas {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.js"></script>
<canvas id="canvas"></canvas>
You might find this article useful
Related
I'm learning three.js's frustum by modifying the example in Scene Graph below.
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 40;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 50, 0);
camera.up.set(0, 0, 1);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
{
const color = 0xFFFFFF;
const intensity = 3;
const light = new THREE.PointLight(color, intensity);
scene.add(light);
}
// an array of objects who's rotation to update
const objects = [];
const radius = 1;
const widthSegments = 6;
const heightSegments = 6;
const sphereGeometry = new THREE.SphereGeometry(
radius, widthSegments, heightSegments);
const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
sunMesh.scale.set(5, 5, 5);
scene.add(sunMesh);
objects.push(sunMesh);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
objects.forEach((obj) => {
obj.rotation.y = time;
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
html, body {
height: 100%;
margin: 0;
}
#c {
width: 100%;
height: 100%;
display: block;
}
<canvas id="c"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.144.0/three.min.js"></script>
Settings:
A sphere at the origin with radius = 1.
A camera positioned at y = 50, looking towards the origin, with the UP direction as (0,0,1).
Its frustum has fov = 40, aspect = 2, near = 0.1 and far = 1000.
I changed two parameters:
near: 0.1 → 48
far: 1000 → 52.
I'm expecting the sphere being contained inside the frustum, but why is the sphere's top part truncated?
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 40;
const aspect = 2; // the canvas default
const near = 48;
const far = 52;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 50, 0);
camera.up.set(0, 0, 1);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
{
const color = 0xFFFFFF;
const intensity = 3;
const light = new THREE.PointLight(color, intensity);
scene.add(light);
}
// an array of objects who's rotation to update
const objects = [];
const radius = 1;
const widthSegments = 6;
const heightSegments = 6;
const sphereGeometry = new THREE.SphereGeometry(
radius, widthSegments, heightSegments);
const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
sunMesh.scale.set(5, 5, 5);
scene.add(sunMesh);
objects.push(sunMesh);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
objects.forEach((obj) => {
obj.rotation.y = time;
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
html, body {
height: 100%;
margin: 0;
}
#c {
width: 100%;
height: 100%;
display: block;
}
<canvas id="c"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.144.0/three.min.js"></script>
Thanks to WestLangley's comment, I've found out the answer: the property Object3D.scale is a 3D vector that scales the object locally. Mesh is a subclass of Object3D. In my modified example above, the "sphere" (a hexagon in fact) is scaled to 5×. I commented out this line, so that there's no scaling (default factor 1×), and I observed that the "sphere" is contained inside the frustum.
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 10;
const aspect = 2; // the canvas default
const near = 49;
const far = 51;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 50, 0);
camera.up.set(0, 0, 1);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
{
const color = 0xFFFFFF;
const intensity = 3;
const light = new THREE.PointLight(color, intensity);
scene.add(light);
}
// an array of objects who's rotation to update
const objects = [];
const radius = 1;
const widthSegments = 6;
const heightSegments = 6;
const sphereGeometry = new THREE.SphereGeometry(
radius, widthSegments, heightSegments);
const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
//sunMesh.scale.set(5, 5, 5);
scene.add(sunMesh);
objects.push(sunMesh);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
objects.forEach((obj) => {
obj.rotation.y = time;
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
html, body {
height: 100%;
margin: 0;
}
#c {
width: 100%;
height: 100%;
display: block;
}
<canvas id="c"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.144.0/three.min.js"></script>
To check my understanding, I reduced the distance between near and the center of the "sphere" by 0.3, and I observed a hole as expected.
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 10;
const aspect = 2; // the canvas default
const near = 49.3;
const far = 50.7;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 50, 0);
camera.up.set(0, 0, 1);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
{
const color = 0xFFFFFF;
const intensity = 3;
const light = new THREE.PointLight(color, intensity);
scene.add(light);
}
// an array of objects who's rotation to update
const objects = [];
const radius = 1;
const widthSegments = 6;
const heightSegments = 6;
const sphereGeometry = new THREE.SphereGeometry(
radius, widthSegments, heightSegments);
const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
//sunMesh.scale.set(5, 5, 5);
scene.add(sunMesh);
objects.push(sunMesh);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
objects.forEach((obj) => {
obj.rotation.y = time;
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
html, body {
height: 100%;
margin: 0;
}
#c {
width: 100%;
height: 100%;
display: block;
}
<canvas id="c"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.144.0/three.min.js"></script>
Remark: I'm answering my own question in order to clear it from the unanswered queue.
I developed a 3D cube that moves on one axis simulating the accelerometer sensor.
Currently, I have the .obj and .mtl of a toycar which I aim to add to the scene(), but when I remove the
BoxGeometry 3D cube and replace it with the car mesh I got these errors all the time:
I also get this error saying that obj is not defined, even if I defined it globally I still have the same issue:
I checked libraries that exist locally and other function but I can't see where is the problem.
Below is how I load the car model:
const scene = new THREE.Scene();
var loader = new THREE.OBJMTLLoader();
loader.load('https://jyunming-chen.github.io/tutsplus/models/toycar.obj', 'https://jyunming-chen.github.io/tutsplus/models/toycar.mtl',
function (vehicle) {
toycar = vehicle;
toycar.rotateY(-10.99);
scene.add(toycar);
});
and this is my full .HTML code with js implementation:
This is hoq looks like now:
and this is what I am aiming to achieve:
That's my current code:
<html>
<head>
<meta charset="UTF-8">
<script src="./three.min.js"></script>
<script src="./require.js" type="text/javascript"></script>
<script src="./OrbitControls.js"></script>
<script src="./KeyboardState.js"></script>
<script src="./MTLLoader.js"></script>
<script src="./OBJMTLLoader.js"></script>
<script type="module"> import * as THREE from "./three.module.js"</script>
</head>
<body>
<canvas id="canvas" width="1000" height="600" style="border:1px solid #000000;"></canvas>
</body>
<script>
let sensorValue = 0;
let sensorAddr = 0;
var toycar;
StartRetrieveLiveData();
function main() {
const canvas = document.querySelector('#canvas');
const accelPanel = document.querySelector('#accelPanel');
const renderer = new THREE.WebGLRenderer({ alpha: true, canvas });
renderer.setClearColor( 0x626d73, 1 );
var context = canvas.getContext("2d");
var width = window.innerWidth;
var height = window.innerHeight;
const fov = 70;
const aspect = 2;
const near = 20;
const far = 500;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 50, 1.5);
camera.up.set(0, 0, 1);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
// var loader = new THREE.OBJMTLLoader();
// loader.load('https://jyunming-chen.github.io/tutsplus/models/toycar.obj', 'https://jyunming-chen.github.io/tutsplus/models/toycar.mtl',
// function (vehicle) {
// toycar = vehicle;
// toycar.rotateY(-10.99);
// scene.add(toycar);
// });
// An array of objects who's rotation to update
const objects = [];
const radius = 3;
const widthSegments = 3;
const heightSegments = 3;
const sphereGeometry = new THREE.BoxGeometry(radius, widthSegments, heightSegments);
const sunMaterial = new THREE.MeshBasicMaterial({ color: "green", wireframe: false });
const object = new THREE.Mesh(sphereGeometry, sunMaterial);
var cubeAxis = new THREE.AxesHelper(10);
object.add(cubeAxis);
object.scale.set(2, 2, 2);
scene.add(object);
objects.push(object);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
objects.forEach((obj) => {
sensorValueIndex = ((sensorValue / 16384) * 10);
obj.position.z = ((sensorValue / 16384) * 20);
console.log("AccX: ",sensorValueIndex);
// // Here I take accelerometerX and pass them to the 3D model
// if (sensorAddr === 1) {
// }
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
function onMsg(event) {
// console.log(`[message] Data received from server: ${event.data}`);
// console.log("event.data = " + JSON.parse(event.data));
var received_msg = event.data;
var obj = JSON.parse(JSON.parse(received_msg));
if (obj !== null) {
if (
obj.hasOwnProperty("DataMapChangedObjectsAddressValue") &&
obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"] !==
undefined
) {
sensorAddr =
obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"];
sensorValue =
obj["DataMapChangedObjectsAddressValue"][0]["Value"];
// if (sensorAddr === 1) {
// sensorValueIndex = (sensorValue / 16384) * 500;
// }
}
}
}
function onOpen(e) {
console.log("SSE connected");
}
function onError(e) {
// console.log(`[error] ${error.message}`);
if (e.eventPhase == EventSource.CLOSED) this.source.close();
if (e.target.readyState == EventSource.CLOSED) {
console.log("SSE Disconnected");
} else if (e.target.readyState == EventSource.CONNECTING) {
console.log("SSE Connecting ...");
}
}
function StartRetrieveLiveData() {
if (!!window.EventSource) {
this.source = new EventSource("/sse");
} else {
console.log("Your browser doesn't support SSE");
}
this.source.addEventListener("message", e => this.onMsg(e));
this.source.addEventListener("open", e => this.onOpen(e), false);
this.source.addEventListener("error", e => this.onError(e), false);
// Add here (only mozilla)
main();
// Add here
}
</script>
</html>
Note that when I used a public server the whole thing works just fine, but I used the remote server (the actual server) I get these error and the whole thing doesn't work as expected.
Would appreciate a solution for this.
I solved the problem so I am going to answer this.
Firstly, the document.querySelector('#canvas') should be removed to avoid creating two canvas, because I am calling the libraries in the . This was a silly mistake but I found it finally.
Secondly, the camera position was off and it wasn't really pointing at the car so nothing was shown on the screen. I tweaked the camera.position on the X, Y and Z axis to get it right.
There were bunches of other silly mistakes I found while carefully debugging the code, I am not an expert in the language yet so these mistakes serve as a learning experience for me.
The final working code is below:
let sensorValue = 0;
var toycar;
StartRetrieveLiveData();
var scene, renderer, camera;
var controls, keyboard = new KeyboardState();
var toycar;
function init() {
var width = window.innerWidth;
var height = window.innerHeight;
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setClearColor(0x626d73, 1);
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(10, width / height, 1, 10000);
camera.position.y = -150;
camera.lookAt(new THREE.Vector3(0, 0, 0));
var loader = new THREE.OBJMTLLoader();
loader.load('./toycar.obj', './toycar.mtl',
function (object) {
toycar = object;
toycar.rotateZ(10.99); //toycar.rotateZ(-10.99);
scene.add(toycar);
});
var gridXZ = new THREE.GridHelper(350000, 10000);
gridXZ.setColors(new THREE.Color(0xff0000), new THREE.Color(0xffffff));
scene.add(gridXZ);
var pointLight = new THREE.PointLight(0xffffff);
pointLight.position.set(350, 20, 5);
scene.add(pointLight);
var ambientLight = new THREE.AmbientLight(0x111111);
scene.add(ambientLight);
}
function animate() {
var angle = 0;
var speed = 0;
var pos = new THREE.Vector3(0, 0, 0);
var clock = new THREE.Clock();
var dt = clock.getDelta();
var dir = new THREE.Vector3(1, 0, 0);
dir.multiplyScalar(dt * speed);
dir.applyAxisAngle(new THREE.Vector3(0, 0, 0), 10);
pos.add(dir);
if (toycar != undefined) {
sensorValueIndex = ((sensorValue / 16384) * 50);
toycar.scale.set(0.1, 0.1, 0.1);
toycar.position.x = sensorValueIndex;
toycar.position.y = 0;
toycar.position.z = 0;
toycar.rotation.x = (angle + Math.PI);
}
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
function onMsg(event) {
var received_msg = event.data;
var obj = JSON.parse(JSON.parse(received_msg));
if (obj !== null) {
if (
obj.hasOwnProperty("DataMapChangedObjectsAddressValue") &&
obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"] !==
undefined
) {
let sensorAddr =
obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"];
sensorValue =
obj["DataMapChangedObjectsAddressValue"][0]["Value"];
if (sensorAddr === 1) {
sensorValueIndex = (sensorValue / 16384) * 10;
console.log(sensorValueIndex);
}
}
}
}
I will like to put each of the spheres in different canvas so that I could manipulate their positions easily with CSS.
Then hover in each h2 to show display them one by one
I have been advised to refactor the code with ES6 Classes for constructing every canvas with the sphere inside.
how can I acchive this?
https://jsfiddle.net/zhampu/q5j42pu9/9/
const v = new THREE.Vector3()
const sceneElements = []
const spheres = []
// Renderer
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('#c'),
antialias: true,
alpha: true
})
renderer.setClearColor(0x000000, 0)
renderer.setPixelRatio(window.devicePixelRatio)
// renderer.setSize(window.innerWidth, window.innerHeight)
// Scene & Camera
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)
// const camera = new THREE.PerspectiveCamera(70, 2, 1, 1000);
camera.position.z = 10
// Data Diagram
document.querySelectorAll('[data-diagram]').forEach((elem) => {
const sceneTexture = elem.dataset.diagram
const eachTexture = new THREE.TextureLoader().load(sceneTexture)
sceneElements.push(eachTexture)
return sceneElements
})
function makeBlob(sceneElements) {
for (var i = 0; i < sceneElements.length; i++) {
const sphere_geometry = new THREE.SphereBufferGeometry(1, 32, 16).toNonIndexed()
let material = new THREE.MeshBasicMaterial({
map: sceneElements[i]
})
const sphere = new THREE.Mesh(sphere_geometry, material)
const positionOfPiece = document.querySelectorAll('[data-diagram]')
sphere.position.x = 3 * i -3
// sphere.position.y = positionOfPiece.top
scene.add(sphere)
spheres.push(sphere)
}
}
makeBlob(sceneElements)
function animate() {
requestAnimationFrame(animate)
let time = performance.now() * 0.0005
resizeCanvasToDisplaySize()
for (let i = 0; i < spheres.length; i++) {
var sphere = spheres[i]
let k = 1
var positionAttribute = sphere.geometry.getAttribute('position')
for (let j = 0; j < positionAttribute.count; j++) {
v.fromBufferAttribute(positionAttribute, j)
v.normalize().multiplyScalar(1 + 0.3 * noise.perlin3(v.x * k + time, v.y * k, v.z * k))
positionAttribute.setXYZ(j, v.x, v.y, v.z)
}
positionAttribute.needsUpdate = true
sphere.rotation.y += 0.003
}
renderer.render(scene, camera)
}
animate()
function resizeCanvasToDisplaySize() {
const canvas = renderer.domElement
const width = canvas.clientWidth
const height = canvas.clientHeight
if (canvas.width !== width || canvas.height !== height) {
// you must pass false here or three.js sadly fights the browser
renderer.setSize(width, height, false)
camera.aspect = width / height
camera.updateProjectionMatrix()
// set render target sizes here
}
}
#c {
position: absolute;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
display: block;
z-index: -1;
}
*[data-diagram] {
display: inline-block;
width: 5em;
height: 3em;
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.115/build/three.js"></script>
<script src="https://www.fariskassim.com/stage/rebel9/teaf/blob/v4/js/perlin.js"></script>
<canvas id="c"></canvas>
<a class="pieces-list" href="" target="_self">
<h2>Publications</h2>
<span data-diagram="https://i.picsum.photos/id/1002/600/300.jpg"></span>
</a>
<a class="pieces-list" href="" target="_self">
<h2>Fashion</h2>
<span data-diagram="https://i.picsum.photos/id/1002/200/300.jpg"></span>
</a>
i m following this guide for the light Light in Threejs
and i already add some light in my scene.
Now i m try to add a light on the character of my game, but still dont work.
i use the same code of the guide changing just the position.set
const color = 0xFFFFFF;
const intensity = 1;
const light2 = new THREE.SpotLight(color, intensity,0,Math.PI/3);
light2.position.set(100,-5000,1000);
light2.target = lightTarget;
light2.castShadow = true;
const helper2 = new THREE.SpotLightHelper(light2);
and after i add in this way to my character
self.flame.add( helper2 );
self.flame.add(lightTarget);
self.flame.add(light2);
I added a helper too, but if I use just the helper in the scene , so if comment
self.flame.add(light2)
I see the position of the light in perfect way, when add the light the helper disappear (in other light don't happened) and the light go as her want.
Someone can help me?
The helpers have to be parented to the scene (or at least the SpotLightHelper does). You may or may not want to parent the target to the scene.
You also need to call helper.update for each helper
'use strict';
/* global THREE, dat */
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 45;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 100;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 10, 20);
const controls = new THREE.OrbitControls(camera, canvas);
controls.target.set(0, 5, 0);
controls.update();
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
{
const planeSize = 40;
const loader = new THREE.TextureLoader();
const texture = loader.load('https://threejsfundamentals.org/threejs/resources/images/checker.png');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.magFilter = THREE.NearestFilter;
const repeats = planeSize / 2;
texture.repeat.set(repeats, repeats);
const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
const planeMat = new THREE.MeshPhongMaterial({
map: texture,
side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(planeGeo, planeMat);
mesh.rotation.x = Math.PI * -.5;
scene.add(mesh);
}
const cubes = [];
let parent = scene;
{
const cubeSize = 1;
const cubeGeo = new THREE.BoxBufferGeometry(cubeSize, cubeSize, cubeSize);
const cubeMat = new THREE.MeshPhongMaterial({
color: '#8AC',
emissive: '#333',
});
for (let i = 0; i < 6; ++i) {
const mesh = new THREE.Mesh(cubeGeo, cubeMat);
mesh.position.set(1, 0, 0);
parent.add(mesh);
cubes.push(mesh);
parent = mesh;
}
}
cubes[0].position.set(-3, 7, 0);
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.SpotLight(color, intensity);
light.position.set(0, 0, 0);
light.target.position.set(0, -1, 0);
parent.add(light);
parent.add(light.target);
//scene.add(light.target);
const helper = new THREE.SpotLightHelper(light);
scene.add(helper);
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
for (const cube of cubes) {
cube.rotation.z = Math.sin(time) * .4;
}
light.angle = THREE.Math.lerp(
THREE.Math.degToRad(20),
THREE.Math.degToRad(80),
Math.sin(time * 0.77) * 0.5 + 0.5);
helper.update();
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
html, body {
margin: 0;
height: 100%;
}
#c {
width: 100%;
height: 100%;
display: block;
}
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/three.min.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/js/controls/OrbitControls.js"></script>
Im developing an web-app that is supposed to create a 3d model of a gravel pile
from points measured with a laser instrument with three.js. The only problem is the
creating a hull that supposed to be the surface of the pile that includes all points. I already made a pointswarm model with the points and tried to make a hull around it with ConvexBufferGeometry but not all points get included in the hull when using ConvexBufferGeometry. Can someone please point me in the right direction?
You can try to combine Three.js with Delaunator library for triangulation of your points to make a surface:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);
camera.position.setScalar(150);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
var canvas = renderer.domElement;
document.body.appendChild(canvas);
var controls = new THREE.OrbitControls(camera, canvas);
var light = new THREE.DirectionalLight(0xffffff, 1.5);
light.position.setScalar(100);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
var size = { x: 200, y: 200 };
var pointsCount = 1000;
var points3d = [];
for (let i = 0; i < pointsCount; i++) {
let x = THREE.Math.randFloatSpread(size.x);
let z = THREE.Math.randFloatSpread(size.y);
let y = noise.perlin2(x / size.x * 5, z / size.y * 5) * 50;
points3d.push(new THREE.Vector3(x, y, z));
}
var geom = new THREE.BufferGeometry().setFromPoints(points3d);
var cloud = new THREE.Points(
geom,
new THREE.PointsMaterial({ color: 0x99ccff, size: 2 })
);
scene.add(cloud);
// triangulate by [x, z]
var indexDelaunay = Delaunator.from(
points3d.map(v => {
return [v.x, v.z];
})
);
var meshIndex = []; // delaunay index => three.js index
for (let i = 0; i < indexDelaunay.triangles.length; i++){
meshIndex.push(indexDelaunay.triangles[i]);
}
geom.setIndex(meshIndex); // add three.js index to the existing geometry
geom.computeVertexNormals();
var mesh = new THREE.Mesh(
geom, // re-use the existing geometry
new THREE.MeshLambertMaterial({ color: "purple", wireframe: true })
);
scene.add(mesh);
var gui = new dat.GUI();
gui.add(mesh.material, "wireframe");
render();
function resize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resize(renderer)) {
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
html, body {
height: 100%;
margin: 0;
overflow: hidden;
font-family: Verdana;
}
canvas {
width: 100%;
height: 100%;
display; block;
}
#info{
position: absolute;
margin-left: 10px;
}
a{
color: yellow;
text-decoration: none;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.115.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.115.0/examples/js/controls/OrbitControls.js"></script>
<!-- https://github.com/mapbox/delaunator -->
<script src="https://unpkg.com/delaunator#3.0.2/delaunator.js"></script>
<script src="https://josephg.github.io/noisejs/perlin.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.3/dat.gui.min.js"></script>
<div id="info">
Delaunator<br>(triangulation)
</div>