Color based on mesh height Three.js - javascript

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>

Related

Three.js – Create half a ring and animate it

I've created a Ring and would like to have only half of it. And after that animate it, that it builds itself up from 0 to half.
var geometry = new THREE.RingGeometry(10, 9, 32);
var material = new THREE.MeshBasicMaterial({
color: 0xffff00,
side: THREE.DoubleSide,
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
How can I archive it? I'm new to three.js.
Use thetaStart and thetaLength to animate the half-ring.
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.jsdelivr.net/npm/three#0.118.3/build/three.module.js";
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
var grid = new THREE.GridHelper(10, 10);
grid.rotation.x = Math.PI * 0.5;
scene.add(grid);
var innerRadius = 1;
var outerRadius = 2;
// re-building geometry
var usualRingGeom = new THREE.RingBufferGeometry(innerRadius, outerRadius, 32, 1, 0, 1);
var usualRingMat = new THREE.MeshBasicMaterial({color: 0xffff00});
var usualRing = new THREE.Mesh(usualRingGeom, usualRingMat);
scene.add(usualRing);
var clock = new THREE.Clock();
renderer.setAnimationLoop(()=>{
let t = clock.getElapsedTime();
// re-building geometry
usualRingGeom = new THREE.RingBufferGeometry(innerRadius, outerRadius, 32, 1, 0, (Math.sin(t) * 0.5 + 0.5) * Math.PI);
usualRing.geometry.dispose();
usualRing.geometry = usualRingGeom;
renderer.render(scene, camera);
});
</script>
PS You also can achieve the same result without re-building a geometry. For that, you can bend a plane in js (changing vertices) or in shaders :)

Creating a cylinder with slanted bottom

I want to create a cylinder with slanted bottom shape in three.js.
I don't see any direct way to create such geometry in three.js. I tried to see if I can cut the cylinder by a slanted plane, but could not find such operation in the documentation. Can anybody suggest a way to create this?
You can operate with vertices as you want.
Just a simple concept:
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({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
var cylGeom = new THREE.CylinderBufferGeometry(1, 1, 5, 16);
var vertices = cylGeom.attributes.position;
// change upper vertices
var v3 = new THREE.Vector3(); // temp vector
for (let i = 0; i < vertices.count; i++) {
v3.fromBufferAttribute(vertices, i); // set the temp vector
v3.y = v3.y > 0 ? (v3.x * 0.5) + 2.5 : v3.y; // change position by condition and equation
vertices.setY(i, v3.y); // set Y-component of a vertex
}
var cylMat = new THREE.MeshLambertMaterial({
color: "aqua"
});
var cyl = new THREE.Mesh(cylGeom, cylMat);
scene.add(cyl);
renderer.setAnimationLoop(() => {
renderer.render(scene, camera)
});
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

BoxGeometry sides

I already asked a Question here: Add Thickness to faces
The core question is solved but i ran into another problem.
Before my walls were set on side:THREE.BackSide so that they didnt show when they faced the camera but now when they have a thickness that doesnt work anymore and i dont realy understand why.
Before:
Before
After: After
How can i make the thick walls behave like the Plane walls ?
A very rough concept of controlling the visibility of a wall (I've slightly changed translating and positioning of a geometry):
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 5, 5);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
scene.add(new THREE.GridHelper(10, 10));
var points = [
new THREE.Vector3(-2, 0, 2),
new THREE.Vector3(2, 0, 2),
new THREE.Vector3(2, 0, -2),
new THREE.Vector3(-2, 0, -2)
]
var walls = [];
points.forEach((p, idx, points) => {
let nextIdx = idx === points.length - 1 ? 0 : idx + 1;
buildWall(p, points[nextIdx], 2, 0.1);
});
function buildWall(pointStart, pointEnd, height, thickness) {
var boxW = pointEnd.clone().sub(pointStart).length();
var boxH = height;
var boxD = thickness;
var boxGeometry = new THREE.BoxGeometry(boxW, boxH, boxD);
boxGeometry.translate(0, boxH * 0.5, 0);
boxGeometry.rotateY(-Math.PI * 0.5);
var wall = new THREE.Mesh(boxGeometry, new THREE.MeshBasicMaterial({
color: "aqua",
wireframe: true
}));
wall.position.copy(pointStart).add(pointEnd).multiplyScalar(0.5);
wall.lookAt(pointEnd);
scene.add(wall);
walls.push(wall);
}
var currentPosition = new THREE.Vector3();
render();
function render() {
requestAnimationFrame(render);
walls.forEach(w => {
w.visible = currentPosition.copy(w.position).sub(camera.position).lengthSq() > camera.position.lengthSq();
})
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

create a 3D object by adding a default height javascript

I have this code which should create a 3D form. The idea is that I have whatever coordinates stored into a vector in the same plan to which I should add a default height in order to make it 3D. As you can see I am a beginner in programming and this is the first time I use ThreeJS so can you tell me what am I doing wrong? Honestly I have no clue and I would like to know if there is another way of adding the default height to my 2D vector coordinates in order to make it 3D without using ThreeJS. Thank you!
$(document).ready(function(){
function storeCoordinate(x, y, array) {
array.push(x);
array.push(y);
}
var coords = [];
var z=500;
storeCoordinate(3, 5, coords);
storeCoordinate(10, 100, coords);
storeCoordinate(30, 120, coords);
storeCoordinate(3, 5, coords);
for (var i = 0; i < coords.length; i+=2) {
var x = coords[i];
var y = coords[i+1];
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var shape = new THREE.Shape( coords );
ctx.moveTo(coords[i],coords[i+1]);
ctx.lineTo(coords[i+2],coords[i+3]);
ctx.stroke();
}
var render,mycanvas,scene,camera,renderer,light;
init();
animate();
function init(){
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 1, 1000 );
var extrudedGeometry = new THREE.ExtrudeGeometry(shape, {amount: 5, bevelEnabled: false});
var extrudedMesh = new THREE.Mesh(extrudedGeometry, new THREE.MeshPhongMaterial({color: 0xff0000}));
scene.add(extrudedMesh);
document.body.onmousemove = function(e){
extrudedMesh.rotation.z = e.pageX / 100;
extrudedMesh.rotation.x = e.pageY / 100;
}
//lights
dirLight = new THREE.DirectionalLight(0xffffff);
dirLight.intensity = .9;
dirLight.position.set(500, 140, 500);
dirLight.castShadow = true;
dirLight.shadowMapHeight = 2048
dirLight.shadowMapWidth = 2048
dirLight.shadowDarkness = .15
spotLight = new THREE.PointLight( 0xffffff );
spotLight.intensity = .5
spotLight.position.set( -500, 140, -500 );
camera.add( spotLight)
camera.add(dirLight);
lighthelper = new THREE.DirectionalLightHelper(dirLight, 20);
lighthelper.children[1].material.color.set(0,0,0)
lighthelper.visible = false;
scene.add(lighthelper);
ambientLight = new THREE.AmbientLight( 0x020202, 1 );
scene.add( ambientLight );
light = new THREE.PointLight(0xffffff);
light.position.set(-100,200,100);
scene.add(light);
renderer = new THREE.WebGLRenderer({canvas: mycanvas});
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.autoRotate = true;
controls.enableZoom = true;
controls.enablePan = true;
controls.rotateSpeed = 3.0;
controls.zoomSpeed = 1.0;
controls.panSpeed = 2.0;
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.minDistance = 1.1;
controls.maxDistance = 1000;
controls.keys = [65, 83, 68]; // [ rotateKey, zoomKey, panKey ]
}
function animate() {
window.requestAnimationFrame( animate );
render();
}
function render() {
renderer.render( scene, camera );
}
var loader = new THREE.OBJLoader();
});
Just an option of how you can do it, using THREE.ExtrudeGeometry():
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 3);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var grid = new THREE.GridHelper(5, 10, "white", "gray");
grid.geometry.rotateX(Math.PI * 0.5);
scene.add(grid);
var points = [
new THREE.Vector2(0, 1),
new THREE.Vector2(1, 1),
new THREE.Vector2(1, 0)
]
var shape = new THREE.Shape(points);
var extrudeGeom = new THREE.ExtrudeGeometry(shape, {
amount: 0.5,
bevelEnabled: false
});
var mesh = new THREE.Mesh(extrudeGeom, new THREE.MeshBasicMaterial({
color: "aqua",
wireframe: true
}));
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