move the camera to face the selected object 3js - javascript

so this is the first time i try to learn how to create web with 3 js and tween js. i created multiple object when user click 1 of object it will display its content. but when i try to move the camera to face the object (zooming and focus on the selected the object), the camera just jump to the top of canvas and scan all of the canvas.
(function() {
var DZOOM, OX, OY, aspectt, camera, height, light, loader, render, renderer, scene, view, width, raycaster, intersects, INTERSECTED;
var objects = [],
uuids = [],
names = [];
var container = document.getElementById( 'main-content' );
var windowHalfX = container.offsetWidth / 2;
var windowHalfY = container.offsetHeight / 2;
width = container.offsetWidth;
height = container.offsetHeight;
var raycaster = new THREE.Raycaster();
var lookAtVector = new THREE.Vector3(0,0,0);
var mouse = new THREE.Vector2(),
INTERSECTED;
document.body.appendChild( container );
aspectt = width / height;
scene = new THREE.Scene();
scene.background = new THREE.Color( '#fff' );
camera = new THREE.PerspectiveCamera(85, window.innerWidth / window.innerHeight, 1, 1000);
renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true
});
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize() {
windowHalfX = container.offsetWidth / 2;
windowHalfY = container.offsetHeight / 2;
camera.aspect = container.offsetWidth / container.offsetHeight;
camera.updateProjectionMatrix();
renderer.setSize( container.offsetWidth, container.offsetHeight );
}
renderer.setSize(width, height);
container.appendChild( renderer.domElement );
light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(15, -5, 15);
scene.add(light);
OX = -35;
OY = -5;
if (!deviceIsMobile()) {
camera.position.set(OX + 60, OY - 5, 35);
}
else{
camera.position.set(OX + 30, OY - 10, 20);
}
camera.up = new THREE.Vector3(0, 0, 1);
camera.lookAt(new THREE.Vector3(OX, OY, 0));
container.addEventListener( 'mousedown', onDocumentMouseDown, false );
container.addEventListener( 'touchstart', onDocumentTouchStart, false );
container.addEventListener( 'touchmove', onDocumentTouchMove, false );
function displayCaptionOnClick( event ) {
event.preventDefault();
mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
intersects = raycaster.intersectObjects( objects[0].children, true );
if ( intersects.length > 0 ) {
for( var i = 0; i < intersects.length; i++ ) {
displayCaption(intersects[0].object.uuid);
}
}
}
function redOnHover( event ) {
event.preventDefault();
mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
intersects = raycaster.intersectObjects( objects[0].children, true );
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
INTERSECTED = intersects[ 0 ].object;
INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
INTERSECTED.material.emissive.setHex( 0xff0000 );
}
} else {
if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
INTERSECTED = null;
}
}
function toObj(obj) {
console.log(obj);
var normalMatrix = new THREE.Matrix3().getNormalMatrix( obj.matrixWorld );
var worldNormal = new THREE.Vector3(0,0,1).applyMatrix3( normalMatrix ).normalize();
console.log(worldNormal);
var camPosition = new THREE.Vector3().copy(obj.position).add(worldNormal.multiplyScalar(100));
var rotateTween = new TWEEN.Tween(lookAtVector)
.to({
x: obj.position.x,
y: obj.position.y,
z: obj.position.z
}, 4000)
.easing(TWEEN.Easing.Quadratic.InOut)
.onUpdate(function(){
camera.lookAt(lookAtVector);
})
.onComplete(function(){
lookAtVector.copy(obj.position);
})
.start();
var goTween = new TWEEN.Tween(camera.position)
.to(camPosition, 4000)
.easing(TWEEN.Easing.Quadratic.InOut)
.start();
}
function displayCaption( uuid ) {
var curObj = uuids.indexOf(uuid);
console.log(curObj);
if(curObj<=7){
$('.single-page').hide();
var crnt= $('#'+curObj);
crnt.show();
$('#sidebar').animate({right:0});
redOnHover( event );
}
}
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
function animate() {
requestAnimationFrame(animate);
render();
}
render = function() {
TWEEN.update();
camera.updateMatrixWorld();
return renderer.render(scene, camera);
};
function onDocumentMouseDown( event ) {
event.preventDefault();
container.addEventListener( 'mousemove', onDocumentMouseMove, false );
container.addEventListener( 'mouseup', onDocumentMouseUp, false );
container.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseXOnMouseDown = event.clientX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
checkClick(event);
displayCaptionOnClick( event );
toObj(INTERSECTED);
}
var myObj;
loader = new THREE.ObjectLoader();
loader.load("js/try.dae.json",function ( obj ) {
if (!deviceIsMobile()) {
obj.scale.x = obj.scale.y = obj.scale.z = 2.3;
}
else{
obj.scale.x = obj.scale.y = obj.scale.z = 0.8;
}
// FIXED
obj.position.x = -15;
obj.position.y = -5;
obj.position.z = 24;
obj.rotation.y = 0.15;
obj.rotation.z = 0.6;
myObj = obj;
scene.add( obj );
objects.push(obj);
console.log(objects);
var exclude = ["Cylinder_007", "Cube_005", "Cube_004", "Cylinder_006", "Cylinder_005", "Cylinder_004", "Cylinder_003", "Cylinder_002", "Plane_004", "Plane_003", "Plane_002", "Cube_003", "Cube_002", "Cube", "Cube_001", "Cylinder_001", "Plane_001", "Cylinder", "Torus_001", "Text"];
for( var i = 0; i < objects[0].children.length; i++ ) {
if ( exclude.indexOf(objects[0].children[i].name) < 0 ) {
uuids.push(objects[0].children[i].children[0].uuid);
}
}
for( var i = 0; i < objects[0].children.length; i++ ) {
uuids.push(objects[0].children[i].children[0].uuid);
}
return render();
});
animate();
}).call(this);

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

