Creating three tables with header - javascript

I'm trying to cycle through a table and create three tables of clickable divs with a header for each (ideally with a separate class to make them look different). I'm trying to use a while loop with three if statements but the headers are not displaying properly. All three still show up as normal divs instead of with different classes but the first one is covered with a second copy of the third column header with the correct header and the second header is covered with a second copy of the first header, again with the correct class.
JS Snippet
var table = [
"Column Title", "#", 2,2,
"Column Item", "website.com", 1, 3,
"Column Item 2", "website2.com", 2, 3,
// Etc.
];
var camera, scene, renderer;
var controls;
var objects = [];
var targets = { table: [], sphere: [], helix: [], grid: [] };
init();
animate();
function init() {
for ( var i = 0; i < table.length; i += 4 ) {
if(i === 0){
var courtsTitle = document.createElement('div');
courtsTitle.className = 'listTitle';
courtsTitle.innerHTML = "<p>Column Title</p>";
var object = new THREE.CSS3DObject( courtsTitle );
object.position.x = Math.random() * 4000 - 2000;
object.position.y = Math.random() * 4000 - 2000;
object.position.z = Math.random() * 4000 - 2000;
scene.add( object );
objects.push( object );
var object = new THREE.Object3D();
object.position.x = ( 6 * 480 ) - 2900;
object.position.y = - ( 2 * 340 ) + 1550;
targets.table.push( object );
}
if(i === 14){
var departmentsTitle = document.createElement('div');
departmentsTitle.className = 'listTitle';
departmentsTitle.innerHTML = "<p>Column Title2</p>";
var object = new THREE.CSS3DObject( departmentsTitle );
object.position.x = Math.random() * 4000 - 2000;
object.position.y = Math.random() * 4000 - 2000;
object.position.z = Math.random() * 4000 - 2000;
scene.add( object );
objects.push( object );
var object = new THREE.Object3D();
object.position.x = ( 10 * 480 ) - 2900;
object.position.y = - ( 2 * 340 ) + 1550;
targets.table.push( object );
}
if(i === 28){
var servicesTitle = document.createElement('div');
servicesTitle.className = 'listTitle';
servicesTitle.innerHTML = "<p>Column Title3</p>";
var object = new THREE.CSS3DObject( servicesTitle );
object.position.x = Math.random() * 4000 - 2000;
object.position.y = Math.random() * 4000 - 2000;
object.position.z = Math.random() * 4000 - 2000;
scene.add( object );
objects.push( object );
//
var object = new THREE.Object3D();
object.position.x = ( 2 * 480 ) - 2900;
object.position.y = - ( 2 * 340 ) + 1550;
targets.table.push( object );
} else {
var department = document.createElement('a');
department.className = 'department';
department.style.backgroundColor = 'rgba(0,127,127,' + ( Math.random() * 0.5 + 0.25 ) + ')';
department.setAttribute('href', table[i + 1]);
department.setAttribute('target', "_blank");
var link = document.createElement('div');
link.className = 'link';
link.innerHTML = table[i];
department.appendChild(link);
/*Random Starting point*/
var object = new THREE.CSS3DObject( department );
object.position.x = Math.random() * 4000 - 2000;
object.position.y = Math.random() * 4000 - 2000;
object.position.z = Math.random() * 4000 - 2000;
scene.add( object );
objects.push( object );
/*Final position*/
var object = new THREE.Object3D();
object.position.x = ( table[ i + 2 ] * 480 ) - 2900;
object.position.y = - ( table[ i + 3 ] * 340 ) + 1550;
targets.table.push( object );
}
}

Related

ThreeJS how to change text particles color

I have been trying for days to modify the colors in this project and I couldn't
In particulat I'd like to change:
the background color [edit, I was able to do this]
the yellow and white fixed colors for the text in the linked snippet
I tried to do it via the const particle = new THREE.TextureLoader(manager).load linking to another png image but the text disappears even if the link is valid
If there is a working project similar to this please feel free to share it
Thanks!
const preload = () => {
let manager = new THREE.LoadingManager();
manager.onLoad = function() {
const environment = new Environment( typo, particle );
}
var typo = null;
const loader = new THREE.FontLoader( manager );
const font = loader.load('https://res.cloudinary.com/dydre7amr/raw/upload/v1612950355/font_zsd4dr.json', function ( font ) { typo = font; });
const particle = new THREE.TextureLoader( manager ).load( 'https://res.cloudinary.com/dfvtkoboz/image/upload/v1605013866/particle_a64uzf.png');
}
if ( document.readyState === "complete" || (document.readyState !== "loading" && !document.documentElement.doScroll))
preload ();
else
document.addEventListener("DOMContentLoaded", preload );
class Environment {
constructor( font, particle ){
this.font = font;
this.particle = particle;
this.container = document.querySelector( '#wn-magic' );
this.scene = new THREE.Scene();
this.createCamera();
this.createRenderer();
this.setup()
this.bindEvents();
}
bindEvents(){
window.addEventListener( 'resize', this.onWindowResize.bind( this ));
}
setup(){
this.createParticles = new CreateParticles( this.scene, this.font, this.particle, this.camera, this.renderer );
}
render() {
this.createParticles.render()
this.renderer.render( this.scene, this.camera )
}
createCamera() {
this.camera = new THREE.PerspectiveCamera( 65, this.container.clientWidth / this.container.clientHeight, 1, 10000 );
this.camera.position.set( 0,0, 100 );
}
createRenderer() {
this.renderer = new THREE.WebGLRenderer();
this.renderer.setSize( this.container.clientWidth, this.container.clientHeight );
this.renderer.setPixelRatio( Math.min( window.devicePixelRatio, 2));
this.renderer.outputEncoding = THREE.sRGBEncoding;
this.container.appendChild( this.renderer.domElement );
this.renderer.setAnimationLoop(() => { this.render() })
}
onWindowResize(){
this.camera.aspect = this.container.clientWidth / this.container.clientHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize( this.container.clientWidth, this.container.clientHeight );
}
}
class CreateParticles {
constructor( scene, font, particleImg, camera, renderer ) {
this.scene = scene;
this.font = font;
this.particleImg = particleImg;
this.camera = camera;
this.renderer = renderer;
this.raycaster = new THREE.Raycaster();
this.mouse = new THREE.Vector2(-200, 200);
this.colorChange = new THREE.Color();
this.buttom = false;
this.data = {
text: 'Welcome\n To Rostami\n Creative\n Studio',
amount: 800,
particleSize: 2,
particleColor: 0xeeeeee,
textSize: 16,
area: 250,
ease: .05,
}
this.setup();
this.bindEvents();
}
setup(){
const geometry = new THREE.PlaneGeometry( this.visibleWidthAtZDepth( 100, this.camera ), this.visibleHeightAtZDepth( 100, this.camera ));
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00, transparent: true } );
this.planeArea = new THREE.Mesh( geometry, material );
this.planeArea.visible = false;
this.createText();
}
bindEvents() {
document.addEventListener( 'mousedown', this.onMouseDown.bind( this ));
document.addEventListener( 'mousemove', this.onMouseMove.bind( this ));
document.addEventListener( 'mouseup', this.onMouseUp.bind( this ));
}
onMouseDown(){
this.mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
this.mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
const vector = new THREE.Vector3( this.mouse.x, this.mouse.y, 0.5);
vector.unproject( this.camera );
const dir = vector.sub( this.camera.position ).normalize();
const distance = - this.camera.position.z / dir.z;
this.currenPosition = this.camera.position.clone().add( dir.multiplyScalar( distance ) );
const pos = this.particles.geometry.attributes.position;
this.buttom = true;
this.data.ease = .01;
}
onMouseUp(){
this.buttom = false;
this.data.ease = .05;
}
onMouseMove( ) {
this.mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
this.mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
render( level ){
const time = ((.001 * performance.now())%12)/12;
const zigzagTime = (1 + (Math.sin( time * 2 * Math.PI )))/6;
this.raycaster.setFromCamera( this.mouse, this.camera );
const intersects = this.raycaster.intersectObject( this.planeArea );
if ( intersects.length > 0 ) {
const pos = this.particles.geometry.attributes.position;
const copy = this.geometryCopy.attributes.position;
const coulors = this.particles.geometry.attributes.customColor;
const size = this.particles.geometry.attributes.size;
const mx = intersects[ 0 ].point.x;
const my = intersects[ 0 ].point.y;
const mz = intersects[ 0 ].point.z;
for ( var i = 0, l = pos.count; i < l; i++) {
const initX = copy.getX(i);
const initY = copy.getY(i);
const initZ = copy.getZ(i);
let px = pos.getX(i);
let py = pos.getY(i);
let pz = pos.getZ(i);
this.colorChange.setHSL( .5, 1 , 1 )
coulors.setXYZ( i, this.colorChange.r, this.colorChange.g, this.colorChange.b )
coulors.needsUpdate = true;
size.array[ i ] = this.data.particleSize;
size.needsUpdate = true;
let dx = mx - px;
let dy = my - py;
const dz = mz - pz;
const mouseDistance = this.distance( mx, my, px, py )
let d = ( dx = mx - px ) * dx + ( dy = my - py ) * dy;
const f = - this.data.area/d;
if( this.buttom ){
const t = Math.atan2( dy, dx );
px -= f * Math.cos( t );
py -= f * Math.sin( t );
this.colorChange.setHSL( .5 + zigzagTime, 1.0 , .5 )
coulors.setXYZ( i, this.colorChange.r, this.colorChange.g, this.colorChange.b )
coulors.needsUpdate = true;
if ((px > (initX + 70)) || ( px < (initX - 70)) || (py > (initY + 70) || ( py < (initY - 70)))){
this.colorChange.setHSL( .15, 1.0 , .5 )
coulors.setXYZ( i, this.colorChange.r, this.colorChange.g, this.colorChange.b )
coulors.needsUpdate = true;
}
}else{
if( mouseDistance < this.data.area ){
if(i%5==0){
const t = Math.atan2( dy, dx );
px -= .03 * Math.cos( t );
py -= .03 * Math.sin( t );
this.colorChange.setHSL( .15 , 1.0 , .5 )
coulors.setXYZ( i, this.colorChange.r, this.colorChange.g, this.colorChange.b )
coulors.needsUpdate = true;
size.array[ i ] = this.data.particleSize /1.2;
size.needsUpdate = true;
}else{
const t = Math.atan2( dy, dx );
px += f * Math.cos( t );
py += f * Math.sin( t );
pos.setXYZ( i, px, py, pz );
pos.needsUpdate = true;
size.array[ i ] = this.data.particleSize * 1.3 ;
size.needsUpdate = true;
}
if ((px > (initX + 10)) || ( px < (initX - 10)) || (py > (initY + 10) || ( py < (initY - 10)))){
this.colorChange.setHSL( .15, 1.0 , .5 )
coulors.setXYZ( i, this.colorChange.r, this.colorChange.g, this.colorChange.b )
coulors.needsUpdate = true;
size.array[ i ] = this.data.particleSize /1.8;
size.needsUpdate = true;
}
}
}
px += ( initX - px ) * this.data.ease;
py += ( initY - py ) * this.data.ease;
pz += ( initZ - pz ) * this.data.ease;
pos.setXYZ( i, px, py, pz );
pos.needsUpdate = true;
}
}
}
createText(){
let thePoints = [];
let shapes = this.font.generateShapes( this.data.text , this.data.textSize );
let geometry = new THREE.ShapeGeometry( shapes );
geometry.computeBoundingBox();
const xMid = - 0.5 * ( geometry.boundingBox.max.x - geometry.boundingBox.min.x );
const yMid = (geometry.boundingBox.max.y - geometry.boundingBox.min.y)/2.85;
geometry.center();
let holeShapes = [];
for ( let q = 0; q < shapes.length; q ++ ) {
let shape = shapes[ q ];
if ( shape.holes && shape.holes.length > 0 ) {
for ( let j = 0; j < shape.holes.length; j ++ ) {
let hole = shape.holes[ j ];
holeShapes.push( hole );
}
}
}
shapes.push.apply( shapes, holeShapes );
let colors = [];
let sizes = [];
for ( let x = 0; x < shapes.length; x ++ ) {
let shape = shapes[ x ];
const amountPoints = ( shape.type == 'Path') ? this.data.amount/2 : this.data.amount;
let points = shape.getSpacedPoints( amountPoints ) ;
points.forEach( ( element, z ) => {
const a = new THREE.Vector3( element.x, element.y, 0 );
thePoints.push( a );
colors.push( this.colorChange.r, this.colorChange.g, this.colorChange.b);
sizes.push( 1 )
});
}
let geoParticles = new THREE.BufferGeometry().setFromPoints( thePoints );
geoParticles.translate( xMid, yMid, 0 );
geoParticles.setAttribute( 'customColor', new THREE.Float32BufferAttribute( colors, 3 ) );
geoParticles.setAttribute( 'size', new THREE.Float32BufferAttribute( sizes, 1) );
const material = new THREE.ShaderMaterial( {
uniforms: {
color: { value: new THREE.Color( 0xffffff ) },
pointTexture: { value: this.particleImg }
},
vertexShader: document.getElementById( 'vertexshader' ).textContent,
fragmentShader: document.getElementById( 'fragmentshader' ).textContent,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true,
} );
this.particles = new THREE.Points( geoParticles, material );
this.scene.add( this.particles );
this.geometryCopy = new THREE.BufferGeometry();
this.geometryCopy.copy( this.particles.geometry );
}
visibleHeightAtZDepth ( depth, camera ) {
const cameraOffset = camera.position.z;
if ( depth < cameraOffset ) depth -= cameraOffset;
else depth += cameraOffset;
const vFOV = camera.fov * Math.PI / 180;
return 2 * Math.tan( vFOV / 2 ) * Math.abs( depth );
}
visibleWidthAtZDepth( depth, camera ) {
const height = this.visibleHeightAtZDepth( depth, camera );
return height * camera.aspect;
}
distance (x1, y1, x2, y2){
return Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2));
}
}
I gave a look to your code and your comments
how to use setHSL(): quite easy
H values are between 0 and 360, S and L between 0 and 100. You can see this clearly here. The same link will shortcut the colors selection too
On the other side, ThreeJS defines this values on a different pattern, i.e. each of the H,S,L values is between 0.0 and 1.0
So if you wanna go green [120,100,50] you will translate the ThreeJS setHSL() call with values [0.33,1,0.5] where 0.33=120/360
changing the colors in your code
const preload = () => {
let manager = new THREE.LoadingManager();
manager.onLoad = function() {
const environment = new Environment(typo, particle);
}
var typo = null;
const loader = new THREE.FontLoader(manager);
const font = loader.load('https://res.cloudinary.com/dydre7amr/raw/upload/v1612950355/font_zsd4dr.json', function(font) {
typo = font;
});
const particle = new THREE.TextureLoader(manager).load('https://res.cloudinary.com/dfvtkoboz/image/upload/v1605013866/particle_a64uzf.png');
}
if (document.readyState === "complete" || (document.readyState !== "loading" && !document.documentElement.doScroll))
preload();
else
document.addEventListener("DOMContentLoaded", preload);
class Environment {
constructor(font, particle) {
this.font = font;
this.particle = particle;
this.container = document.querySelector('#magic');
this.scene = new THREE.Scene();
this.createCamera();
this.createRenderer();
this.setup()
this.bindEvents();
}
bindEvents() {
window.addEventListener('resize', this.onWindowResize.bind(this));
}
setup() {
this.createParticles = new CreateParticles(this.scene, this.font, this.particle, this.camera, this.renderer);
}
render() {
this.createParticles.render()
this.renderer.render(this.scene, this.camera)
}
createCamera() {
this.camera = new THREE.PerspectiveCamera(65, this.container.clientWidth / this.container.clientHeight, 1, 10000);
this.camera.position.set(0, 0, 100);
}
createRenderer() {
this.renderer = new THREE.WebGLRenderer();
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
this.renderer.outputEncoding = THREE.sRGBEncoding;
this.container.appendChild(this.renderer.domElement);
this.renderer.setAnimationLoop(() => {
this.render()
})
}
onWindowResize() {
this.camera.aspect = this.container.clientWidth / this.container.clientHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
}
}
class CreateParticles {
constructor(scene, font, particleImg, camera, renderer) {
this.scene = scene;
this.font = font;
this.particleImg = particleImg;
this.camera = camera;
this.renderer = renderer;
this.raycaster = new THREE.Raycaster();
this.mouse = new THREE.Vector2(-200, 200);
this.colorChange = new THREE.Color();
this.buttom = false;
this.data = {
text: 'FUTURE\nIS NOW',
amount: 1500,
particleSize: 1,
particleColor: 0xffffff,
textSize: 16,
area: 250,
ease: .05,
}
this.setup();
this.bindEvents();
}
setup() {
const geometry = new THREE.PlaneGeometry(this.visibleWidthAtZDepth(100, this.camera), this.visibleHeightAtZDepth(100, this.camera));
const material = new THREE.MeshBasicMaterial({
color: 0x00ff00,
transparent: true
});
this.planeArea = new THREE.Mesh(geometry, material);
this.planeArea.visible = false;
this.createText();
}
bindEvents() {
document.addEventListener('mousedown', this.onMouseDown.bind(this));
document.addEventListener('mousemove', this.onMouseMove.bind(this));
document.addEventListener('mouseup', this.onMouseUp.bind(this));
}
onMouseDown() {
this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
const vector = new THREE.Vector3(this.mouse.x, this.mouse.y, 0.5);
vector.unproject(this.camera);
const dir = vector.sub(this.camera.position).normalize();
const distance = -this.camera.position.z / dir.z;
this.currenPosition = this.camera.position.clone().add(dir.multiplyScalar(distance));
const pos = this.particles.geometry.attributes.position;
this.buttom = true;
this.data.ease = .01;
}
onMouseUp() {
this.buttom = false;
this.data.ease = .05;
}
onMouseMove() {
this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
render(level) {
const time = ((.001 * performance.now()) % 12) / 12;
const zigzagTime = (1 + (Math.sin(time * 2 * Math.PI))) / 6;
this.raycaster.setFromCamera(this.mouse, this.camera);
const intersects = this.raycaster.intersectObject(this.planeArea);
if (intersects.length > 0) {
const pos = this.particles.geometry.attributes.position;
const copy = this.geometryCopy.attributes.position;
const coulors = this.particles.geometry.attributes.customColor;
const size = this.particles.geometry.attributes.size;
const mx = intersects[0].point.x;
const my = intersects[0].point.y;
const mz = intersects[0].point.z;
for (var i = 0, l = pos.count; i < l; i++) {
const initX = copy.getX(i);
const initY = copy.getY(i);
const initZ = copy.getZ(i);
let px = pos.getX(i);
let py = pos.getY(i);
let pz = pos.getZ(i);
// base color when the mouse is distant
// color that will be distorted when the mouse hovers on the text
// e.g. red
this.colorChange.setHSL(0, 1, .50)
coulors.setXYZ(i, this.colorChange.r, this.colorChange.g, this.colorChange.b)
coulors.needsUpdate = true;
size.array[i] = this.data.particleSize;
size.needsUpdate = true;
let dx = mx - px;
let dy = my - py;
const dz = mz - pz;
const mouseDistance = this.distance(mx, my, px, py)
let d = (dx = mx - px) * dx + (dy = my - py) * dy;
const f = -this.data.area / d;
if (this.buttom) {
const t = Math.atan2(dy, dx);
px -= f * Math.cos(t);
py -= f * Math.sin(t);
//onMouseDown color
//e.g. light blue when zigzagTime equals 0 but keep pressing on the text and the color will change because of the time dependency
this.colorChange.setHSL(.5 + zigzagTime, 1.0, .5)
coulors.setXYZ(i, this.colorChange.r, this.colorChange.g, this.colorChange.b)
coulors.needsUpdate = true;
if ((px > (initX + 70)) || (px < (initX - 70)) || (py > (initY + 70) || (py < (initY - 70)))) {
//color of the external particles when mouse is down on the text
//e.g. yellow
this.colorChange.setHSL(.15, 1.0, .5);
coulors.setXYZ(i, this.colorChange.r, this.colorChange.g, this.colorChange.b)
coulors.needsUpdate = true;
}
} else {
if (mouseDistance < this.data.area) {
if (i % 5 == 0) {
const t = Math.atan2(dy, dx);
px -= .03 * Math.cos(t);
py -= .03 * Math.sin(t);
// changing the color around the mouse position
// e.g. green
this.colorChange.setHSL(.33, 1.0, .5)
coulors.setXYZ(i, this.colorChange.r, this.colorChange.g, this.colorChange.b)
coulors.needsUpdate = true;
size.array[i] = this.data.particleSize / 1.2;
size.needsUpdate = true;
} else {
const t = Math.atan2(dy, dx);
px += f * Math.cos(t);
py += f * Math.sin(t);
pos.setXYZ(i, px, py, pz);
pos.needsUpdate = true;
size.array[i] = this.data.particleSize * 1.3;
size.needsUpdate = true;
}
if ((px > (initX + 10)) || (px < (initX - 10)) || (py > (initY + 10) || (py < (initY - 10)))) {
// changing color of the external particles when mouse is down on the text
this.colorChange.setHSL(.15, 1.0, .5)
coulors.setXYZ(i, this.colorChange.r, this.colorChange.g, this.colorChange.b)
coulors.needsUpdate = true;
size.array[i] = this.data.particleSize / 1.8;
size.needsUpdate = true;
}
}
}
px += (initX - px) * this.data.ease;
py += (initY - py) * this.data.ease;
pz += (initZ - pz) * this.data.ease;
pos.setXYZ(i, px, py, pz);
pos.needsUpdate = true;
}
}
}
createText() {
let thePoints = [];
let shapes = this.font.generateShapes(this.data.text, this.data.textSize);
let geometry = new THREE.ShapeGeometry(shapes);
geometry.computeBoundingBox();
const xMid = -0.5 * (geometry.boundingBox.max.x - geometry.boundingBox.min.x);
const yMid = (geometry.boundingBox.max.y - geometry.boundingBox.min.y) / 2.85;
geometry.center();
let holeShapes = [];
for (let q = 0; q < shapes.length; q++) {
let shape = shapes[q];
if (shape.holes && shape.holes.length > 0) {
for (let j = 0; j < shape.holes.length; j++) {
let hole = shape.holes[j];
holeShapes.push(hole);
}
}
}
shapes.push.apply(shapes, holeShapes);
let colors = [];
let sizes = [];
for (let x = 0; x < shapes.length; x++) {
let shape = shapes[x];
const amountPoints = (shape.type == 'Path') ? this.data.amount / 2 : this.data.amount;
let points = shape.getSpacedPoints(amountPoints);
points.forEach((element, z) => {
const a = new THREE.Vector3(element.x, element.y, 0);
thePoints.push(a);
colors.push(this.colorChange.r, this.colorChange.g, this.colorChange.b);
sizes.push(1)
});
}
let geoParticles = new THREE.BufferGeometry().setFromPoints(thePoints);
geoParticles.translate(xMid, yMid, 0);
geoParticles.setAttribute('customColor', new THREE.Float32BufferAttribute(colors, 3));
geoParticles.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1));
const material = new THREE.ShaderMaterial({
uniforms: {
color: {
value: new THREE.Color(0xffffff)
},
pointTexture: {
value: this.particleImg
}
},
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true,
});
this.particles = new THREE.Points(geoParticles, material);
this.scene.add(this.particles);
this.geometryCopy = new THREE.BufferGeometry();
this.geometryCopy.copy(this.particles.geometry);
}
visibleHeightAtZDepth(depth, camera) {
const cameraOffset = camera.position.z;
if (depth < cameraOffset) depth -= cameraOffset;
else depth += cameraOffset;
const vFOV = camera.fov * Math.PI / 180;
return 2 * Math.tan(vFOV / 2) * Math.abs(depth);
}
visibleWidthAtZDepth(depth, camera) {
const height = this.visibleHeightAtZDepth(depth, camera);
return height * camera.aspect;
}
distance(x1, y1, x2, y2) {
return Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2));
}
}
This should solve your issue from a theoretical and practical point of view

