THREE.js particles not showing up inside a shape - javascript

I've been trying to modify this demo. Currently the particles are placed in a text geometry, my end goal here is opposite. I'd like to:
Replace the text geometries with a box, cone and sphere.
Replace the particles with numbers.
So basically, have the numbers placed inside one of the shapes and animate the particles to form the next shape with a delay.
First, I tried changing the shapes, leaving the particles and everything else as is. However, for some reason the particles aren't showing up. I'm not sure why the particles aren't rendered? Console logs no errors.
Also, what would be the fastest way to have numbers as particles? It'd be great if someone could point me in the right direction. Thank you!
Below is the modified code:
// Options
const shapes = [{
"geoCode": new THREE.ConeGeometry(25, 50, 30),
"color": 0x11659C,
},
{
"geoCode": new THREE.SphereGeometry(25, 33, 33),
"color": 0x8F3985,
},
{
"geoCode": new THREE.BoxGeometry(50, 50, 50),
"color": 0x029894,
}
],
triggers = document.getElementsByTagName('span'),
particleCount = 1000,
particleSize = .3,
defaultAnimationSpeed = 1,
morphAnimationSpeed = 18,
color = '#FFFFFF';
// Renderer
const renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Ensure Full Screen on Resize
function fullScreen() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', fullScreen, false)
// Scene
const scene = new THREE.Scene();
// Camera and position
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.y = -45;
camera.position.z = 45;
// Lighting
const light = new THREE.AmbientLight(0xFFFFFF, 1);
scene.add(light);
// Particle Vars
const particles = new THREE.Geometry();
const pMaterial = new THREE.PointsMaterial({
size: particleSize,
});
// Texts
const loader = new THREE.FontLoader();
const typeface = 'https://dl.dropboxusercontent.com/s/bkqic142ik0zjed/swiss_black_cond.json?';
//CONTINUE
loader.load(typeface, (font) => {
Array.from(shapes).forEach((shape, idx) => {
shapes[idx].geometry = shapes[idx].geoCode;
const material = new THREE.MeshLambertMaterial({
color: shapes[idx].color,
opacity: .5,
transparent: true,
wireframe: true
});
const mesh = new THREE.Mesh(shapes[idx].geometry, material);
//THREE.GeometryUtils.center(shapes[idx].geometry)
scene.add(mesh);
shapes[idx].particles = new THREE.Geometry();
shapes[idx].points = THREE.GeometryUtils.randomPointsInGeometry(shapes[idx].geometry, particleCount);
createVertices(shapes[idx].particles, shapes[idx].points)
enableTrigger(shape, idx, triggers[idx]);
});
});
// Particles
for (var i = 0; i < shapes; i++) {
const vertex = new THREE.Vector3();
vertex.x = 0;
vertex.y = 0;
vertex.z = 0;
particles.vertices.push(vertex);
}
function createVertices(emptyArray, points) {
for (var p = 0; p < particleCount; p++) {
const vertex = new THREE.Vector3();
vertex.x = points[p]['x'];
vertex.y = points[p]['y'];
vertex.z = points[p]['z'];
emptyArray.vertices.push(vertex);
}
}
function enableTrigger(trigger, idx, el) {
el.setAttribute('data-disabled', false);
el.addEventListener('click', () => {
morphTo(shapes[idx].particles, el.dataset.color);
})
if (idx == 0) {
morphTo(shapes[idx].particles, el.dataset.color);
}
}
const particleSystem = new THREE.Points(
particles,
pMaterial
);
particleSystem.sortParticles = true;
// Add the particles to the scene
scene.add(particleSystem);
// Animate
const normalSpeed = (defaultAnimationSpeed / 100),
fullSpeed = (morphAnimationSpeed / 100)
let animationVars = {
speed: normalSpeed,
color: color,
rotation: 100
}
function animate() {
particleSystem.rotation.y += animationVars.speed;
particles.verticesNeedUpdate = true;
camera.position.z = animationVars.rotation;
camera.position.y = animationVars.rotation;
camera.lookAt(scene.position);
particleSystem.material.color = new THREE.Color(animationVars.color);
window.requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
function morphTo(newParticles, color = '#FFFFFF') {
TweenMax.to(animationVars, 2, {
ease: Linear.easeNone,
color: color
});
particleSystem.material.color.setHex(color);
for (const i = 0; i < particles.vertices.length; i++) {
TweenMax.to(particles.vertices[i], 2, {
ease: Elastic.easeOut.config(0.1, .3),
x: newParticles.vertices[i].x,
y: newParticles.vertices[i].y,
z: newParticles.vertices[i].z
})
}
}
body {
font-family: 'Titillium Web', sans-serif;
margin: 0;
overflow: hidden;
}
.triggers {
bottom: 20px;
color: white;
left: 50%;
position: absolute;
text-align: center;
transform: translateX(-50%);
width: 100%;
z-index: 10;
}
.triggers span {
cursor: pointer;
display: inline-block;
font-size: 14px;
margin: 0 20px;
padding: 2px 4px;
transition: opacity 0.5s, color 0.5s;
}
.triggers span[data-disabled="true"] {
opacity: 0.3;
pointer-events: none;
}
.triggers span:hover {
color: red;
}
<div class="triggers">
<span data-disabled="true" data-color="#3D8CD0">CLICK</span>
<span data-disabled="true" data-color="#D32A7B">TO</span>
<span data-disabled="true" data-color="#2AD37A">SWITCH</span>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js" type="text/javascript"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/605067/GeometryUtils.js" type="text/javascript"></script>
EDIT: Particles are now rendered, the updated code is here --> Fiddle

Apologies, I was actually able to fix the particles not rendering. I was iterating over the shapes instead of the particleCount.
// Particles
for (var i = 0; i < shapes; i++) {
^^^^^^
let vertex = new THREE.Vector3();
vertex.x = 0;
vertex.y = 0;
vertex.z = 0;
particles.vertices.push(vertex);
}
Below is the updated code that loads the particles.
// Options
const shapes = [{
"geoCode": new THREE.ConeGeometry(25, 50, 30),
"color": 0x11659C,
},
{
"geoCode": new THREE.SphereGeometry(25, 33, 33),
"color": 0x8F3985,
},
{
"geoCode": new THREE.BoxGeometry(50, 50, 50),
"color": 0x029894,
}
],
triggers = document.getElementsByTagName('span'),
particleCount = 1000,
particleSize = 3,
defaultAnimationSpeed = 1,
morphAnimationSpeed = 18,
color = '#FFFFFF';
// Renderer
const renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Ensure Full Screen on Resize
function fullScreen() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', fullScreen, false)
// Scene
const scene = new THREE.Scene();
// Camera and position
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.y = -45;
camera.position.z = 45;
// Lighting
const light = new THREE.AmbientLight(0xFFFFFF, 1);
scene.add(light);
// Particle Vars
const particles = new THREE.Geometry();
const pMaterial = new THREE.PointsMaterial({
size: particleSize,
});
// Texts
const loader = new THREE.FontLoader();
const typeface = 'https://dl.dropboxusercontent.com/s/bkqic142ik0zjed/swiss_black_cond.json?';
//CONTINUE
loader.load(typeface, (font) => {
Array.from(shapes).forEach((shape, idx) => {
shapes[idx].geometry = shapes[idx].geoCode;
const material = new THREE.MeshLambertMaterial({
color: shapes[idx].color,
opacity: .5,
transparent: true,
wireframe: true
});
const mesh = new THREE.Mesh(shapes[idx].geometry, material);
//THREE.GeometryUtils.center(shapes[idx].geometry)
scene.add(mesh);
shapes[idx].particles = new THREE.Geometry();
shapes[idx].points = THREE.GeometryUtils.randomPointsInGeometry(shapes[idx].geometry, particleCount);
createVertices(shapes[idx].particles, shapes[idx].points)
enableTrigger(shape, idx, triggers[idx]);
});
});
// Particles
for (var i = 0; i < particleCount; i++) {
const vertex = new THREE.Vector3();
vertex.x = 0;
vertex.y = 0;
vertex.z = 0;
particles.vertices.push(vertex);
}
function createVertices(emptyArray, points) {
for (var p = 0; p < particleCount; p++) {
const vertex = new THREE.Vector3();
vertex.x = points[p]['x'];
vertex.y = points[p]['y'];
vertex.z = points[p]['z'];
emptyArray.vertices.push(vertex);
}
}
function enableTrigger(trigger, idx, el) {
el.setAttribute('data-disabled', false);
el.addEventListener('click', () => {
morphTo(shapes[idx].particles, el.dataset.color);
})
if (idx == 0) {
morphTo(shapes[idx].particles, el.dataset.color);
}
}
let particleSystem = new THREE.Points(
particles,
pMaterial
);
particleSystem.sortParticles = true;
// Add the particles to the scene
scene.add(particleSystem);
// Animate
const normalSpeed = (defaultAnimationSpeed / 100),
fullSpeed = (morphAnimationSpeed / 100)
let animationVars = {
speed: normalSpeed,
color: color,
rotation: 100
}
function animate() {
particleSystem.rotation.y += animationVars.speed;
particles.verticesNeedUpdate = true;
camera.position.z = animationVars.rotation;
camera.position.y = animationVars.rotation;
camera.lookAt(scene.position);
particleSystem.material.color = new THREE.Color(animationVars.color);
window.requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
function morphTo(newParticles, color = '#FFFFFF') {
TweenMax.to(animationVars, 2, {
ease: Linear.easeNone,
color: color
});
particleSystem.material.color.setHex(color);
for (let i = 0; i < particles.vertices.length; i++) {
TweenMax.to(particles.vertices[i], 2, {
ease: Elastic.easeOut.config(0.1, .3),
x: newParticles.vertices[i].x,
y: newParticles.vertices[i].y,
z: newParticles.vertices[i].z
})
}
}
body {
font-family: 'Titillium Web', sans-serif;
margin: 0;
overflow: hidden;
}
.triggers {
bottom: 20px;
color: white;
left: 50%;
position: absolute;
text-align: center;
transform: translateX(-50%);
width: 100%;
z-index: 10;
}
.triggers span {
cursor: pointer;
display: inline-block;
font-size: 14px;
margin: 0 20px;
padding: 2px 4px;
transition: opacity 0.5s, color 0.5s;
}
.triggers span[data-disabled="true"] {
opacity: 0.3;
pointer-events: none;
}
.triggers span:hover {
color: red;
}
<div class="triggers">
<span data-disabled="true" data-color="#3D8CD0">CLICK</span>
<span data-disabled="true" data-color="#D32A7B">TO</span>
<span data-disabled="true" data-color="#2AD37A">SWITCH</span>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js" type="text/javascript"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/605067/GeometryUtils.js" type="text/javascript"></script>
Note: This post only has a solution for particles not rendering. I will accept the post that answers how I should go about replacing the particles with a number.

Related

Three.js: How to add 3D primitives to CSS3DRenderer scene in specific case?

This is the code:
"use strict";
var OrbitControls = THREE.OrbitControls,
CSS3DRenderer = THREE.CSS3DRenderer,
CSS3DObject = THREE.CSS3DObject,
Scene = THREE.Scene,
PerspectiveCamera = THREE.PerspectiveCamera,
Mesh = THREE.Mesh,
PlaneGeometry = THREE.PlaneGeometry,
MeshPhongMaterial = THREE.MeshPhongMaterial,
Color = THREE.Color,
DoubleSide = THREE.DoubleSide,
NoBlending = THREE.NoBlending,
WebGLRenderer = THREE.WebGLRenderer,
MeshBasicMaterial = THREE.MeshBasicMaterial;
var CSS3DDemo = /** #class */ (function() {
function CSS3DDemo() {
this.scene = new Scene();
this.camera = new PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 500);
this.webGLRenderer = new WebGLRenderer();
this.css3DRenderer = new CSS3DRenderer();
this.controls = new OrbitControls(this.camera, this.css3DRenderer.domElement);
this.controls.autoRotate = true;
this.camera.position.set(0, 0, 20);
this.webGLRenderer.setSize(window.innerWidth, window.innerHeight);
this.webGLRenderer.setClearColor(0xFFFFFF);
this.css3DRenderer.setSize(window.innerWidth, window.innerHeight);
this.css3DRenderer.domElement.style.top = '0px';
this.css3DRenderer.domElement.style.left = '0px';
this.css3DRenderer.domElement.style.position = 'absolute';
var div = window.document.createElement('img');
div.style.width = '160px';
div.style.height = 'auto';
div.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2e/1-month-old_kitten_42.jpg/2880px-1-month-old_kitten_42.jpg';
var object = new CSS3DObject(div);
object.position.set(0, 0, 0);
object.scale.set(1 / 16, 1 / 16, 1 / 16);
this.scene.add(object);
var planeGeometry = new PlaneGeometry(10, 10);
this.scene.add(this.camera);
document.getElementById("content").appendChild(this.webGLRenderer.domElement);
document.getElementById("content").appendChild(this.css3DRenderer.domElement);
this.render();
}
CSS3DDemo.prototype.render = function() {
var _this = this;
window.requestAnimationFrame(function() {
return _this.render();
});
this.css3DRenderer.render(this.scene, this.camera);
this.webGLRenderer.render(this.scene, this.camera);
this.controls.update();
};
return CSS3DDemo;
}());
new CSS3DDemo();
html,
body {
width: 100vw;
margin: 0;
height: 100vh;
padding: 0;
overflow: hidden;
border: 0;
}
#content {
width: 100%;
height: 100%;
overflow: hidden;
}
<div id="content"></div>
<script src='https://gitcdn.xyz/repo/mrdoob/three.js/dev/build/three.min.js'></script>
<script src='https://gitcdn.xyz/repo/mrdoob/three.js/dev/examples/js/controls/OrbitControls.js'></script>
<script src='https://gitcdn.xyz/repo/mrdoob/three.js/dev/examples/js/renderers/CSS3DRenderer.js'></script>
Now I would like to add a torus with MeshBasicMaterial.
I tried to add something like that:
const geometry = new THREE.TorusGeometry( 10, 3, 16, 100 );
const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
const torus = new THREE.Mesh( geometry, material );
torus.position.set(0, 0, 0);
scene.add( torus );
Unfortunately, it doesn't work. I also don't know if it could work theoretically.
Could somebody help me? I would be very happy! :)
If I replace scene with this.scene it seems to work just fine. Notice however that the combination of WebGL rendered 3D objects and HTML elements is problematic in some cases since depth testing does not work across both primitive types.
With the current setup, the image will always be rendered on top of the torus.
"use strict";
var OrbitControls = THREE.OrbitControls,
CSS3DRenderer = THREE.CSS3DRenderer,
CSS3DObject = THREE.CSS3DObject,
Scene = THREE.Scene,
PerspectiveCamera = THREE.PerspectiveCamera,
Mesh = THREE.Mesh,
PlaneGeometry = THREE.PlaneGeometry,
MeshPhongMaterial = THREE.MeshPhongMaterial,
Color = THREE.Color,
DoubleSide = THREE.DoubleSide,
NoBlending = THREE.NoBlending,
WebGLRenderer = THREE.WebGLRenderer,
MeshBasicMaterial = THREE.MeshBasicMaterial;
var CSS3DDemo = /** #class */ (function() {
function CSS3DDemo() {
this.scene = new Scene();
this.camera = new PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 500);
this.webGLRenderer = new WebGLRenderer();
this.css3DRenderer = new CSS3DRenderer();
this.controls = new OrbitControls(this.camera, this.css3DRenderer.domElement);
this.controls.autoRotate = true;
this.camera.position.set(0, 0, 20);
this.webGLRenderer.setSize(window.innerWidth, window.innerHeight);
this.webGLRenderer.setClearColor(0xFFFFFF);
this.css3DRenderer.setSize(window.innerWidth, window.innerHeight);
this.css3DRenderer.domElement.style.top = '0px';
this.css3DRenderer.domElement.style.left = '0px';
this.css3DRenderer.domElement.style.position = 'absolute';
var div = window.document.createElement('img');
div.style.width = '160px';
div.style.height = 'auto';
div.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2e/1-month-old_kitten_42.jpg/2880px-1-month-old_kitten_42.jpg';
var object = new CSS3DObject(div);
object.position.set(0, 0, 0);
object.scale.set(1 / 16, 1 / 16, 1 / 16);
this.scene.add(object);
const geometry = new THREE.TorusGeometry( 10, 3, 16, 100 );
const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
const torus = new THREE.Mesh( geometry, material );
this.scene.add( torus );
document.getElementById("content").appendChild(this.webGLRenderer.domElement);
document.getElementById("content").appendChild(this.css3DRenderer.domElement);
this.render();
}
CSS3DDemo.prototype.render = function() {
var _this = this;
window.requestAnimationFrame(function() {
return _this.render();
});
this.css3DRenderer.render(this.scene, this.camera);
this.webGLRenderer.render(this.scene, this.camera);
this.controls.update();
};
return CSS3DDemo;
}());
new CSS3DDemo();
html,
body {
width: 100vw;
margin: 0;
height: 100vh;
padding: 0;
overflow: hidden;
border: 0;
}
#content {
width: 100%;
height: 100%;
overflow: hidden;
}
<div id="content"></div>
<script src='https://gitcdn.xyz/repo/mrdoob/three.js/dev/build/three.min.js'></script>
<script src='https://gitcdn.xyz/repo/mrdoob/three.js/dev/examples/js/controls/OrbitControls.js'></script>
<script src='https://gitcdn.xyz/repo/mrdoob/three.js/dev/examples/js/renderers/CSS3DRenderer.js'></script>