PointerLockControls threejs "null is not an object (evaluating 'instructions.addEventListener')"

I am trying to integrate PointerLockControls into my project.
I am using the example from the THREEJS examples page and I've basically copied the exact thing over and it still gives me errors in console and won't run. Im using a basic code structure and am importing three via node module and express server.
this is my main html code:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>-</title>
<!--<link rel="stylesheet" href="../css/main.css"> -->
<style>
body {
margin: 0;
overflow: hidden;
}
.blocker {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
}
.instructions {
width: 100%;
height: 100%;
display: -webkit-box;
display: -moz-box;
display: box;
-webkit-box-orient: horizontal;
-moz-box-orient: horizontal;
box-orient: horizontal;
-webkit-box-pack: center;
-moz-box-pack: center;
box-pack: center;
-webkit-box-align: center;
-moz-box-align: center;
box-align: center;
color: #ffffff;
text-align: center;
font-family: Arial, sans-serif;
font-size: 14px;
line-height: 24px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="blocker">
<div class="instructions">
<span style="font-size:36px">Click to play</span>
<br /><br />
Move: WASD<br/>
Jump: SPACE<br/>
Look: MOUSE
</div>
</div>
<script type="module" src="client.js">
</script>
</body>
</html>
and here's my client.js file:
//---------- Imports
import * as THREE from '/build/three.module.js';
//import {OrbitControls} from '/jsm/controls/OrbitControls.js';
import {PointerLockControls} from '/jsm/controls/PointerLockControls.js';
import Stats from '/jsm/libs/stats.module.js';
//---------- Setup
let camera, scene, renderer, controls;
const objects = [];
let raycaster;
let moveForward = false;
let moveBackward = false;
let moveLeft = false;
let moveRight = false;
let canJump = false;
let prevTime = performance.now();
const velocity = new THREE.Vector3();
const direction = new THREE.Vector3();
const vertex = new THREE.Vector3();
const color = new THREE.Color();
init();
animate();
//---------- Controls
function init() {
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 10;
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xffffff );
scene.fog = new THREE.Fog( 0xffffff, 0, 750 );
const light = new THREE.HemisphereLight( 0xeeeeff, 0x777788, 0.75 );
light.position.set( 0.5, 1, 0.75 );
scene.add( light );
controls = new PointerLockControls( camera, document.body );
const blocker = document.getElementById( 'blocker' );
const instructions = document.getElementById( 'instructions' );
instructions.addEventListener( 'click', function () {
controls.lock();
} );
controls.addEventListener( 'lock', function () {
instructions.style.display = 'none';
blocker.style.display = 'none';
} );
controls.addEventListener( 'unlock', function () {
blocker.style.display = 'block';
instructions.style.display = '';
} );
scene.add( controls.getObject() );
const onKeyDown = function ( event ) {
switch ( event.code ) {
case 'ArrowUp':
case 'KeyW':
moveForward = true;
break;
case 'ArrowLeft':
case 'KeyA':
moveLeft = true;
break;
case 'ArrowDown':
case 'KeyS':
moveBackward = true;
break;
case 'ArrowRight':
case 'KeyD':
moveRight = true;
break;
case 'Space':
if ( canJump === true ) velocity.y += 350;
canJump = false;
break;
}
};
const onKeyUp = function ( event ) {
switch ( event.code ) {
case 'ArrowUp':
case 'KeyW':
moveForward = false;
break;
case 'ArrowLeft':
case 'KeyA':
moveLeft = false;
break;
case 'ArrowDown':
case 'KeyS':
moveBackward = false;
break;
case 'ArrowRight':
case 'KeyD':
moveRight = false;
break;
}
};
document.addEventListener( 'keydown', onKeyDown );
document.addEventListener( 'keyup', onKeyUp );
raycaster = new THREE.Raycaster( new THREE.Vector3(), new THREE.Vector3( 0, - 1, 0 ), 0, 10 );
// floor
let floorGeometry = new THREE.PlaneGeometry( 2000, 2000, 100, 100 );
floorGeometry.rotateX( - Math.PI / 2 );
// vertex displacement
let position = floorGeometry.attributes.position;
for ( let i = 0, l = position.count; i < l; i ++ ) {
vertex.fromBufferAttribute( position, i );
vertex.x += Math.random() * 20 - 10;
vertex.y += Math.random() * 2;
vertex.z += Math.random() * 20 - 10;
position.setXYZ( i, vertex.x, vertex.y, vertex.z );
}
floorGeometry = floorGeometry.toNonIndexed(); // ensure each face has unique vertices
position = floorGeometry.attributes.position;
const colorsFloor = [];
for ( let i = 0, l = position.count; i < l; i ++ ) {
color.setHSL( Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75 );
colorsFloor.push( color.r, color.g, color.b );
}
floorGeometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colorsFloor, 3 ) );
const floorMaterial = new THREE.MeshBasicMaterial( { vertexColors: true } );
const floor = new THREE.Mesh( floorGeometry, floorMaterial );
scene.add( floor );
// objects
const boxGeometry = new THREE.BoxGeometry( 20, 20, 20 ).toNonIndexed();
position = boxGeometry.attributes.position;
const colorsBox = [];
for ( let i = 0, l = position.count; i < l; i ++ ) {
color.setHSL( Math.random() * 0.3 + 0.5, 0.75, Math.random() * 0.25 + 0.75 );
colorsBox.push( color.r, color.g, color.b );
}
boxGeometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colorsBox, 3 ) );
for ( let i = 0; i < 500; i ++ ) {
const boxMaterial = new THREE.MeshPhongMaterial( { specular: 0xffffff, flatShading: true, vertexColors: true } );
boxMaterial.color.setHSL( Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75 );
const box = new THREE.Mesh( boxGeometry, boxMaterial );
box.position.x = Math.floor( Math.random() * 20 - 10 ) * 20;
box.position.y = Math.floor( Math.random() * 20 ) * 20 + 10;
box.position.z = Math.floor( Math.random() * 20 - 10 ) * 20;
scene.add( box );
objects.push( box );
}
//
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
//
window.addEventListener( 'resize', onWindowResize );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
const time = performance.now();
if ( controls.isLocked === true ) {
raycaster.ray.origin.copy( controls.getObject().position );
raycaster.ray.origin.y -= 10;
const intersections = raycaster.intersectObjects( objects );
const onObject = intersections.length > 0;
const delta = ( time - prevTime ) / 1000;
velocity.x -= velocity.x * 10.0 * delta;
velocity.z -= velocity.z * 10.0 * delta;
velocity.y -= 9.8 * 100.0 * delta; // 100.0 = mass
direction.z = Number( moveForward ) - Number( moveBackward );
direction.x = Number( moveRight ) - Number( moveLeft );
direction.normalize(); // this ensures consistent movements in all directions
if ( moveForward || moveBackward ) velocity.z -= direction.z * 400.0 * delta;
if ( moveLeft || moveRight ) velocity.x -= direction.x * 400.0 * delta;
if ( onObject === true ) {
velocity.y = Math.max( 0, velocity.y );
canJump = true;
}
controls.moveRight( - velocity.x * delta );
controls.moveForward( - velocity.z * delta );
controls.getObject().position.y += ( velocity.y * delta ); // new behavior
if ( controls.getObject().position.y < 10 ) {
velocity.y = 0;
controls.getObject().position.y = 10;
canJump = true;
}
}
prevTime = time;
renderer.render( scene, camera );
}
here's my app.js with a basic expression server setup
const express = require('express')
const app = express()
const path = require('path')
app.use(express.static(__dirname + '/public'))
app.use('/build', express.static(path.join(__dirname, 'node_modules/three/build')));
app.use('/jsm/', express.static(path.join(__dirname, 'node_modules/three/examples/jsm')));
app.listen(3000, () =>
console.log('Visit http://127.0.0.1:3000')
);
and here ist the console error im experiencing:
[Error] TypeError: null is not an object (evaluating 'instructions.addEventListener')
init (client.js:61)
Modulcode (client.js:33)
evaluate
moduleEvaluation
(anonyme Funktion)
promiseReactionJob
Im probably sitting on a basic mistake but still can't solve it.
Ive been also battling (won the battle tho) to understand how to integrate threejs via es6 module so maybe the mistake is somewhere around there. Im happy to provide further information on my document structure if needed.
Thanks a lot.
David
You have this markup:
<div class="instructions">
And this JS code:
const instructions = document.getElementById( 'instructions' );
You can't query the DOM element in this way since it has no id attribute. You need this:
<div id="instructions">
I am using the example from the THREEJS examples page and I've basically copied the exact thing over
Well, the example does properly use the id attribute.
https://github.com/mrdoob/three.js/blob/94f043c4e105eb73236529231388402da2b07cba/examples/misc_controls_pointerlock.html#L49

