three.js using points to make smoke effect - javascript

I want to make a smoke effect like this demo (Smoke) by using points. Now I have two problems.
At the beginning of the animation, all points get together and go up together like cloud.
the shape of the effect looks like a rectangular prism. How to make it looks like a cone (like the following picture)?
Can somebody please tell me how to fix these problems? Thanks!
let renderer, scene, camera;
let controls, stats;
// points
const particleCount = 500;
let points;
function createPoints() {
const geometry = new THREE.Geometry();
const texture = new THREE.TextureLoader().load('http://stemkoski.github.io/Three.js/images/smokeparticle.png');
let material = new THREE.PointsMaterial({
size: 15,
map: texture,
blending: THREE.AdditiveBlending,
depthWrite: false,
transparent: true,
color: 'rgb(30,30,30)'
});
const range = 10;
for (let i = 0; i < particleCount; i++) {
const x = THREE.Math.randInt(-range, range);
const y = THREE.Math.randInt(-range, range);
const z = THREE.Math.randInt(-range, range);
const point = new THREE.Vector3(x, y, z);
point.velocityX = THREE.Math.randFloat(-0.01, 0.01);
point.velocityY = THREE.Math.randFloat(0.1, 0.3);
geometry.vertices.push(point);
}
points = new THREE.Points(geometry, material);
scene.add(points);
}
function init() {
// scene
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x000000, 0.0008);
// camera
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set(0, 10, 170);
camera.lookAt(scene.position);
let axes = new THREE.AxesHelper(20);
scene.add(axes);
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// OrbitControls
controls = new THREE.OrbitControls( camera, renderer.domElement );
createPoints();
document.body.appendChild(renderer.domElement);
}
function pointsAnimation() {
points.geometry.vertices.forEach(function(v) {
v.y = v.y + v.velocityY;
v.x = v.x + v.velocityX;
if (v.y >= 100) v.y = 0;
});
points.geometry.verticesNeedUpdate = true;
}
function render() {
pointsAnimation();
requestAnimationFrame(render);
controls.update();
renderer.render(scene, camera);
}
window.addEventListener('resize', function() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
init();
render();
body {
margin: 0;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/104/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

You could simply set velocityX depending on point x, e.g. :
point.velocityX = THREE.Math.randFloat(0.0, 0.1) * Math.sign(x);
Don't forget to reset x position :
if (v.y >= 100) {
v.x = THREE.Math.randInt(-10, 10);
v.y = 0;
}

Related

Set 3d cube rotation origin

I have a simple 3d cube (BoxGeometry of 100, 100, 100) and I am trying to rotate it. If we call all 100x100x100 a tile - when I rotate it I can see it's overlapping the below tile.
(by changing color, now I totally understand the behaviour).
tl.to(this.cube4.rotation, 0.5, {z: -45* Math.PI/180});
[
What if I want to rotate it based on an anchor point of right bottom? So instead of overflowing inside the below tile, it will overflow that portion to above tile.
So it will look like the green example and not the red example:
The red example here is achieved by
tl.to(this.cube4.rotation, 0.5, {z: -45* Math.PI/180});
tl.to(this.cube4.position, 0.5, {x: 50 }, 0.5);
I am very new to three.js so if any terminology is wrong, please warn me
Add the ("red") cube to a THREE.Group, in that way that the rotation axis (the edge) is in the origin of the group. This means the cube has to be shifted by the half side length.
If you rotate the group object, then the cube (which is inside the group) will rotate around the edge and not around its center.
e.g.
var bbox = new THREE.Box3().setFromObject(cube);
cube.position.set(bbox.min.x, bbox.max.y, 0);
var pivot = new THREE.Group();
pivot.add(cube);
scene.add(pivot);
See also the answer to How to center a group of objects?, which uses this solution to rotate a group of objects.
(function onLoad() {
var camera, scene, renderer, orbitControls, pivot;
var rot = 0.02;
init();
animate();
function init() {
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({
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, 100);
camera.position.set(4, 1, 2);
//camera.lookAt( -1, 0, 0 );
loader = new THREE.TextureLoader();
loader.setCrossOrigin("");
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);
var ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
directionalLight.position.set(1,2,-1.5);
scene.add( directionalLight );
addGridHelper();
createModel();
}
function createModel() {
var material = new THREE.MeshPhongMaterial({color:'#80f080'});
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var cube1 = new THREE.Mesh(geometry, material);
cube1.position.set(0,-0.5,-0.5);
var cube2 = new THREE.Mesh(geometry, material);
cube2.position.set(0,0.5,-0.5);
var cube3 = new THREE.Mesh(geometry, material);
cube3.position.set(0,-0.5,0.5);
var material2 = new THREE.MeshPhongMaterial({color:'#f08080'});
var cube4 = new THREE.Mesh(geometry, material2);
var bbox = new THREE.Box3().setFromObject(cube4);
cube4.position.set(bbox.min.x, bbox.max.y, 0);
pivot = new THREE.Group();
pivot.add(cube4);
pivot.position.set(-bbox.min.x, 0.5-bbox.max.y, 0.5);
scene.add(cube1);
scene.add(cube2);
scene.add(cube3);
scene.add(pivot);
}
function addGridHelper() {
var helper = new THREE.GridHelper(100, 100);
helper.material.opacity = 0.25;
helper.material.transparent = true;
scene.add(helper);
var axis = new THREE.AxesHelper(1000);
scene.add(axis);
}
function animate() {
requestAnimationFrame(animate);
orbitControls.update();
pivot.rotation.z += rot;
if (pivot.rotation.z > 0.0 || pivot.rotation.z < -Math.PI/2) rot *= -1;
render();
}
function render() {
renderer.render(scene, camera);
}
})();
<!--script src="https://threejs.org/build/three.js"></!--script-->
<script src="https://rawcdn.githack.com/mrdoob/three.js/r124/build/three.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r124/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.js"></script>
<div id="container"></div>
From the first image, it appears that the pivot of your red tile is at its center.
For the rotation you want, you would ideally change the pivot to the lower right of the cube. This is impossible without modifying the geometry of the cube.
BUT a simple trick is to create an empty node at that pivot point, parent your cube to that empty, and apply your rotation to the empty. (Don't forget to remove your translation, you don't need it anymore)
Here is some pseudo code, assuming your red box is centered at (0,0,0) and has a width and height of 100:
// create an empty node at desired rotation pivot
var empty = new Object3D or group
empty.position = (50, -50, 0)
// parent your cube to the empty
var cube = your box
empty.add(cube)
// you may need to change the local position of your cube to bring it back to its global position of (0,0,0)
cube.position = (-50, 50, 0)
rotate empty by 45°
I think you can get the bounds of the rotated object like this:
bounds = new THREE.Box3().setFromObject( theRedObject )
Then reposition the object.y based on its bounds.min.y
let scene, camera, controls, ambient, point, loader, renderer, container, stats;
const targetRotation = 0;
const targetRotationOnMouseDown = 0;
const mouseX = 0;
const mouseXOnMouseDown = 0;
const windowHalfX = window.innerWidth / 2;
const windowHalfY = window.innerHeight / 2;
init();
animate();
var box, b1, b2, b3;
function init() {
// Create a scene which will hold all our meshes to be rendered
scene = new THREE.Scene();
// Create and position a camera
camera = new THREE.PerspectiveCamera(
60, // Field of view
window.innerWidth / window.innerHeight, // Aspect ratio
/*window.innerWidth / -8,
window.innerWidth / 8,
window.innerHeight / 8,
window.innerHeight / -8,
*/
0.1, // Near clipping pane
1000 // Far clipping pane
);
scene.add(camera)
// Reposition the camera
camera.position.set(0, 5, 10);
// Point the camera at a given coordinate
camera.lookAt(new THREE.Vector3(0, 0, 0));
// Add orbit control
controls = new THREE.OrbitControls(camera);
controls.target.set(0, -0.5, 0);
controls.update();
// Add an ambient lights
ambient = new THREE.AmbientLight(0xffffff, 0.2);
scene.add(ambient);
// Add a point light that will cast shadows
point = new THREE.PointLight(0xffffff, 1);
point.position.set(25, 50, 25);
point.castShadow = true;
point.shadow.mapSize.width = 1024;
point.shadow.mapSize.height = 1024;
scene.add(point);
group = new THREE.Group();
group.position.y = 0;
scene.add(group);
rotationAnchor = new THREE.Object3D()
group.add(rotationAnchor);
box = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshStandardMaterial({
color: 'grey'
}))
b1 = box.clone();
b2 = box.clone();
b3 = box.clone();
b3.material = b3.material.clone()
b3.material.color.set('red')
group.add(box);
group.add(b1);
b1.position.y += 1
group.add(b2);
b2.position.z += 1
rotationAnchor.add(b3);
rotationAnchor.position.set(0.5, 0.5, 1.5)
b3.position.set(-.5, -.5, -.5)
// Create a renderer
renderer = new THREE.WebGLRenderer({
antialias: true
});
// Set size
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Set color
renderer.setClearColor(0xf8a5c2);
renderer.gammaOutput = true;
// Enable shadow mapping
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Append to the document
container = document.createElement("div");
document.body.appendChild(container);
document.body.appendChild(renderer.domElement);
// Add resize listener
window.addEventListener("resize", onWindowResize, false);
// Enable FPS stats
stats = new Stats();
container.appendChild(stats.dom);
var gui = new dat.GUI({
height: 5 * 32 - 1
});
let params = {
'test': 4,
'bevelThickness': 1,
'bevelSize': 1.5,
'bevelSegments': 3
}
gui.add(params, 'test', 0, 10).onChange(val => {
test = val
})
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
rotationAnchor.rotation.z = (Math.cos(performance.now() * 0.001) * Math.PI * 0.25) + (Math.PI * 1.25)
requestAnimationFrame(animate);
// Re-render scene
renderer.render(scene, camera);
// Update stats
stats.update();
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.2/dat.gui.min.js"></script>

Zoom in to the object based on mouse pointer

Here I'm trying to zoom in the object(say cube) based on the on mouse pointer position. Here I googled and got a idea that it can be achieved in D3 JS and also it can achieved by capturing the mouse pointer 3D point and passing it in the mouse wheel function.
Here's the fiddle https://jsfiddle.net/fpt9hswo/
var scene, renderer, camera;
var cube;
var controls;
var containerWidth = window.innerWidth,
containerHeight = window.innerHeight;
init();
animate();
function init() {
configureRenderer();
scene = new THREE.Scene();
configureCube();
configureCamera();
configureLight();
configureControls();
fitAll();
}
function configureRenderer() {
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(containerWidth, containerHeight);
document.body.appendChild(renderer.domElement);
}
function configureCube() {
var cubeGeometry = new THREE.BoxGeometry(20, 20, 20);
var cubeMaterial = new THREE.MeshLambertMaterial({
color: 0xff0000
});
cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(50, 0, 0);
scene.add(cube);
}
function configureCamera() {
camera = new THREE.PerspectiveCamera(45, containerWidth / containerHeight, 1, 1000);
camera.position.set(0, 160, 400);
camera.lookAt(scene);
}
function configureLight() {
pointLight = new THREE.PointLight(0xffffff, 1.0, 100000);
pointLight.position.set(0, 300, 200);
scene.add(pointLight);
}
function configureControls() {
controls = new THREE.TrackballControls(camera, renderer.domElement);
// configuration of controls
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 5.0;
controls.panSpeed = 2.0;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0;
}
function fitAll() {
// Calculate bounding box of the whole scene
var boundingBoxOfNode = new THREE.Box3().setFromObject(scene),
centerOfGravity = boundingBoxOfNode.getCenter();
/************* CAMERA *************************/
camera.position.addVectors(camera.position, centerOfGravity);
camera.lookAt(centerOfGravity);
//new camera positions will be set here
//Eg: camera.position.set(newCamera.x,newCamera.y,newCamera.z);
//Similarly new camera rotation and quaternion coordinates will be set
//Eg: camera.rotation.set(newCamera.rotatex,newCamera.rotatey,newCamera.rotatez);
//Eg: camera.quaternion.set(newCamera.qw,newCamera.qx,newCamera.qy,newCamera.qz);
/************* CONTROLS *************************/
controls.target.set(centerOfGravity.x, centerOfGravity.y, centerOfGravity.z);
//new controls.target values will be set here
//Eg: controls.target.set(newCamera.targetx,newCamera.targety,newCamera.targetz);
}
function animate() {
controls.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
Thanks in advance
To do what you want you've to implement your own mouse wheel event and you've to disable the default zoom of THREE.TrackballControls:
controls = new THREE.TrackballControls(camera, renderer.domElement);
//...
controls.zoomSpeed = 0.0;
Add a wheel event:
e.g.
renderer.domElement.addEventListener("wheel", event => {
const delta = event.deltaY;
// [...]
}
Zooming in perspective projection can be achieved, by shifting the camera position in the depth of the world.
If you want to zoom to a point, this can be achieved by moving the camera along a ray, from the camera position through the cursor (mouse) position and to move the target position in parallel.
A point on the ray from the camera to the cursor in normalized device space can be found with ease. In normalized device space all coordinates are in range [-1, 1] and all points with the same x and y coordinate are at the same ray. If the z coordinate is -1, the the point is on the near plane and if z is 1 then the point is on the far plane.
e.g. NDC point on the far plane and on a ray through the cursor:
let x = 2 * event.clientX / window.innerWidth - 1;
let y = 1 - 2 * event.clientY / window.innerHeight;
let cursorpos = new THREE.Vector3(x, y, 1);
This point in normalized device space can be transformed to a point in world space, by THREE.Vector3.unproject(). The parameter to the function has to be the THREE.Camera which defines the view and projection:
cursorpos.unproject(camera);
The direction for the movement of the camera is the normalized direction from the camera position to the cursor position in world space:
let dir = new THREE.Vector3().copy(cursorpos).sub(camera.position).normalize();
Calculate the movement dependent on the direction and the mouse wheel delta and update the camera and THREE.TrackballControls:
let shift = new THREE.Vector3().copy(dir).multiplyScalar(delta * 0.1);
camera.position.add(shift);
controls.position0.add(shift);
controls.target.add(shift);
See the example, where I applied the suggestions to the code of the question:
var scene, renderer, camera;
var cube;
var controls;
var containerWidth = window.innerWidth,
containerHeight = window.innerHeight;
init();
animate();
function init() {
configureRenderer();
scene = new THREE.Scene();
configureCube();
configureCamera();
configureLight();
configureControls();
}
function configureRenderer() {
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(containerWidth, containerHeight);
document.body.appendChild(renderer.domElement);
window.onresize = function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
if (controls)
controls.handleResize();
}
renderer.domElement.addEventListener("wheel", event => {
const delta = event.deltaY;
let x = 2 * event.clientX / window.innerWidth - 1;
let y = 1 - 2 * event.clientY / window.innerHeight;
let cursorpos = new THREE.Vector3(x, y, 1);
cursorpos.unproject(camera);
let dir = new THREE.Vector3().copy(cursorpos).sub(camera.position).normalize();
let shift = new THREE.Vector3().copy(dir).multiplyScalar(delta * 0.1);
camera.position.add(shift);
controls.position0.add(shift);
controls.target.add(shift);
});
}
function configureCube() {
var cubeGeometry = new THREE.BoxGeometry(20, 20, 20);
var cubeMaterial = new THREE.MeshLambertMaterial({
color: 0xff0000
});
cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.set(50, 0, 0);
scene.add(cube);
}
function configureCamera() {
camera = new THREE.PerspectiveCamera(45, containerWidth / containerHeight, 1, 1000);
camera.position.set(0, 160, 400);
camera.lookAt(scene);
}
function configureLight() {
pointLight = new THREE.PointLight(0xffffff, 1.0, 100000);
pointLight.position.set(0, 300, 200);
scene.add(pointLight);
}
function configureControls() {
controls = new THREE.TrackballControls(camera, renderer.domElement);
// configuration of controls
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 0.0;
controls.panSpeed = 2.0;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0;
}
function animate() {
controls.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>

Preserve constant size regardless of perspective in Three.js

How can I preserve constant size of meshes regardless of perspective using Three.js?
Lets assume I have multiple meshes of the same size. I want them to always have the same on screen size. I also have to use perspective camera.
I have found some related answers, but seems that I miss something:
First approach is to use Euclidean distance to objects from
camera and scale them respectively every animation frame.
Three JS Keep Label Size On Zoom
I have tried to modify jsfiddle given in the answer to apply scale to meshes instead of sprites, but that doesn't work for me. The result looks as follows https://jsfiddle.net/a2ogz9vx/258/
var camera, scene, renderer, controls;
var planets = [];
var timestamp = 0;
var scaleVector = new THREE.Vector3();
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 100, 100);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
var createPlanet = function(name, radius, orbit, speed) {
var geom = new THREE.SphereGeometry(radius, 32, 16);
var mat = new THREE.MeshBasicMaterial({
color: Math.random() * 0xFFFFFF,
});
var planet = new THREE.Mesh(geom, mat);
planet.userData.orbit = orbit;
planet.userData.speed = speed;
var canvas = document.createElement('canvas');
canvas.width = 256;
canvas.height = 256;
var tex = new THREE.Texture(canvas);
tex.needsUpdate = true;
var spriteMat = new THREE.SpriteMaterial({
map: tex
});
var sprite = new THREE.Sprite(spriteMat);
planet.add(sprite);
planets.push(planet);
scene.add(planet);
};
createPlanet("One", 11, -10, 5);
createPlanet("Two", 11, 5, 5);
createPlanet("Three", 11, 10, 5);
}
function animate() {
requestAnimationFrame(animate);
planets.forEach(function(planet) {
var scaleFactor = 100;
var scale = scaleVector.subVectors(planet.position, camera.position).length() / scaleFactor;
planet.scale.set(scale, scale, scale);
var orbit = planet.userData.orbit;
var speed = planet.userData.speed;
planet.position.x = speed * orbit;
planet.position.z = speed * orbit;
});
render();
}
function render() {
renderer.render(scene, camera);
}
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>
Second approach is to use on screen width calculation. https://stackoverflow.com/a/13351534/8465699
Result also doesn't look right https://jsfiddle.net/a2ogz9vx/260/
var camera, scene, renderer, controls;
var planets = [];
var timestamp = 0;
var scaleVector = new THREE.Vector3();
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 100, 100);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
var createPlanet = function(name, radius, orbit, speed) {
var geom = new THREE.SphereGeometry(radius, 32, 16);
var mat = new THREE.MeshBasicMaterial({
color: Math.random() * 0xFFFFFF,
});
var planet = new THREE.Mesh(geom, mat);
planet.userData.orbit = orbit;
planet.userData.speed = speed;
var canvas = document.createElement('canvas');
canvas.width = 256;
canvas.height = 256;
var tex = new THREE.Texture(canvas);
tex.needsUpdate = true;
var spriteMat = new THREE.SpriteMaterial({
map: tex
});
var sprite = new THREE.Sprite(spriteMat);
planet.add(sprite);
planets.push(planet);
scene.add(planet);
};
createPlanet("One", 11, -10, 5);
createPlanet("Two", 11, 0, 5);
createPlanet("Three", 11, 10, 5);
}
function animate() {
requestAnimationFrame(animate);
planets.forEach(function(planet) {
const dist = planet.position.distanceTo(camera.position);
const vFOV = THREE.Math.degToRad(camera.fov);
const size = 2 * Math.tan(vFOV / 2) * dist;
const scaleFactor = 130;
const scale = size / scaleFactor;
planet.scale.set(scale, scale, scale);
var orbit = planet.userData.orbit;
var speed = planet.userData.speed;
planet.position.x = speed * orbit;
planet.position.z = speed * orbit;
});
render();
}
function render() {
renderer.render(scene, camera);
}
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>
Any suggestions how to fix the code or other approaches are welcome!

Color based on mesh height Three.js

I am loading in an STL file with the STLLoader() in Three.js and am transforming it into a mesh. Now, I would like to color each cube of my mesh based on its height, as in the image attached here screenshot-color-by-height. Is this possible within Three.js and if so, what would be the best approach? The actual model is here:
https://casagroupproject.github.io/subpage1.html
Just a concept of how you can make it with colors of vertices:
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();
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(10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
var planeGeom = new THREE.PlaneBufferGeometry(10, 10, 10, 10);
planeGeom.rotateX(-Math.PI * 0.5);
var yMin = 0;
var yMax = 2;
var colors = [];
for (let i = 0; i < planeGeom.attributes.position.count; i++) {
let yVal = THREE.Math.randInt(yMin, yMax);
let yNorm = (yVal - yMin) / (yMax - yMin);
planeGeom.attributes.position.setY(i, yVal);
colors.push(yNorm, yNorm, 1);
}
planeGeom.addAttribute('color', new THREE.BufferAttribute(new Float32Array(colors), 3));
planeGeom.computeVertexNormals();
var mesh = new THREE.Mesh(planeGeom, new THREE.MeshStandardMaterial({
vertexColors: THREE.VertexColors
}));
scene.add(mesh)
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>

ThreeJS - Extrude ParametricGeometry

Is there any way to use the ExtrudeGeometry with the ParametricGeometry?
Like this:
function exampleGeometryF(u,v){
var x = -(width/2) + width * u;
var y = -(height/2) + height *v;
var z = (Math.sin(u*Math.PI))* -20;
return new THREE.Vector3(x,y,z);
}
let parametricGeometry = new THREE.ParametricGeometry(exampleGeometryF, 100, 100);
let extrudedGeometry = new THREE.ExtrudeGeometry(parametricGeometry, {amount:10, ...});
So the parametricGeometry in this Example describes a plane like Geometry. Now I want to give this Geometry a depth.
Workarounds are welcome!
Specifically for a plane-like geometry with some "depth", you can deform a box geometry:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.setScalar(3);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var boxGeom = new THREE.BoxGeometry(2, 2, 3, 10, 10, 1);
boxGeom.vertices.forEach(v => {
v.z += Math.cos(v.x * 2) * Math.sin(v.y * 2) * 0.125;
});
var deformed = new THREE.Mesh(boxGeom, new THREE.MeshBasicMaterial({
color: "aqua",
wireframe: true
}));
scene.add(deformed);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/90/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Categories