How to make an object float on water like Buoyancy effect using threejs

I have created a water effect using THREE.WATER and added few gltf objects to the scene, now i am trying to make the added objects float on water like a boat is floating.
here is the code attached.
var scene, camera, renderer, ambient, directional, controls, stats, clock, imageLoader;
var terrain, water, mixer, model,modelL;
var lillyCoordPosition = [
[3.5, -6.1, -18],
[8.5, -6.1, -18],
[13.3, -6.1, -18],
[3.5, -8.1, -16],
[8.5, -8.1, -16],
[13.3, -8.1, -16],
[3.5, -7.1, -17],
[8.5, -7.1, -17],
[13.3, -7.1, -17]
];
init();
animate();
resize();
function resize() {
window.addEventListener("resize", function () {
let width = window.innerWidth;
let height = window.innerHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
});
}
function init() {
clock = new THREE.Clock();
imageLoader = new THREE.TextureLoader();
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 20000);
camera.position.y = 6.5;
camera.position.z = 2;
ambient = new THREE.AmbientLight(0xe8eb34);
scene.add(ambient);
directional = new THREE.DirectionalLight(0xe8eb34, 1);
directional.position.set(30, 80, 20);
scene.add(directional);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setClearColor(0x70c8ff, 1);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// controls = new THREE.OrbitControls( camera, renderer.domElement );
// controls.target.set(0,120,-500);
// controls.update();
document.body.appendChild(renderer.domElement);
scene.fog = new THREE.FogExp2(0xEDC9AF, 0.003);
loadWater();
/*lillyCoordPosition.map( position => {
loadLilly(position);
})*/
}
function loadBar() {
var texture = new THREE.Texture(generateTexture());
texture.needsUpdate = true;
var geometry = new THREE.PlaneGeometry(0.060, 10);
var material = new THREE.MeshBasicMaterial({
map: texture,
// color: 0xffffff,
side: THREE.DoubleSide
});
var plane = new THREE.Mesh(geometry, material);
plane.position.set(1.500, 6.390, 0.000);
plane.scale.set(1, 0.110, 1);
//border
var geo = new THREE.EdgesGeometry(plane.geometry);
var mat = new THREE.LineBasicMaterial({ color: 0xffffff, linewidth: 4 });
var wireframe = new THREE.LineSegments(geo, mat);
wireframe.renderOrder = 1; // make sure wireframes are rendered 2nd
plane.add(wireframe);
scene.add(plane);
//indicator
var indicatorGeo = new THREE.PlaneGeometry(0.110, 0.300);
var indMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide });
var indicator = new THREE.Mesh(indicatorGeo, indMaterial);
indicator.position.set(1.500, 6.000, 0.000);
indicator.scale.set(1, 0.110, 1);
scene.add(indicator);
}
function generateTexture() {
var size = 25;
canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
var context = canvas.getContext('2d');
var gradient = context.createLinearGradient(0, size, 0, 0);
gradient.addColorStop(0, '#ff0000');
gradient.addColorStop(1, '#00ff00');
context.fillStyle = gradient;
context.fillRect(0, 0, size, size);
return canvas;
}
function loadLilly(coord){
var loader = new THREE.GLTFLoader();
loader.load('model/lillypad/scene.gltf', function(lilly){
modelL = lilly.scene;
modelL.scale.set(3,1.5,1.5);
modelL.position.z = coord[2];
modelL.position.y = coord[1];
modelL.position.x = coord[0];
// modelL.position.x = i*1.6;
scene.add(modelL);
});
}
function loadFrog() {
var loader = new THREE.GLTFLoader();
loader.load(
'model/frog/scene.gltf', function (gltf) {
//console.log(gltf.animations[0]);
model = gltf.scene;
//console.log(model);
model.scale.set(0.7, 0.7, 1.1);
model.position.z = -30;
scene.add(model);
mixer = new THREE.AnimationMixer(model);
mixer.clipAction(gltf.animations[0]).play();
});
}
function loadPlant() {
var loader = new THREE.GLTFLoader();
loader.load('model/forest_2/scene.gltf', function (plant) {
var modelP = plant.scene;
modelP.scale.set(46, 40, 40);
modelP.position.z = -80;
modelP.position.y = 10;
modelP.position.x = 4;
modelP.rotation.y = 20;
scene.add(modelP);
});
}
function loadWater() {
var geo = new THREE.PlaneBufferGeometry(15000, 15000, 10, 10);
var c = directional.position.clone();
var normal = imageLoader.load('https://www.titansoftime.com/textures/water/waternormals.jpg');
normal.wrapS = THREE.RepeatWrapping;
normal.wrapT = THREE.RepeatWrapping;
water = new THREE.Water(geo, {
textureWidth: 204,
textureHeight: 204,
waterNormals: normal,
alpha: 0.01,
fog: true,
distortionScale: 10.0,
sunDirection: c.normalize(),
sunColor: 0x73a9ff,
waterColor: 0x73a9ff,
side: THREE.DoubleSide
});
water.rotation.x = - Math.PI * 0.5;
water.matrixAutoUpdate = false;
water.rotationAutoUpdate = false;
water.updateMatrix();
water.name = 'water';
scene.add(water);
}
function animate() {
requestAnimationFrame(animate);
var delta = clock.getDelta();
if (water) {
water.material.uniforms.time.value += 0.5 * delta;
}
if (mixer != null) mixer.update(delta);
renderer.render(scene, camera);
}
<body>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
body {
overflow: hidden;
/* background:url('https://www.publicdomainpictures.net/pictures/30000/velka/blue-sky-1330598792xLu.jpg'); */
}
canvas {
width: 100vw;
height: 100vh;
position: absolute;
left: 0;
}
#question {
width: fit-content;
height: 90px;
background-color: rgba(0, 0, 0, 0.2);
position: absolute;
top: 50px;
left: 30%;
border-radius: 20px;
color: white;
text-align: center;
z-index: 1;
box-shadow: 0 10px 10px rgba(0, 1, 0, 0.3);
padding: 8px;
}
.score,
.pause {
width: 90px;
height: 90px;
border-radius: 20px;
background-color: rgba(0, 0, 0, 0.2);
box-shadow: 0 10px 10px rgba(0, 1, 0, 0.3);
position: absolute;
top: 50px;
z-index: 1;
right: 10;
text-align: center;
color: white;
}
</style>
<div id="question">
</div>
<span class="score">
<h1>23</h1>
</span>
<script src="https://threejs.org/build/three.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/loaders/GLTFLoader.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/objects/Water.js"></script>
<script src="index.js"></script>
</body>
In the above code, loadLilly() is a function which loads lillypads on the water, but i want the lillypads to float on water.
lillypad object: https://sketchfab.com/3d-models/lilypad-8c8285abc29f4d6cb5836f23037b741b
Please help me in resolving the issue, I have tried using obje.position.y but of no use.
Thank you.
You can load that lilly model once and then re-use its geometry and material in a loop, creating a new mesh for each lilly.
In the purpose of an example, I simply created lilly's geometry and material in the code.
Effect of floating is made with sin function, applied to y-coordinate. You can use the same principle to make lillies move on any coordinate axis.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100);
camera.position.set(0, 2.5, 5);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(1);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
scene.add(new THREE.GridHelper(10, 100, "aqua", "aqua"));
// lilly geom
let lCurve = new THREE.EllipseCurve(0, 0, 1, 1, 0, 1.9 * Math.PI);
let lPts = lCurve.getPoints(32);
lPts.push(new THREE.Vector2());
let lShape = new THREE.Shape(lPts);
let lGeom = new THREE.ExtrudeBufferGeometry(lShape, {
depth: 0.25,
bevelEnabled: false
});
lGeom.rotateX(-Math.PI * 0.5);
lGeom.translate(0, -0.125, 0);
let lMat = new THREE.MeshLambertMaterial({
color: "green"
});
// lillies
var lillies = [];
var lillyCoordPosition = [
[-2.5, -2.5],
[0, -2.5],
[2.5, -2.5],
[-2.5, 0],
[0, 0],
[2.5, 0],
[-2.5, 2.5],
[0, 2.5],
[2.5, 2.5]
].forEach(p => {
let l = new THREE.Mesh(lGeom, lMat);
l.position.set(p[0], 0, p[1]);
l.rotation.y = Math.random() * Math.PI * 2; // random rotation
let s = Math.random() * 0.25 + 0.75; // slightly different size of each one
l.scale.set(s, 1, s);
l.userData.initFloating = Math.random() * Math.PI * 2; // initial value for start of floating
lillies.push(l);
scene.add(l);
});
var clock = new THREE.Clock();
renderer.setAnimationLoop(al);
function al() {
let t = clock.getElapsedTime();
lillies.forEach(lil => {
lil.position.y = Math.sin(lil.userData.initFloating + t) * 0.05;
});
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>

Multiple canvas in three.js

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>

How programmatically focus a mesh in three js on click on a button?

I have a three js Mesh on Click of a button the mesh need to be focus based on the button
for example on click of view top camera need to focus from the top of the mesh
in three.js is there any inbuilt method to focus a mesh or how to calculate top left front of a mesh?
var scene, camera, renderer, controls;
var ROTATE = true;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, 450 / 450, 0.1, 1000);
renderer = new THREE.WebGLRenderer();
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.userPan = false;
controls.userPanSpeed = 0.0;
controls.maxDistance = 5000.0;
controls.maxPolarAngle = Math.PI * 0.495;
// controls.rotateUp(Math.PI * 0.1);
// controls.autoRotate = ROTATE; //true:自動回転する,false:自動回転しない
controls.autoRotateSpeed = 4.0; //自動回転する時の速度
renderer.setSize(465, 465);
renderer.shadowMapEnabled = true;
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 150;
camera.lookAt(scene.position);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(100, 100, -100);
scene.add(spotLight);
var light = new THREE.DirectionalLight(0xffffff, 1.5);
light.position.set(100, 100, 100).normalize();
scene.add(light);
var light2 = new THREE.DirectionalLight(0xffffff);
light2.position.set(-100, -100, -100).normalize();
scene.add(light2);
document.body.appendChild(renderer.domElement);
var parser = new vox.Parser();
// yuusha.vox
parser.parse("https://rawcdn.githack.com/siouxcitizen/3DModel/b2d06e45f6b64c3e342b724a4ec5a0c427a4ce0a/vox/hiyoko.vox").then(function(voxelData) {
var builder = new vox.MeshBuilder(voxelData, {
voxelSize: 7.0,
vertexColor: true,
optimizeFaces: false,
});
var v0 = builder.createMesh();
v0.position.y -= 50;
scene.add(v0);
});
render();
}
function render() {
controls.update();
requestAnimationFrame(render);
renderer.render(scene, camera);
}
init();
function topView(){
alert("topView view")
}
function sideView(){
alert("sideview view")
}
function frontiew(){
alert("front view")
}
* {
margin: 0;
padding: 0;
border: 0;
overflow: hidden;
}
body {
background: #000;
font: 30px sans-serif;
}
button{
padding:5px 10px
}
<!-- three.min.js r87 -->
<button onClick={topView()}>top view</button>
<button onClick={frontiew()}>front view</button>
<button onClick={sideView()}>side view</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
<!-- vox.js v1.0.1 -->
<script src="https://cdn.jsdelivr.net/gh/daishihmr/vox.js#1.0.1/build/vox.min.js"></script>
<!-- Old OrbitControls.js -->
<script src="https://codepen.io/siouxcitizen/pen/XWWXZZN.js"></script>
the above is demo code.
I try to forcefully update camera position it won't work
You can get axis aligned bbox with new THREE.Box3().setFromObject(mesh)
and next - fit camera to this box.
Here is my code (typescript) to do it (works well with PerspetiveCamera and OrbitControls).
fitCameraTo(boundingBox: THREE.Box3) {
const camera = this._camera;
const objPosition = boundingBox.getCenter(new THREE.Vector3());
const objSize = boundingBox.getSize(new THREE.Vector3());
boundingBox.min.y = 0;
boundingBox.max.y = 0;
const boundingSphere = boundingBox.getBoundingSphere(new THREE.Sphere());
let dim = boundingSphere.radius * 2;
if (dim < camera.near) {
dim = camera.near;
}
const direction = THREE.Object3D.DefaultUp.clone(); // view direction
// object angular size
const fov = THREE.Math.degToRad(camera.fov);
let distance = dim / (2.0 * Math.tan(fov / 2.0));
if (camera.aspect <= 1) {
distance = distance / camera.aspect;
}
if (distance < camera.near) {
distance = objSize.y;
}
if (distance < camera.near) {
distance = camera.near;
}
camera.position.copy(objPosition.clone().add(direction.multiplyScalar(distance)));
if (this.this._orbitControls) {
this._orbitControls.target.copy(objPosition);
this._orbitControls.rotateLeft(Math.PI);
} else {
camera.lookAt(objPosition);
}
camera.updateProjectionMatrix();
}

Create 3D model of pile with points with Three.js

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>

Categories