How to simulate the wave effect to the content with threejs wave background

I need to simulate the wave effect to the content on top of the wave background using three.js
In my case, the wave effect is working as my expectation but I need the contents will be up and down with the background effect. Like boats in sea waves
Mostly, you can achieve that by adding the wave effects to the background of the scene.
This link may help you
https://codepen.io/mweslander/pen/JreWPa
const SEPARATION = 100, AMOUNTX = 50, AMOUNTY = 50;
let container, stats;
let camera, scene, renderer;
let particles, particle, count = 0;
let mouseX = 0, mouseY = 0;
let windowHalfX = window.innerWidth / 2;
let windowHalfY = window.innerHeight / 2;
function init() {
container = document.createElement( 'div' );
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000; // Good var to change
scene = new THREE.Scene();
particles = new Array();
var PI2 = Math.PI * 2;
var geometry = new THREE.Geometry();
var material = new THREE.SpriteCanvasMaterial({
color: 0xffffff,
program: function ( context ) {
context.beginPath();
context.arc( 0, 0, 0.4, 0, PI2, true );
context.fill();
}
});
var i = 0;
for ( var ix = 0; ix < AMOUNTX; ix ++ ) {
for ( var iy = 0; iy < AMOUNTY; iy ++ ) {
particle = particles[ i ++ ] = new THREE.Sprite( material );
particle.position.x = ix * SEPARATION - ( ( AMOUNTX * SEPARATION ) / 2 );
particle.position.z = iy * SEPARATION - ( ( AMOUNTY * SEPARATION ) / 2 );
scene.add(particle);
if (i > 0) {
geometry.vertices.push( particle.position );
}
}
}
renderer = new THREE.CanvasRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
stats = new Stats();
container.appendChild( stats.dom );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function onDocumentTouchStart(event) {
if (event.touches.length === 1) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
}
}
function onDocumentTouchMove( event ) {
if (event.touches.length === 1) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
}
}
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
renderer.setClearColor( 0x07074e, 1);
camera.position.x += ( mouseX - camera.position.x ) * .05;
camera.position.y += ( - mouseY - camera.position.y ) * .05;
camera.lookAt( scene.position );
var i = 0;
for (var ix = 0; ix < AMOUNTX; ix++) {
for (var iy = 0; iy < AMOUNTY; iy++) {
particle = particles[i++];
particle.position.y = (Math.sin((ix + count) * 0.3) * 50) + (Math.sin((iy + count) * 0.5) * 50);
particle.scale.x = particle.scale.y = (Math.sin((ix + count) * 0.3) + 1) * 4 + (Math.sin((iy + count) * 0.5) + 1) * 4;
}
}
renderer.render(scene, camera);
count += 0.1;
}
init();
animate();