threejs coincident vertices texture discontinued

I want to make a animated tube with hemisphere ends, the tubular segments is 200. I have the vertices from the first 60 segments to copy the position of a SphereGeometry's upper half part, and the last 60 segments lower half part.
The segments between the upper and lower hemisphere is all copied to the vertices around the sphere's equatorial.
The geometry looks fine, but the spherical environment mapping texture is discontinued at the sphere's equatorial.
I have my code as below, anyone know how to solve the problem?
var camera, scene, renderer;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 28, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 50;
scene = new THREE.Scene();
var nMat = new THREE.MeshNormalMaterial({side:THREE.DoubleSide,});
var tube = new DSTube( 200, 30, 10, nMat);
scene.add( tube.mesh );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
body {
margin: 0px;
background-color: #000000;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r78/three.js"></script>
<script>
function DSTube( lengthSeg, radiusSeg, radius, material ) {
//for speed
this.framerate = 60;
//center
this.origin = new THREE.Vector3();
this.head = this.origin;
this.tail = this.origin;
//setup
this.lengthSeg = lengthSeg;
this.radiusSeg = radiusSeg;
this.radius = radius;
this.pathPoints = [];
for(var i=0; i<this.lengthSeg; i++) {
this.pathPoints.push( new THREE.Vector3( 0, 0, 0) );
}
// TubeGeometry(path, tubularSegments, radius, radiusSegments, closed)
this.geometry = new THREE.TubeGeometry( new THREE.CatmullRomCurve3(this.pathPoints), this.lengthSeg, this.radius, this.radiusSeg, false );
this.material = material;
this.mesh = new THREE.Mesh( this.geometry, this.material );
this.verticeCount = this.geometry.vertices.length;
//sphere part
//adjust height segment if needed
this.sphereHeightSegments = 60;
//SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength)
this.headSphere = new THREE.SphereGeometry( this.radius, this.radiusSeg, this.sphereHeightSegments );
this.tailSphere = new THREE.SphereGeometry( this.radius, this.radiusSeg, this.sphereHeightSegments );
this.sphereVerticeCount = this.headSphere.vertices.length;
//count for tube hemisphere
this.headHemisphereVerticeCount = ( this.sphereHeightSegments / 2 + 1 ) * this.radiusSeg;
//layer
this.tubeLayerCount = this.lengthSeg + 1;
this.headHemisphereLayerCount = this.tailHemisphereLayerCount = this.sphereHeightSegments / 2 + 1;
this.tailHemisphereStartLayer = this.tubeLayerCount - this.sphereHeightSegments / 2;
this.middleLayerCount = this.tubeLayerCount - this.headHemisphereLayerCount * 2;
this.initGeometry();
// return this.mesh;
}
DSTube.prototype.initGeometry = function() {
this.copyHeadSphere();
this.copyInitialTubePart();
this.copyTailSphere();
}
DSTube.prototype.copyHeadSphere = function() {
//copy head hemisphere vertice
for( var y = 0; y < this.headHemisphereLayerCount; y++ ) {
for( var x = 0; x < this.radiusSeg; x++ ) {
if( x == 0 ) {
var sphereVertex = this.headSphere.vertices[ y * (this.radiusSeg + 1) + x ];
this.geometry.vertices[ y * this.radiusSeg + x ].copy( sphereVertex );
} else {
var sphereVertex = this.headSphere.vertices[ y * (this.radiusSeg + 1) + ( this.radiusSeg - x ) ];
this.geometry.vertices[ y * this.radiusSeg + x ].copy( sphereVertex );
}
}
}
this.geometry.computeBoundingSphere();
this.geometry.computeFaceNormals();
this.geometry.computeVertexNormals();
}
DSTube.prototype.copyInitialTubePart = function() {
//copy head hemisphere vertice
for( var y = this.headHemisphereLayerCount - 1; y < this.tubeLayerCount ; y++ ) {
for( var x = 0; x < this.radiusSeg; x++ ) {
var vertex = this.geometry.vertices[ ( this.headHemisphereLayerCount - 1 ) * this.radiusSeg + x ];
this.geometry.vertices[ y * this.radiusSeg + x ].copy( vertex );
}
}
this.geometry.computeBoundingSphere();
this.geometry.computeFaceNormals();
this.geometry.computeVertexNormals();
}
DSTube.prototype.copyTailSphere = function() {
//copy tail hemisphere vertice
for( var y = this.tailHemisphereStartLayer; y < this.tubeLayerCount; y++ ) {
for( var x = 0; x < this.radiusSeg; x++ ) {
if( x == 0 ) {
var sphereVertex = this.tailSphere.vertices[ ( y - this.middleLayerCount - 1 ) * (this.radiusSeg + 1) + x ];
this.geometry.vertices[ y * this.radiusSeg + x ].copy( sphereVertex );
} else {
var sphereVertex = this.tailSphere.vertices[ ( y - this.middleLayerCount - 1 ) * (this.radiusSeg + 1) + ( this.radiusSeg - x ) ];
this.geometry.vertices[ y * this.radiusSeg + x ].copy( sphereVertex );
}
}
}
this.geometry.computeBoundingSphere();
this.geometry.computeFaceNormals();
this.geometry.computeVertexNormals();
}
</script>

Three.js clickable objects not clickable

I am attempting to turn 3D objects into clickable elements by using an array called objects[]; and a switch statement which accesses the userData of the object. Right now, the script runs with no errors yet the objects still aren't clickable. What am I missing?
var container, stats;
var camera, scene, raycaster, renderer;
var mouse = new THREE.Vector2(),
INTERSECTED;
var radius = 100,
theta = 0;
init();
animate();
function createMesh(name, geometry, material) {
var object = new THREE.Mesh(geometry, material);
object.position.x = Math.random() * 800 - 400;
object.position.y = Math.random() * 800 - 400;
object.position.z = Math.random() * 800 - 400;
object.scale.x = Math.random() * 2 + 1;
object.scale.y = Math.random() * 2 + 1;
object.scale.z = Math.random() * 2 + 1;
object.rotation.x = Math.random() * 2 * Math.PI;
object.rotation.y = Math.random() * 2 * Math.PI;
object.rotation.z = Math.random() * 2 * Math.PI;
object.userData = {
URL: "http://www.google.com"
};
var objects = [];
for (i = 0; i > objects.length; i++) {
objects += i;
objects.push(object);
}
scene.add(object);
switch (i) {
case 1:
objects[i].userData = {
URL: "http://www.google.com"
};
break;
case 2:
objects[i].userData = {
URL: "https://www.yahoo.com"
};
break;
}
object.name = name;
}
var objects = [];
// objects.length == 0
// i is not greater than so nothing happens
for (i = 0; i > objects.length; i++) {
objects += i;
objects.push(object);
}
scene.add(object);
// i is still equal to 0 so nothing happens once again
switch (i) {
case 1: ...
case 2: ...

How can I turn shaders off and on at specific points in my Three JS scene?

I am creating a THREEjs animation which I eventually want to sync with audio. (Can't accomplish this currently) I would like to add and remove shaders at specific points. How can I accomplish this most efficiently?
The way I have it set up now, is that I have a mirror shader inside of a function called turnOnMirror and in my render function, I have a conditional statement,
if (audioSrc.context.currentTime > 32.0) { turnOnMirror(); }
The shader looks like this:
var mirror = mirrorPass = new THREE.ShaderPass( THREE.MirrorShader );
mirror.renderToScreen = true;
composer.addPass(mirror);
(I am doing this for 2 reasons!
A: The renderer is the only place I can grab the actual time to make this call. And B: because for whatever reason, my frequencyData array comes back as 0s.
However, when the scene reaches this point, everything slows down extremely. How can I keep the same frame rate and accomplish what I am attempting to at the same time?
A piece of information for you is that the scene works fine at the same constant speed if I just apply the shader without making the call in the render function.
You can view the site here!
And the source code for the main.js is below!
/* ==================== [ Global Variables ] ==================== */
var scene, camera, renderer, aspectRatio;
var stats;
var composer, effect, clock;
var backMesh;
/* ==================== [ Audio Context ] ==================== */
var ctx = new AudioContext();
var audio = document.getElementById('player');
audio.play();
audio.volume = 1;
// audio.crossOrigin = "anonymous";
var audioSrc = ctx.createMediaElementSource(audio);
var analyser = ctx.createAnalyser();
audioSrc.connect(analyser);
audioSrc.connect(ctx.destination);
// frequencyBinCount tells you how many values you'll receive from the analyser
var frequencyData = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(frequencyData);
console.log(audioSrc);
console.log(audioSrc.context.currentTime);
console.log(frequencyData);
console.log(analyser.fftSize); // 2048 by default
console.log(analyser.frequencyBinCount); // will give us 1024 data points
analyser.fftSize = 64;
console.log(analyser.frequencyBinCount); // fftSize/2 = 32 data points
/* ==================== [ Set Scene & Camera ] ==================== */
scene = new THREE.Scene();
// scene.fog = new THREE.Fog(0x000000, 0, 1200);
aspectRatio = window.innerWidth / window.innerHeight;
camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 100);
// camera.target = new THREE.Vector3( 10, 10, 10 );
// Set the DOM
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor("#000000");
document.body.appendChild(renderer.domElement);
/* ==================== [ Camera Position ] ==================== */
camera.position.z = 15;
camera.position.y = 0;
/* ==================== [ Point Lights ] ==================== */
var pointLightBlue = new THREE.PointLight("#00ccff", 5, 100, 2);
pointLightBlue.position.set(-10, -40, -10);
scene.add(pointLightBlue);
// var pointLightWhite = new THREE.PointLight( "#ffffff", 1, 0, 1 );
// // pointLightWhite.position.set( -10, 160, -10 );
// pointLightWhite.position.set( 0, 0, 1 );
// scene.add(pointLightWhite);
// camera.add(pointLightWhite);
// var pointLightPink = new THREE.PointLight( "#EE567C", 5, 100, 10 );
// pointLightPink.position.set( 1, 0, -5 );
// scene.add(pointLightPink);
var pointLight = new THREE.PointLight("#A805FA", 2, 100, 40);
pointLight.position.set(40, 0, 40);
scene.add(pointLight);
var light2 = new THREE.PointLight( 0xFFFFFF, 1, 100 );
scene.add( light2 );
light2.position.z = 1000;
var pointLight2 = new THREE.PointLight("#07FAA0", 2, 100, 30);
pointLight2.position.set(-40, 0, -40);
scene.add(pointLight2);
/* ==================== [ Particles ] ==================== */
var getCamera = function() {
return camera;
}
// var texture = new Image();
// texture.src = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/82015/snowflake.png';
// texture.src = './images/particle.png';
//var material = new THREE.ParticleBasicMaterial( { map: new THREE.Texture(texture) } );
var particleCount = 0, particleSystem, particles;
THREE.ImageUtils.crossOrigin = '';
var texture = THREE.ImageUtils.loadTexture('./images/particle.png');
//console.log(texture);
particleCount = 20000,
particles = new THREE.Geometry();
var pMaterial = new THREE.PointCloudMaterial({
color: 0xFFFFFF,
map: texture,
blending: THREE.AdditiveBlending,
depthTest: false,
depthWrite: false,
transparent: true,
opacity: 0.3,
side: THREE.DoubleSide,
size: 1.2
});
for (var i = 0; i < particleCount; i++) {
var pX = Math.random() * 500 - 250,
pY = Math.random() * 500 - 250,
pZ = Math.random() * 500 - 250,
particle = new THREE.Vector3(pX, pY, pZ);
particles.vertices.push(particle);
}
particleSystem = new THREE.ParticleSystem(particles, pMaterial);
particleSystem.sortParticles = false;
particleSystem.frustumCulled = false;
scene.add(particleSystem);
/* ==================== [ Light Beams ] ==================== */
var BEAM_ROT_SPEED = 0.003;
var BEAM_COUNT = 360;
var beamGeometry = new THREE.PlaneBufferGeometry(1, 500, 10, 1);
beamGroup = new THREE.Object3D();
beamMaterial = new THREE.MeshBasicMaterial({
opacity: 0.02,
transparent: true,
});
for (var i = 0; i <= BEAM_COUNT; ++i) {
var beam = new THREE.Mesh(beamGeometry, beamMaterial);
beam.doubleSided = true;
beam.rotation.x = Math.random() * Math.PI;
beam.rotation.y = Math.random() * Math.PI;
beam.rotation.z = Math.random() * Math.PI;
beamGroup.add(beam);
}
scene.add(beamGroup);
beamGroup.translateZ( -5 );
/* ==================== [ Cubes ] ==================== */
var doStrobe = false;
var doShake = false;
var strobeOn = false;
var beatTime = 30;
THREE.ImageUtils.crossOrigin = '';
var imgTextureStripes2 = THREE.ImageUtils.loadTexture( "./images/stripes2.jpg" );
imgTextureStripes2.wrapS = imgTextureStripes2.wrapT = THREE.RepeatWrapping;
imgTextureStripes2.repeat.set( 100, 100 );
backMaterial2 = new THREE.MeshBasicMaterial( {
map:imgTextureStripes2
} );
backMesh2 = new THREE.Mesh( new THREE.SphereGeometry( 1900, 30, 20 ), backMaterial2 );
backMesh2.scale.x = -1;
scene.add( backMesh2 );
backMesh2.visible = false;
function Box() {
this.posn = new THREE.Vector3();
this.rotation = new THREE.Vector3();
this.speed = getRand(3, 20);
this.init();
}
Box.ORIGIN = new THREE.Vector3();
Box.MAX_DISTANCE = 1000;
Box.INIT_POSN_RANGE = 500;
Box.FRONT_PLANE_Z = 1000;
Box.BACK_PLANE_Z = -1000;
Box.prototype.init = function() {
this.posn.copy(Box.ORIGIN);
this.posn.x = getRand(-Box.INIT_POSN_RANGE,Box.INIT_POSN_RANGE);
this.posn.y = getRand(-Box.INIT_POSN_RANGE,Box.INIT_POSN_RANGE);
this.posn.z = Box.BACK_PLANE_Z;
this.rotation.x = (Math.random() * 360 ) * Math.PI / 180;
this.rotation.y = (Math.random() * 360 ) * Math.PI / 180;
this.rotation.z = (Math.random() * 360 ) * Math.PI / 180;
};
Box.prototype.update = function() {
this.posn.z += this.speed * sketchParams.cubeSpeed ;
this.rotation.x += 0.03;
this.rotation.y += 0.01;
if(this.posn.z > Box.FRONT_PLANE_Z) {
this.init();
}
};
// returns random number within a range
function getRand(minVal, maxVal) {
return minVal + (Math.random() * (maxVal - minVal));
}
var cubesize = 100;
var BOX_COUNT;
var geometry = new THREE.CubeGeometry(cubesize, cubesize, cubesize);
cubeHolder = new THREE.Object3D();
THREE.ImageUtils.crossOrigin = '';
imgTextureStripes = THREE.ImageUtils.loadTexture( "./images/stripes2.jpg" );
cubeMaterial = new THREE.MeshPhongMaterial( {
ambient: 0x111111,
color: 0x666666,
specular: 0x999999,
shininess: 30,
shading: THREE.FlatShading,
map:imgTextureStripes
});
for(i = 0; i < BOX_COUNT; i++) {
var box = new Box();
console.log(box);
boxes.push(box);
var cube = new THREE.Mesh(geometry,cubeMaterial );
cube.position = box.posn;
cube.rotation = box.rotation;
cube.ox = cube.scale.x = Math.random() * 1 + 1;
cube.oy = cube.scale.y = Math.random() * 1 + 1;
cube.oz = cube.scale.z = Math.random() * 1 + 1;
cubeHolder.add(cube);
}
scene.add(cubeHolder);
/* ==================== [ Mini Geometries ] ==================== */
/* ==================== [ Post Processing ] ==================== */
composer = new THREE.EffectComposer(renderer);
composer.addPass(new THREE.RenderPass(scene, camera));
effect = new THREE.ShaderPass(THREE.FilmShader);
effect.uniforms['time'].value = 2.0;
effect.uniforms['nIntensity'].value = 0.4;
effect.uniforms['sIntensity'].value = 0.9;
effect.uniforms['sCount'].value = 1800;
effect.uniforms['grayscale'].value = 0.8;
composer.addPass(effect);
// var dot = new THREE.ShaderPass( THREE.DotScreenShader );
// dot.uniforms[ 'scale' ].value = 400;
// dot.uniforms[ 'tDiffuse' ].value = 40;
// dot.uniforms[ 'tSize' ].value = new THREE.Vector2( 256, 256 );
// composer.addPass(dot);
// var kaleidoPass = new THREE.ShaderPass(THREE.KaleidoShader);
// kaleidoPass.uniforms['sides'].value = 3;
// kaleidoPass.uniforms['angle'].value = 45 * Math.PI / 180;
// composer.addPass(kaleidoPass);
// var mirror = mirrorPass = new THREE.ShaderPass( THREE.MirrorShader );
// // mirror.uniforms[ "tDiffuse" ].value = 1.0;
// // mirror.uniforms[ "side" ].value = 3;
// composer.addPass(mirror);
var glitch = new THREE.GlitchPass(64);
glitch.uniforms[ "tDiffuse" ].value = 1.0;
glitch.uniforms[ 'seed' ].value = Math.random() * 5;
glitch.uniforms[ 'byp' ].value = 0;
// glitch.goWild = true;
composer.addPass(glitch);
var superPass = new THREE.ShaderPass(THREE.SuperShader);
superPass.uniforms.vigDarkness.value = 1;
superPass.uniforms.vigOffset.value = 1.3;
superPass.uniforms.glowSize.value = 2;
superPass.uniforms.glowAmount.value = 1;
composer.addPass( superPass );
var tv = new THREE.ShaderPass( THREE.BadTVShader );
tv.uniforms[ "distortion" ].value = 1;
tv.uniforms[ "distortion2" ].value = .01;
// tv.uniforms[ "time" ].value = 1.5;
tv.uniforms[ "speed" ].value = 8.8;
tv.uniforms[ "rollSpeed" ].value = 0.8;
composer.addPass(tv);
var staticPass = new THREE.ShaderPass( THREE.StaticShader );
staticPass.uniforms[ "amount" ].value = 0.15;
staticPass.uniforms[ "size" ].value = 1.0;
staticPass.uniforms[ "time" ].value = 4.5;
composer.addPass(staticPass);
var effect1 = new THREE.ShaderPass(THREE.RGBShiftShader);
effect1.uniforms['amount'].value = 0.003;
effect1.renderToScreen = true;
composer.addPass(effect1);
function turnOnMirror() {
var mirror = mirrorPass = new THREE.ShaderPass( THREE.MirrorShader );
mirror.renderToScreen = true;
composer.addPass(mirror);
}
function turnOffMirror() {
var mirror = mirrorPass = new THREE.ShaderPass( THREE.MirrorShader );
mirror.renderToScreen = false;
composer.addPass(mirror);
}
// add a timer
clock = new THREE.Clock;
/* ==================== [ Stats ] ==================== */
// stats = new Stats();
// stats.domElement.style.position = 'absolute';
// stats.domElement.style.left = '0px';
// stats.domElement.style.top = '0px';
// document.body.appendChild(stats.domElement);
// document.body.appendChild( renderer.domElement );
/* ==================== [ Shapes ] ==================== */
var quantity = 40;
var shapes = [];
for (var i = 0; i < quantity; i++) {
if (Math.random() < 0.5) {
var geometry = new THREE.RingGeometry(4, 40, 3);
// geometry.position = 0;
// var geometry = new THREE.RingGeometry( 30, 30, 18);
// camera.position.z = 60;
// var geometry = new THREE.RingGeometry( 20, 150, 18);
// var geometry = new THREE.RingGeometry( 20, 150, 18);
// var geometry = new THREE.TorusKnotGeometry( 10, 3, 100, 16 );
}
else {
//var geometry = new THREE.RingGeometry( 4, 40, 3);
// var geometry = new THREE.RingGeometry( 30, 30, 18);
// var geometry = new THREE.RingGeometry( 1, 5, 6 );
// var material = new THREE.MeshBasicMaterial( { color: 0xffff00,
// side: THREE.DoubleSide } );
// var mesh = new THREE.Mesh( geometry, material );
// scene.add( mesh );
}
if (i % 7 === 0) {
var material = new THREE.MeshPhongMaterial({
color: "#ffffff"
});
} else if (i % 2 === 0) {
var material = new THREE.MeshPhongMaterial({
color: "#666666"
});
} else {
var material = new THREE.MeshPhongMaterial({
color: "#333333"
});
}
var mesh = new THREE.Mesh(geometry, material);
mesh.position.z = -i * 3;
// mesh.rotation.z = i;
shapes.push(mesh);
scene.add(mesh);
}
// function refRate() {
// curTime = Date.now();
// delta = curTime - oldTime;
//
// if (delta > interval) {
// oldTime = curTime - (delta % interval);
// updateSize();
// }
//
// }
// Variables
var u_time = 0;
/* ==================== [ Render Function ] ==================== */
var render = function () {
requestAnimationFrame(render);
// var timer = Date.now() * 0.0010;
// camera.lookAt(scene.position);
u_time++;
for (var i = 0; i < quantity; i++) {
// Set rotation change of shapes
shapes[i].position.z += 0.2;
shapes[i].rotation.z += 0;
shapes[i].scale.x = 1 + Math.sin(i + u_time * 0.1) * 0.05;
shapes[i].scale.y = 1 + Math.sin(i + u_time * 0.1) * 0.05;
// shapes[i].scale.y = 120 + Math.tan(i + u_time * 5.0) * 0.5;
// shapes[i].scale.x = 120 + Math.tan(i + u_time * 5.0) * 0.5;
var change = 1.5 + Math.sin(u_time * 0.5) * 0.5;
// Set wireframe & width
if (Math.random() < change) {
shapes[i].material.wireframe = false;
shapes[i].material.wireframeLinewidth = Math.random() * 2;
// if (shapes[i] / 2 === 0) {
// turnOnMirror();
// }
}
else {
shapes[i].material.wireframe = false;
}
if (shapes[i].position.z > 10) {
shapes[i].position.z = -70;
shapes[i].rotation.z = i;
}
}
// Set Point light Intensity & Position
pointLight.intensity = Math.abs(Math.sin(u_time * 0.2) * 2);
pointLight2.intensity = Math.abs(Math.cos(u_time * 0.2) * 2);
pointLight.position.z = Math.abs(Math.sin(u_time * 0.02) * 30);
pointLight2.position.z = Math.abs(Math.cos(u_time * 0.02) * 30);
renderer.render(scene, camera);
composer.render();
var pCount = particleCount;
while (pCount--) {
var camz = getCamera().position.z;
var particle = particles.vertices[pCount];
particle.y = Math.random() * 500 - 250;
//particleSystem.vertices[i].z = camz + Math.random()*600 + 200 ;
particleSystem.geometry.vertices.needsUpdate = true;
}
particleSystem.rotation.y += -0.001;
particleSystem.rotation.z += 0.005;
var normLevel = 0.2;
beamGroup.rotation.x += BEAM_ROT_SPEED;
beamGroup.rotation.y += BEAM_ROT_SPEED;
beamMaterial.opacity = Math.min(normLevel * 0.4, 0.6);
camera.rotation.z += 0.003;
if (doShake) {
var maxshake = 60;
var shake = normLevel * maxshake ;
camera.position.x = Math.random()*shake - shake/2;
camera.position.y = Math.random()*shake - shake/2;
}
camera.rotation.z += 0.003;
// camera.rotation.y += 0.005;
// camera.rotation.x -= 0.003;
//camera.rotation.z += 0.03;
if (doStrobe){
strobeOn = !strobeOn;
if (strobeOn){
light2.intensity = 2;
}
else {
light2.intensity = 0.5;
}
}
else {
light2.intensity = 0.2;
}
// flash background on level threshold
if (normLevel > 0.5 ){
renderer.setClearColor ( 0xFFFFFF );
backMesh2.visible = true;
}
else{
renderer.setClearColor ( 0x000000 );
backMesh2.visible = false;
}
// show stripes for 6 frames on beat
backMesh2.visible = beatTime < 6;
for(var i = 0; i < BOX_COUNT; i++) {
boxes[i].update();
}
if (audioSrc.context.currentTime > 32) {
turnOnMirror();
}
// console.log(audioSrc.context.currentTime);
}
render();

Alterative to merging geometries in Three.js

I'm trying to create a randomized terrain with a square base, which will be exported as an .STL (and 3d printed).
I'm having difficulties combining each seperate geometry into a single mesh. Ostensibly, my shape looks fine, however when I try to 3d Print the .STL, it's clear that there are some gaps in each individual geometry after they are merged.
Currently, I first create the top geometry and then the left, right, front, back, and bottom and finally merge these geometries into a single mesh.
My code right now is:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>STL</title>
<style>
#container {
background: #000;
width: 800px;
height: 600px;
}
</style>
</head>
<body>
<input type="button" id="export" name="export" value="Export" />
<div id="container">
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script src="js/three.min.js"></script>
<script src="js/loaders/STLLoader.js"></script>
<script src="js/exporters/STLExporter.js"></script>
<script src="js/Detector.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src="js/ImprovedNoise.js"></script>
<script src="js/blob/Blob.js"></script>
<script src="js/filesaver/FileSaver.js"></script>
<script src="js/controls/FirstPersonControls.js"></script>
<script>
$(document).ready(function() {
var mouseX, mouseY = 0;
var WIDTH = 800,
HEIGHT = 600;
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000;
var container = $('#container');
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 700;
var controls = new THREE.FirstPersonControls( camera );
controls.movementSpeed = 1000;
controls.lookSpeed = 0.1;
var exporter = new THREE.STLExporter();
var renderer = new THREE.WebGLRenderer();
var camera = new THREE.PerspectiveCamera( VIEW_ANGLE,
ASPECT,
NEAR,
FAR );
var scene = new THREE.Scene();
camera.position.z = 300;
renderer.setSize(WIDTH, HEIGHT);
var clock = new THREE.Clock();
animate();
container.append(renderer.domElement);
var sphereMaterial = new THREE.MeshLambertMaterial(
{
color: 0xCC0000
});
var worldWidth = 100, worldDepth = 100,
worldHalfWidth = worldWidth / 2, worldHalfDepth = worldDepth / 2;
var heightData = generateHeight( worldWidth, worldDepth );
camera.position.y = heightData[ 0] ;
var geometry = new THREE.PlaneGeometry( 300, 300, worldWidth - 1, worldDepth - 1 );
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
for ( var i = 0, l = geometry.vertices.length; i < l; i ++ ) {
geometry.vertices[ i ].y = heightData[ i ] * 2;
}
var leftGeometry = new THREE.PlaneGeometry(300, 1, worldWidth - 1, worldDepth - 1 );
for( var i = 0; i < worldWidth; i++ ) {
for( var j = 0; j < worldDepth; j++ ) {
var index = j * worldWidth + i;
if ( j == worldDepth-1 ) {
leftGeometry.vertices[index].y = geometry.vertices[index].y +1;
}
}
}
var rightGeometry = new THREE.PlaneGeometry(300, 1, worldWidth - 1, worldDepth - 1 );
for( var i = 0; i < worldWidth; i++ ) {
for( var j = 0; j < worldDepth; j++ ) {
var index = j * worldWidth + i;
if ( j == 0 ) {
rightGeometry.vertices[index].y = geometry.vertices[index].y + 1;
}
}
}
var topGeometry = new THREE.PlaneGeometry(1, 300, worldWidth - 1, worldDepth - 1 );
topGeometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
for( var i = 0; i < worldWidth; i++ ) {
for( var j = 0; j < worldDepth; j++ ) {
var index = j * worldWidth + i;
if ( i == 0 ) {
topGeometry.vertices[index].y = geometry.vertices[index].y+1;
}
}
}
var bottomGeometry = new THREE.PlaneGeometry(1, 300, worldWidth - 1, worldDepth - 1 );
bottomGeometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
for( var i = 0; i < worldWidth; i++ ) {
for( var j = 0; j < worldDepth; j++ ) {
var index = j * worldWidth + i;
if ( i == worldWidth-1 ) {
bottomGeometry.vertices[index].y = geometry.vertices[index].y+1;
}
}
}
var baseGeometry = new THREE.PlaneGeometry(300, 300, worldWidth - 1, worldDepth - 1 );
baseGeometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
// ------------------------------
var combined = new THREE.Geometry();
var meshA = new THREE.Mesh( geometry, new THREE.MeshNormalMaterial() );
var meshB = new THREE.Mesh( leftGeometry, new THREE.MeshNormalMaterial() );
var meshC = new THREE.Mesh( rightGeometry, new THREE.MeshNormalMaterial() );
var meshD = new THREE.Mesh( topGeometry, new THREE.MeshNormalMaterial() );
var meshE = new THREE.Mesh( bottomGeometry, new THREE.MeshNormalMaterial() );
var meshF = new THREE.Mesh( baseGeometry, new THREE.MeshNormalMaterial() );
meshB.position.z = worldHalfWidth+100;
meshB.position.y = 0;
meshC.position.y = 0;
meshC.position.z = -worldHalfWidth-100;
meshD.position.x = -worldHalfWidth-99;
meshE.position.x = worldHalfWidth+99;
THREE.GeometryUtils.merge(combined, meshA);
THREE.GeometryUtils.merge(combined, meshB);
THREE.GeometryUtils.merge(combined, meshC);
THREE.GeometryUtils.merge(combined, meshD);
THREE.GeometryUtils.merge(combined, meshE);
THREE.GeometryUtils.merge(combined, meshF);
var out = new THREE.Mesh( combined, new THREE.MeshBasicMaterial({
wireframe: true,
color: 'white'
}));
scene.add(out);
scene.add(camera);
var pointLight = new THREE.PointLight( 0xFFFFFF );
pointLight.position.x = 10;
pointLight.position.y = 50;
pointLight.position.z = 130;
scene.add(pointLight);
renderer.render(scene, camera);
function generateHeight( width, height ) {
var size = width * height, data = new Float32Array( size ),
perlin = new ImprovedNoise(), quality = 1, z = Math.random() * 100;
for ( var i = 0; i < size; i ++ ) {
data[ i ] = 0
}
for ( var j = 0; j < 4; j ++ ) {
for ( var i = 0; i < size; i ++ ) {
var x = i % width, y = ~~ ( i / width );
data[ i ] += Math.abs( perlin.noise( x / quality, y / quality, z ) * quality * 1.75 );
}
quality *= 5;
}
return data;
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
controls.update( clock.getDelta() );
renderer.render( scene, camera );
camera.position.z = ( mouseX - camera.position.x ) * .6;
}
$("#export").click(function(){
var out = exporter.exportScene(scene);
var blob = new Blob([out], {type: 'text/plain'});
saveAs(blob, 'please work.stl');
});
$("#container").mousemove(function(event) {
mouseX = event.pageX;
mouseY = event.pageY;
});
});
</script>
</html>
My questions is: Is there another way to create this type of shape, other than using the GeometryUtils.merge function? Currently, the output shape cannot be 3d printed, and I'm wondering if it's because after the shapes are merged, the final geometry contains gaps. I'm not sure how to remedy this issue.

Categories