Reduce scene height/width and place canvas into div

I'm working on a Three.js project which you can find over here in its entirety.
As you can see, there is a substantial amount of vertical, unoccupied space surrounding the particles. I was wondering if it was possible to reduce that. If not, is it possible to put it inside a div? I tinkered around with renderer.setSize, but it also stretched the scene; meanwhile putting it inside a div did not produce any result for me.
Unfortunately, the formal training I received in regard to web design and development was scarce, only covering the basics and rudiments; thus, I had to try to understand things such as this online so I apologize if this sounds inane.
var SEPARATION = 70, AMOUNTX = 25, AMOUNTY = 20;
var container, camera, scene, renderer;
var particles, particle, count = 0;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000;
scene = new THREE.Scene();
particles = new Array();
var PI2 = Math.PI * 2;
var material = new THREE.SpriteCanvasMaterial( {
color: 0x333399,
program: function ( context ) {
context.beginPath();
context.arc( 0, 0, 0.5, 0, PI2, true );
context.fill();
}
} );
var i = 0;
for ( var ix = 0; ix < AMOUNTX; ix ++ ) {
for ( var iy = 0; iy < AMOUNTY; iy ++ ) {
particle = particles[ i ++ ] = new THREE.Sprite( material );
particle.position.x = ix * SEPARATION - ( ( AMOUNTX * SEPARATION ) / 2 );
particle.position.z = iy * SEPARATION - ( ( AMOUNTY * SEPARATION ) / 2 );
scene.add( particle );
}
}
renderer = new THREE.CanvasRenderer({alpha:true});
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function onDocumentTouchStart( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
var i = 0;
for ( var ix = 0; ix < AMOUNTX; ix ++ ) {
for ( var iy = 0; iy < AMOUNTY; iy ++ ) {
particle = particles[ i++ ];
particle.position.y = ( Math.sin( ( ix + count ) * 0.3 ) * 50 ) +
( Math.sin( ( iy + count ) * 0.5 ) * 50 );
particle.scale.x = particle.scale.y = ( Math.sin( ( ix + count ) * 0.3 ) + 1 ) * 4 +
( Math.sin( ( iy + count ) * 0.5 ) + 1 ) * 5;
}
}
renderer.render( scene, camera );
count += 0.1;
}
You can set a fixed height for you canvas and use it inside onWindowResize function and init function.
For example:
// set a fixed canvas height
var fixedCanvasHeight = 200;
function init(){
// give separation a new value for a better particle distribution
SEPARATION = window.innerWidth/AMOUNTX;
...
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / fixedCanvasHeight, 1, 10000 );
...
renderer.setSize( window.innerWidth, fixedCanvasHeight );
...
}
function onWindowResize() {
// give separation a new value for a better particle distribution
SEPARATION = window.innerWidth/AMOUNTX;
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / fixedCanvasHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, fixedCanvasHeight );
}
Is this what you're looking for? I've combined what cameraman and WestLangley were suggesting:
I used globalized WIDTH and HEIGHT variables
HEIGHT is a fixed value
Adjust camera.fov to zoom to fit what you want
var SEPARATION = 70,
AMOUNTX = 25,
AMOUNTY = 20,
// Globalized width & height varialbes
WIDTH = window.innerWidth, // width still references the window width
HEIGHT = 200; // height is now a fixed value (if this needs to be dynamic, you'll need to calculate it)
var container, camera, scene, renderer, particles, particle, count = 0;
var mouseX = 0,
mouseY = 0;
var windowHalfX = WIDTH / 2;
var windowHalfY = HEIGHT / 2;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(35, WIDTH / HEIGHT, 1, 10000); // smaller FOV = tighter zoom
camera.position.z = 1000;
scene = new THREE.Scene();
particles = new Array();
var PI2 = Math.PI * 2;
var material = new THREE.SpriteCanvasMaterial({
color: 0x333399,
program: function(context) {
context.beginPath();
context.arc(0, 0, 0.5, 0, PI2, true);
context.fill();
}
});
var i = 0;
for (var ix = 0; ix < AMOUNTX; ix++) {
for (var iy = 0; iy < AMOUNTY; iy++) {
particle = particles[i++] = new THREE.Sprite(material);
particle.position.x = ix * SEPARATION - ((AMOUNTX * SEPARATION) / 2);
particle.position.z = iy * SEPARATION - ((AMOUNTY * SEPARATION) / 2);
scene.add(particle);
}
}
renderer = new THREE.CanvasRenderer({
alpha: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(WIDTH, HEIGHT);
container.appendChild(renderer.domElement);
document.addEventListener('mousemove', onDocumentMouseMove, false);
document.addEventListener('touchstart', onDocumentTouchStart, false);
document.addEventListener('touchmove', onDocumentTouchMove, false);
//
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
windowHalfX = WIDTH / 2;
windowHalfY = HEIGHT / 2;
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
renderer.setSize(WIDTH, HEIGHT);
}
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function onDocumentTouchStart(event) {
if (event.touches.length === 1) {
event.preventDefault();
mouseX = event.touches[0].pageX - windowHalfX;
mouseY = event.touches[0].pageY - windowHalfY;
}
}
function onDocumentTouchMove(event) {
if (event.touches.length === 1) {
event.preventDefault();
mouseX = event.touches[0].pageX - windowHalfX;
mouseY = event.touches[0].pageY - windowHalfY;
}
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
var i = 0;
for (var ix = 0; ix < AMOUNTX; ix++) {
for (var iy = 0; iy < AMOUNTY; iy++) {
particle = particles[i++];
particle.position.y = (Math.sin((ix + count) * 0.3) * 50) +
(Math.sin((iy + count) * 0.5) * 50);
particle.scale.x = particle.scale.y = (Math.sin((ix + count) * 0.3) + 1) * 4 +
(Math.sin((iy + count) * 0.5) + 1) * 5;
}
}
renderer.render(scene, camera);
count += 0.1;
}
<script src="http://threejs.org/build/three.js"></script>
<script src="http://threejs.org/examples/js/renderers/CanvasRenderer.js"></script>
<script src="http://threejs.org/examples/js/renderers/Projector.js"></script>
As far as I understood your question, you have troubles putting the canvas into a div. Of course, within a div you can position and size the canvas much better.
Here the basic code snippets from your updated example: http://codepen.io/anon/pen/ybBVYX
var SCREEN_WIDTH, SCREEN_HEIGHT;
// init
container = $('.webgl');
SCREEN_WIDTH = container.width();
SCREEN_HEIGHT = container.height();
camera = new THREE.PerspectiveCamera( 75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000 );
camera.position.z = 1000;
renderer = new THREE.CanvasRenderer({alpha:true});
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
container.append( renderer.domElement );
// resize
function onWindowResize() {
SCREEN_WIDTH = container.width();
SCREEN_HEIGHT = container.height();
camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT;
camera.updateProjectionMatrix();
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
}
html, body {
color: #ff0000;
height: 100%;
}
.header {
height: 60%;
background-color: #ccc;
}
.webgl {
height: 40%;
}
<div class="header">
<p class="test">Hello</p>
Link
</div>
<div class="webgl"></div>
If you want to keep the aspect ratio, then you would need to set the width or height of your div and the canvas element explicitly, e.g. using jQuery:
SCREEN_WIDTH = container.width();
SCREEN_HEIGHT = SCREEN_WIDTH * aspectRatio;
container.height( SCREEN_HEIGHT );

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>

Categories