cloth simulator using three.js - javascript

I am working on three.js to create cloth simulator like hermes' website just difference is I wanted top-down waves instead of horozontal waves that is in hermes.
However I succeed to make vertical waves as I wanted (here is live also added snippet below)
but as you can see top side is not fixed it is also moving slightly I want to make top side Fixed it should not move like hermes website, and want to make this wave continuous instead of just once when webpage loads, also I noticed once wired thing that when I keep open my modified version in browser for 5-10 minutes it shrinks in size (height & width) and gets too smaller after sometime. I don't know why!!
Can any one expert here do some help me for this three things?
make top side fixed like hermes.
Continuous waves.
Get rid of size reducing.
function Particle( x, y, z, mass, drag, clothFunction ) {
this.position = clothFunction( x, y ); // position
this.previous = clothFunction( x, y ); // previous
this.original = clothFunction( x, y );
this.a = new THREE.Vector3( 0, 0, 0 ); // acceleration
this.mass = mass;
this.drag = drag;
this.invMass = 1 / mass;
this.tmp = new THREE.Vector3();
this.tmp2 = new THREE.Vector3();
}
Particle.prototype.addForce = function( force ) {
this.a.add(
this.tmp2.copy( force ).multiplyScalar( this.invMass )
);
};
Particle.prototype.integrate = function( timesq ) {
var newPos = this.tmp.subVectors( this.position, this.previous );
// newPos.multiplyScalar( this.drag ).add( this.position );
newPos.add( this.position );
newPos.add( this.a.multiplyScalar( timesq ) );
this.tmp = this.previous;
this.previous = this.position;
this.position = newPos;
this.a.set( 0, 0, 0 );
};
function Cloth( mass, w, h, restDistance, drag, clothFunction ) {
function index( u, v ) {
return u + v * ( w + 1 );
}
w = w || 10;
h = h || 10;
this.w = w;
this.h = h;
var particles = [];
var constraints = [];
var u, v;
// Create particles
for ( v = 0; v <= h; v ++ ) {
for ( u = 0; u <= w; u ++ ) {
particles.push(
new Particle( u / w, -v / h, 0, mass, drag, clothFunction )
);
}
}
// Structural
for ( v = 0; v < h; v ++ ) {
for ( u = 0; u < w; u ++ ) {
constraints.push( [
particles[ index( u, v ) ],
particles[ index( u, v + 1 ) ],
restDistance
] );
constraints.push( [
particles[ index( u, v ) ],
particles[ index( u + 1, v ) ],
restDistance
] );
}
}
for ( u = w, v = 0; v < h; v ++ ) {
constraints.push( [
particles[ index( u, v ) ],
particles[ index( u, v + 1 ) ],
restDistance
] );
}
for ( v = h, u = 0; u < w; u ++ ) {
constraints.push( [
particles[ index( u, v ) ],
particles[ index( u + 1, v ) ],
restDistance
] );
}
this.particles = particles;
this.constraints = constraints;
this.index = index;
}
function animatedProduct( container, size, canvas, image ) {
this.DAMPING = .02;
this.DRAG = 1 - this.DAMPING
this.MASS = 2000;
this.STIFFNESS = 1;
this.SEGMENTS = 40;
this.canvas = canvas;
this.size = size;
this.demoMode = !0;
this.startTime = Date.now();
this.image = image;
this.restDistance = this.size / this.SEGMENTS;
this.container = container;
this.gravity = new THREE.Vector3( 0, -80, 0 ).multiplyScalar( this.MASS );
this.TIMESTEP_SQ = Math.pow(.01, 2);
this.tmpForce = new THREE.Vector3;
this.diff = new THREE.Vector3;
this.pins = [];
for( var i = 0; i <= this.SEGMENTS; i++ )
this.pins.push( i );
this.degree = 0;
this.wave = 0;
}
animatedProduct.prototype = {
createPlane: function( width, height ) {
return function(c, d) {
var e = ( c - .5 ) * width,
f = ( d + .5 ) * height,
g = 0;
return new THREE.Vector3( e, f, g )
}
},
satisfyConstraints: function( p1, p2, distance ) {
this.diff.subVectors( p2.position, p1.position );
var currentDist = this.diff.length();
if ( currentDist === 0 )
return; // prevents division by 0
this.diff.normalize();
var correction = this.diff.multiplyScalar( currentDist - distance );
var correctionHalf = correction.multiplyScalar( 0.5 );
p1.position.add( correctionHalf );
p2.position.sub( correctionHalf );
},
simulate: function( timestep_sq ) {
var b, c, d, e, f, g, h, i, j = this.clothGeometry.faces;
for (d = this.cloth.particles, b = 0, c = d.length; c > b; b++) {
e = d[b];
e.addForce(this.gravity);
e.integrate(timestep_sq);
}
for (f = this.cloth.constraints, c = f.length, b = 0; c > b; b++) {
g = f[b];
this.satisfyConstraints(g[0], g[1], g[2]);
}
for (d = this.cloth.particles, b = 0, c = d.length; c > b; b++) {
e = d[b];
e.position.x = e.original.x;
}
for (b = 0, c = this.pins.length; c > b; b++) {
var k = this.pins[ b ],
l = d[ k ];
l.position.y = l.original.y;
l.position.x = l.original.x;
l.position.z = l.position.z + this.wave;
}
if( this.degree <= 6 ) {
this.wave = Math.sin( this.degree ) * 6;
this.degree += 0.017 * 42;
}
else
this.wave = 0;
},
init: function() {
this.clothFunction = this.createPlane( this.size, this.size );
this.cloth = new Cloth( this.MASS, this.SEGMENTS, this.SEGMENTS, this.restDistance, this.DRAG, this.createPlane( this.size, this.size ) );
this.scene = new THREE.Scene;
this.camera = new THREE.PerspectiveCamera( 45, this.canvas.width / this.canvas.height, 1, 1e4 );
this.camera.position.y = 0;
this.camera.position.z = 1e3;
this.scene.add( this.camera );
this.light = new THREE.DirectionalLight( 16777215, 1 );
this.light.position.set( 20, -20, 100 );
this.scene.add( this.light );
THREE.ImageUtils.crossOrigin = "";
var texture = THREE.ImageUtils.loadTexture( this.image, {}, function() {
this.canvas.classList.add("play")
}.bind( this ) );
texture.flipY = !1;
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.anisotropy = 16;
var b = new THREE.MeshPhongMaterial({
ambient: 16777215,
shininess: 20,
map: texture,
side: THREE.DoubleSide
});
this.clothGeometry = new THREE.ParametricGeometry( this.clothFunction, this.cloth.w, this.cloth.h );
this.clothGeometry.dynamic = !0;
this.clothGeometry.computeFaceNormals();
var c = {
texture: {
type: "t",
value: texture
}
},
d = "varying vec2 vUV;void main() {vUV = 0.75 * uv;vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );gl_Position = projectionMatrix * mvPosition;}",
e = "uniform sampler2D texture;varying vec2 vUV;vec4 pack_depth( const in float depth ) {const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );vec4 res = fract( depth * bit_shift );res -= res.xxyz * bit_mask;return res;}void main() {vec4 pixel = texture2D( texture, vUV );if ( pixel.a < 0.5 ) discard;gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );}";
this.object = new THREE.Mesh( this.clothGeometry, b );
this.object.position.set( 0, 0, 0 );
this.scene.add( this.object );
this.object.customDepthMaterial = new THREE.ShaderMaterial({
uniforms: c,
vertexShader: d,
fragmentShader: e
});
this.renderer = new THREE.WebGLRenderer({
antialias: !0,
canvas: this.canvas
});
this.renderer.setSize( this.canvas.width, this.canvas.height );
this.renderer.setClearColor( 16777215, 1 );
this.renderer.autoClear = !1;
this.renderer.autoClearDepth = !1;
this.container.appendChild( this.renderer.domElement );
this.renderer.gammaInput = !0;
this.renderer.gammaOutput = !0;
this.canvas.addEventListener("mousedown", this.onClick.bind( this ), !1 );
for (var f = 0; 20 > f; f++) this.simulate(this.TIMESTEP_SQ);
this.play();
},
onClick: function(a) {
},
animate: function() {
this.animationFrame = window.requestAnimationFrame(this.animate.bind(this));
this.simulate(this.TIMESTEP_SQ);
this.render();
},
pause: function() {
window.cancelAnimationFrame( this.animationFrame );
},
play: function() {
this.scene ? this.animate() : this.init();
},
render: function() {
for ( var a = this.cloth.particles, b = 0, c = a.length; c > b; b++ )
this.clothGeometry.vertices[ b ].copy( a[ b ].position );
this.clothGeometry.computeFaceNormals();
this.clothGeometry.computeVertexNormals();
this.clothGeometry.normalsNeedUpdate = !0;
this.clothGeometry.verticesNeedUpdate = !0;
this.camera.lookAt( this.scene.position );
this.renderer.clear();
this.renderer.render( this.scene, this.camera );
},
stop: function() {
this.pause();
this.canvas.parentNode.removeChild( this.canvas );
}
};
var size = 700,
container = document.getElementById( "product-container" ),
image = "http://media.hermes.com/media/catalog/product/import/S/S01/S011/item/flat/hd/H001485S-17.jpg",
canvas = document.createElement( "canvas" );
canvas.width = canvas.height = 600 + 20,
canvas.id = "product",
container.appendChild( canvas ),
productAnimation = new animatedProduct( container, size, canvas, image );
productAnimation.play();
<script src="http://maksible.com/cloth/cloth_slower_v2/cloth/three.min.js"></script>
<body>
<div id="product-container"></div>
<script type="text/javascript" src="three.min.js"></script>
<script type="text/javascript" src="logic.js"></script>
</body>

Here is the solution with three.js but with different logic than yours. Hope it might be useful for you.
var size = 500;
var img = 'Image.jpg';
window.onload = function() {
createWGL();
render();
}
// render
//
function render() {
requestAnimationFrame( render );
if(window.mat)
mat.uniforms.time.value = now();
ctx.render( scn, cam );
}
// create renderer
//
function createWGL() {
// check desktop/mobile
window.desk = !(/Android|webOS|iPhone|iPad|BlackBerry|Windows Phone|Opera Mini|IEMobile|Mobile/i.test(navigator.userAgent));
window.ctx = new THREE.WebGLRenderer({antialias:window.desk});
ctx.setClearColor( 0xffffff );
ctx.setPixelRatio( window.devicePixelRatio );
ctx.setSize( size, size );
// camera
window.cam = new THREE.PerspectiveCamera( 90, 1, 1, 30 );
cam.position.z = 25;
// scene
window.scn = new THREE.Scene();
// canvas
window.cvs = createCanvas();
scn.add( cvs );
loadCanvasTexture( img );
// clear viewport
ctx.render( scn, cam );
document.body.appendChild( ctx.domElement );
}
// now
//
function now(){
return performance.now() * 0.001;
}
// load canvas texture
//
function loadCanvasTexture( path ) {
if(window.tex)
window.tex.dispose();
cvs.visible = false;
window.tex = new THREE.TextureLoader().load( path, function(){
cvs.visible = true;
});
window.tex.anisotropy = ctx.getMaxAnisotropy();
window.mat.uniforms.tex.value = window.tex;
}
// create canvas
//
function createCanvas() {
window.mat = new THREE.RawShaderMaterial({
uniforms: {
time: { value: now() },
tex: { value: null }
},
vertexShader: 'precision mediump float;precision mediump int;uniform mat4 modelViewMatrix;'+
'uniform mat4 projectionMatrix;attribute vec2 pos;uniform float time;varying vec2 uv;varying float amb;'+
'float d(float y){return cos(sin(time/2.)+time/2.+y/2.14)*sin(time+y/4.17)*(.5-y/40.)*1.5;}'+
'void main(){vec3 p=vec3( pos.x+sin(time/3.)*(.5-pos.y/40.), pos.y+sin(time)*(.5-pos.y/40.)/2., d(pos.y));amb=(d(pos.y-1.)-d(pos.y+1.))/4.;'+
'uv=vec2(pos.x/40.+.5,pos.y/40.+.5);gl_Position=projectionMatrix*modelViewMatrix*vec4(p,1.);}',
fragmentShader: 'precision mediump float;precision mediump int;uniform sampler2D tex;varying vec2 uv;varying float amb;'+
'void main(){vec4 col=texture2D(tex,uv)+amb;gl_FragColor=vec4(col.xyz,1.);}'
});
var d = 40,d2=~~(d/2),i,j,k,n,fi,v,m,z1=-1,z2;
fi = new Uint16Array( d * d * 6 );
v = new Int8Array( (d+1) * (d+1) * 2 );
for(j=0;j<=d;j++)
for(i=0;i<=d;i++) {
k = i + j*(d+1);
v[k*2] = i - d2;
v[k*2+1] = j - d2;
if(i<d&&j<d) {
n = (i + j*d) * 6;
fi[n] = k;
fi[n+1] = k + 1;
fi[n+2] = k + d + 1;
fi[n+3] = k + d + 1;
fi[n+4] = k + 1;
fi[n+5] = k + d + 2;
}
}
for(i=0,j=-1;i<fi.length;i++)
if(j<fi[i])
j = fi[i];
m = new THREE.Mesh( new THREE.BufferGeometry(), mat );
m.geometry.setIndex( new THREE.BufferAttribute( fi, 1 ));
m.geometry.addAttribute( 'pos', new THREE.BufferAttribute( v, 2 ));
return m;
}
just change your logic code with this and run.
cheers!

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

Canvas Impulse Animation Effect

I'm studying the following canvas animation by Matei Copot.
Can someone explain how the "impulse"/shooting effect works, and how, say I can simplify the code to only have 3 stationary dots a, b, and c (while showing the impulse effect between a-> b and between b -> c)?
var w = c.width = window.innerWidth,
h = c.height = window.innerHeight,
ctx = c.getContext( '2d' ),
opts = {
range: 180,
baseConnections: 3,
addedConnections: 5,
baseSize: 5,
minSize: 1,
dataToConnectionSize: .4,
sizeMultiplier: .7,
allowedDist: 40,
baseDist: 40,
addedDist: 30,
connectionAttempts: 100,
dataToConnections: 1,
baseSpeed: .04,
addedSpeed: .05,
baseGlowSpeed: .4,
addedGlowSpeed: .4,
rotVelX: .003,
rotVelY: .002,
repaintColor: '#111',
connectionColor: 'hsla(200,60%,light%,alp)',
rootColor: 'hsla(0,60%,light%,alp)',
endColor: 'hsla(160,20%,light%,alp)',
dataColor: 'hsla(40,80%,light%,alp)',
wireframeWidth: .1,
wireframeColor: '#88f',
depth: 250,
focalLength: 250,
vanishPoint: {
x: w / 2,
y: h / 2
}
},
squareRange = opts.range * opts.range,
squareAllowed = opts.allowedDist * opts.allowedDist,
mostDistant = opts.depth + opts.range,
sinX = sinY = 0,
cosX = cosY = 0,
connections = [],
toDevelop = [],
data = [],
all = [],
tick = 0,
totalProb = 0,
animating = false,
Tau = Math.PI * 2;
ctx.fillStyle = '#222';
ctx.fillRect( 0, 0, w, h );
ctx.fillStyle = '#ccc';
ctx.font = '50px Verdana';
ctx.fillText( 'Calculating Nodes', w / 2 - ctx.measureText( 'Calculating Nodes' ).width / 2, h / 2 - 15 );
window.setTimeout( init, 4 ); // to render the loading screen
function init(){
connections.length = 0;
data.length = 0;
all.length = 0;
toDevelop.length = 0;
var connection = new Connection( 0, 0, 0, opts.baseSize );
connection.step = Connection.rootStep;
connections.push( connection );
all.push( connection );
connection.link();
while( toDevelop.length > 0 ){
toDevelop[ 0 ].link();
toDevelop.shift();
}
if( !animating ){
animating = true;
anim();
}
}
function Connection( x, y, z, size ){
this.x = x;
this.y = y;
this.z = z;
this.size = size;
this.screen = {};
this.links = [];
this.probabilities = [];
this.isEnd = false;
this.glowSpeed = opts.baseGlowSpeed + opts.addedGlowSpeed * Math.random();
}
Connection.prototype.link = function(){
if( this.size < opts.minSize )
return this.isEnd = true;
var links = [],
connectionsNum = opts.baseConnections + Math.random() * opts.addedConnections |0,
attempt = opts.connectionAttempts,
alpha, beta, len,
cosA, sinA, cosB, sinB,
pos = {},
passedExisting, passedBuffered;
while( links.length < connectionsNum && --attempt > 0 ){
alpha = Math.random() * Math.PI;
beta = Math.random() * Tau;
len = opts.baseDist + opts.addedDist * Math.random();
cosA = Math.cos( alpha );
sinA = Math.sin( alpha );
cosB = Math.cos( beta );
sinB = Math.sin( beta );
pos.x = this.x + len * cosA * sinB;
pos.y = this.y + len * sinA * sinB;
pos.z = this.z + len * cosB;
if( pos.x*pos.x + pos.y*pos.y + pos.z*pos.z < squareRange ){
passedExisting = true;
passedBuffered = true;
for( var i = 0; i < connections.length; ++i )
if( squareDist( pos, connections[ i ] ) < squareAllowed )
passedExisting = false;
if( passedExisting )
for( var i = 0; i < links.length; ++i )
if( squareDist( pos, links[ i ] ) < squareAllowed )
passedBuffered = false;
if( passedExisting && passedBuffered )
links.push( { x: pos.x, y: pos.y, z: pos.z } );
}
}
if( links.length === 0 )
this.isEnd = true;
else {
for( var i = 0; i < links.length; ++i ){
var pos = links[ i ],
connection = new Connection( pos.x, pos.y, pos.z, this.size * opts.sizeMultiplier );
this.links[ i ] = connection;
all.push( connection );
connections.push( connection );
}
for( var i = 0; i < this.links.length; ++i )
toDevelop.push( this.links[ i ] );
}
}
Connection.prototype.step = function(){
this.setScreen();
this.screen.color = ( this.isEnd ? opts.endColor : opts.connectionColor ).replace( 'light', 30 + ( ( tick * this.glowSpeed ) % 30 ) ).replace( 'alp', .2 + ( 1 - this.screen.z / mostDistant ) * .8 );
for( var i = 0; i < this.links.length; ++i ){
ctx.moveTo( this.screen.x, this.screen.y );
ctx.lineTo( this.links[ i ].screen.x, this.links[ i ].screen.y );
}
}
Connection.rootStep = function(){
this.setScreen();
this.screen.color = opts.rootColor.replace( 'light', 30 + ( ( tick * this.glowSpeed ) % 30 ) ).replace( 'alp', ( 1 - this.screen.z / mostDistant ) * .8 );
for( var i = 0; i < this.links.length; ++i ){
ctx.moveTo( this.screen.x, this.screen.y );
ctx.lineTo( this.links[ i ].screen.x, this.links[ i ].screen.y );
}
}
Connection.prototype.draw = function(){
ctx.fillStyle = this.screen.color;
ctx.beginPath();
ctx.arc( this.screen.x, this.screen.y, this.screen.scale * this.size, 0, Tau );
ctx.fill();
}
function Data( connection ){
this.glowSpeed = opts.baseGlowSpeed + opts.addedGlowSpeed * Math.random();
this.speed = opts.baseSpeed + opts.addedSpeed * Math.random();
this.screen = {};
this.setConnection( connection );
}
Data.prototype.reset = function(){
this.setConnection( connections[ 0 ] );
this.ended = 2;
}
Data.prototype.step = function(){
this.proportion += this.speed;
if( this.proportion < 1 ){
this.x = this.ox + this.dx * this.proportion;
this.y = this.oy + this.dy * this.proportion;
this.z = this.oz + this.dz * this.proportion;
this.size = ( this.os + this.ds * this.proportion ) * opts.dataToConnectionSize;
} else
this.setConnection( this.nextConnection );
this.screen.lastX = this.screen.x;
this.screen.lastY = this.screen.y;
this.setScreen();
this.screen.color = opts.dataColor.replace( 'light', 40 + ( ( tick * this.glowSpeed ) % 50 ) ).replace( 'alp', .2 + ( 1 - this.screen.z / mostDistant ) * .6 );
}
Data.prototype.draw = function(){
if( this.ended )
return --this.ended; // not sre why the thing lasts 2 frames, but it does
ctx.beginPath();
ctx.strokeStyle = this.screen.color;
ctx.lineWidth = this.size * this.screen.scale;
ctx.moveTo( this.screen.lastX, this.screen.lastY );
ctx.lineTo( this.screen.x, this.screen.y );
ctx.stroke();
}
Data.prototype.setConnection = function( connection ){
if( connection.isEnd )
this.reset();
else {
this.connection = connection;
this.nextConnection = connection.links[ connection.links.length * Math.random() |0 ];
this.ox = connection.x; // original coordinates
this.oy = connection.y;
this.oz = connection.z;
this.os = connection.size; // base size
this.nx = this.nextConnection.x; // new
this.ny = this.nextConnection.y;
this.nz = this.nextConnection.z;
this.ns = this.nextConnection.size;
this.dx = this.nx - this.ox; // delta
this.dy = this.ny - this.oy;
this.dz = this.nz - this.oz;
this.ds = this.ns - this.os;
this.proportion = 0;
}
}
Connection.prototype.setScreen = Data.prototype.setScreen = function(){
var x = this.x,
y = this.y,
z = this.z;
// apply rotation on X axis
var Y = y;
y = y * cosX - z * sinX;
z = z * cosX + Y * sinX;
// rot on Y
var Z = z;
z = z * cosY - x * sinY;
x = x * cosY + Z * sinY;
this.screen.z = z;
// translate on Z
z += opts.depth;
this.screen.scale = opts.focalLength / z;
this.screen.x = opts.vanishPoint.x + x * this.screen.scale;
this.screen.y = opts.vanishPoint.y + y * this.screen.scale;
}
function squareDist( a, b ){
var x = b.x - a.x,
y = b.y - a.y,
z = b.z - a.z;
return x*x + y*y + z*z;
}
function anim(){
window.requestAnimationFrame( anim );
ctx.globalCompositeOperation = 'source-over';
ctx.fillStyle = opts.repaintColor;
ctx.fillRect( 0, 0, w, h );
++tick;
var rotX = tick * opts.rotVelX,
rotY = tick * opts.rotVelY;
cosX = Math.cos( rotX );
sinX = Math.sin( rotX );
cosY = Math.cos( rotY );
sinY = Math.sin( rotY );
if( data.length < connections.length * opts.dataToConnections ){
var datum = new Data( connections[ 0 ] );
data.push( datum );
all.push( datum );
}
ctx.globalCompositeOperation = 'lighter';
ctx.beginPath();
ctx.lineWidth = opts.wireframeWidth;
ctx.strokeStyle = opts.wireframeColor;
all.map( function( item ){ item.step(); } );
ctx.stroke();
ctx.globalCompositeOperation = 'source-over';
all.sort( function( a, b ){ return b.screen.z - a.screen.z } );
all.map( function( item ){ item.draw(); } );
/*ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.arc( opts.vanishPoint.x, opts.vanishPoint.y, opts.range * opts.focalLength / opts.depth, 0, Tau );
ctx.stroke();*/
}
window.addEventListener( 'resize', function(){
opts.vanishPoint.x = ( w = c.width = window.innerWidth ) / 2;
opts.vanishPoint.y = ( h = c.height = window.innerHeight ) / 2;
ctx.fillRect( 0, 0, w, h );
});
window.addEventListener( 'click', init );
canvas {
position: absolute;
top: 0;
left: 0;
}
<canvas id=c></canvas>
<!--
ALGORITHM:
structure:
- gen( x,y,z ):
- create node at x,y,z // blue
- append some children to list:
- within a certain distance to parent
- outside a certain distance from any node
- within a global distance
- if no children
- don't append any
- set as end node // green-ish
- gen( 0,0,0 ) // red
- while list has items
- gen( position of first item )
- remove first item
impulse behaviour:
- pick( node ):
- if node is end node
- pick( original node )
- else
- pick( random node from node children )
- pick( original node)
-->

selecting nearby hexes around a hex

I'm trying to select all hexes in a given range. However I'm getting weird results while implement this code found on Amit Patel's page.
var results = []
for each -N ≤ dx ≤ N:
for each max(-N, -dx-N) ≤ dy ≤ min(N, -dx+N):
var dz = -dx-dy
results.append(cube_add(center, Cube(dx, dy, dz)))
This is what I have so far:
var center = this._cel.copy( hex.coords );
var dx = range - center.q;
var dy = range - center.r;
var results = [];
for (var q = -range; q <= dx; q++ ) {
var r1 = Math.max(-range, -q - range);
var r2 = Math.min(range, -q + range);
for ( var r = r1; r <= r2; r++ ) {
//console.log( q, r, -q-r )
var c = new Cell(q, r, -q-r)
results.push( c.add( center ) );
}
}
I suppose that the loop constrains need to me a little bit amended and make use of the dx, dy values.
<body>
<canvas width="420px" height="420px" id="myCanvas" style="margin:0; padding:0; border:1px solid #d3d3d3;"></canvas>
</body>
<script id="hexagon">
function Point( pos ) {
this.x = 0;
this.y = 0;
if( typeof( pos ) !== "undefined" ){
this.x = pos[0];
this.y = pos[1];
}
};
function Cell( _q, _r, _s ){ //// direction ///
this.q = _q;
this.r = _r;
this.s = _s;
this._hashID = null;
this.generateHashID();
}
Cell.prototype = {
constructor: Cell,
add: function( d ){
this.q += d.q;
this.r += d.r;
this.s += d.s;
this.generateHashID();
return this;
},
copy: function( c ){
this.set( c.q, c.r, c.s );
return this;
},
set: function( _q, _r, _s ){
this.q = _q;
this.r = _r;
this.s = _s;
this.generateHashID();
return this;
},
generateHashID: function(){
this._hashID = this.q+"."+this.r+"."+this.s;
},
getHashID: function(){
return this._hashID;
},
round: function(){
var q = Math.trunc(Math.round(this.q));
var r = Math.trunc(Math.round(this.r));
var s = Math.trunc(Math.round(this.s));
var q_diff = Math.abs(q - this.q);
var r_diff = Math.abs(r - this.r);
var s_diff = Math.abs(s - this.s);
if (q_diff > r_diff && q_diff > s_diff){
q = -r - s;
}else if (r_diff > s_diff){
r = -q - s;
}else{
s = -q - r;
}
return this.set( q, r, s );
}
}
var Hex = function( coords, l_ ){ //// [axial], [cartesian] , layout
this.coords = new Cell( coords[0], coords[1], coords[2] );
this.content = -2;
this.pos = this.coords; //// set primary coorinate type ///
this.neighbors = [];
this.layout = l_;
this.corners = [];
this.center = this.get_center_p();
//this.id = this.generate_id( cart_coord );
this.colors = {
"base" : {
filling : "#008844",
border : "#FFDD88",
},
"selected": {
filling: "#00cc00"
},
"hovered": {
filling: "#006600"
},
"path" : {
filling: "#80ff00"
},
"obstacle" : {
filling: "#86592d"
},
"neighbor": {
filling: "#ffbf00"
}
}
this.states = {
"selected" : false,
"hovered" : false,
"isPath": false,
"isObstacle": false,
"isNeighbor": false
}
this.generate_corners();
};
Hex.prototype = {
constructor: Hex,
get_corner_offset: function( corner ){
var angle = 2.0 * Math.PI * (corner + this.layout.orientation.start_angle) / 6;
return new Point( [ size.x * Math.cos(angle), size.y * Math.sin(angle) ] );
},
generate_corners: function( h ){
var offset = null, angle = 0;
var size = this.layout.size;
for (var i = 0; i < 6; i++) {
angle = 2.0 * Math.PI * (i + this.layout.orientation.start_angle) / 6;
offset = new Point( [ size.x * Math.cos(angle), size.y * Math.sin(angle )] );
this.corners.push(
new Point( [ this.center.x + offset.x, this.center.y + offset.y ] )
);
}
},
draw: function( ctx ){
var points = this.corners;
ctx.beginPath();
ctx.moveTo( points[0].x, points[0].y );
for(var i = 1; i < points.length; i++){
var p = points[i];
ctx.lineTo(p.x, p.y);
}
ctx.closePath();
//// fill Hex ///
if( this.checkState("selected") ){
ctx.fillStyle = this.colors.selected.filling;
}else if( this.checkState("hovered") ){
ctx.fillStyle = this.colors.hovered.filling;
}else if( this.checkState("isPath") ){
ctx.fillStyle = this.colors.path.filling;
}else if( this.checkState("isNeighbor") ){
ctx.fillStyle = this.colors.neighbor.filling;
}else if( this.checkState("isObstacle") ){
ctx.fillStyle = this.colors.obstacle.filling;
}else{
ctx.fillStyle = this.colors.base.filling;
}
ctx.fill();
//// draw border ///
ctx.lineWidth = 1;
ctx.strokeStyle = "#19334d";
ctx.stroke();
this.draw_coords( ctx );
this.draw_center_point( ctx );
},
add_neighbor: function( neighbor ){
this.neighbors.push( neighbor );
},
show_neighbors: function(){
for( var nb = 0, nb_l = this.neighbors.length; nb < nb_l; nb++ ){
this.neighbors[nb].changeState("isNeighbor", true);
}
},
hide_neighbors: function(){
for( var nb = 0, nb_l = this.neighbors.length; nb < nb_l; nb++ ){
this.neighbors[nb].changeState("isNeighbor", false);
}
},
draw_coords: function( ctx ){
var text = this.coords.q+" : "+ this.coords.s;
var text_z = this.coords.r;
var metrics1 = ctx.measureText(text);
var metrics2 = ctx.measureText(text_z);
var w1 = metrics1.width;
var w2 = metrics2.width;
var h = 8;
ctx.font = h+'pt Calibri bold';
ctx.textAlign = 'center';
ctx.fillStyle = '#FFFFFF';
ctx.fillText(text, this.center.x, this.center.y + (h/2) - 5 );
ctx.fillText(text_z, this.center.x, this.center.y + (h/2) + 7 );
},
get_center_p: function(){
var M = this.layout.orientation;
var x = ( M.f0 * this.pos.q + M.f1 * this.pos.r ) * this.layout.size.x;
var y = ( M.f2 * this.pos.q + M.f3 * this.pos.r ) * this.layout.size.y;
return new Point([
x + this.layout.origin.x,
y + this.layout.origin.y
]);
},
draw_center_point: function( ctx ){
ctx.beginPath();
ctx.lineWidth="1";
ctx.fillStyle="red";
ctx.arc( this.center.x , this.center.y , 2, 0 ,2*Math.PI);
ctx.closePath();
ctx.stroke();
ctx.fill();
},
generate_id: function( coords ){
return parseInt( coords[0]+''+coords[1] );
},
checkState: function( state ){
return this.states[ state ];
},
changeState: function( state , value){
this.states[ state ] = value;
},
trigger: function( ev_name ){
if( this.events[ ev_name ] ){
this.events[ ev_name ].call( this );
}
},
setContent: function( type ){
this.content = type;
this.changeState( "isObstacle" , true );
},
hover: function(){
if( ! this.checkState("isPath") ){
this.trigger("hover");
}
},
clear_hover: function(){
if( ! this.checkState("isPath") ){
this.trigger("clear_hover");
}
},
select: function(){
this.trigger("select");
//this.show_neighbors();
},
unselect: function(){
this.trigger("unselect");
},
events: {
select: function(){
this.changeState("selected", true);
this.changeState("hovered", false);
},
unselect: function(){
this.changeState("selected", false);
},
hover: function(){
this.changeState("hovered", true);
},
clear_hover: function(){
this.changeState("hovered", false);
}
}
};
</script>
<script id="grid">
var Grid = function( size, hex_size, origin, ctx_pos, layout_type ){
this.size = size;
this.grid_r = size/2;
this.layout_type = layout_type;
this.layout = this.set_layout( this.layout_types[this.layout_type], hex_size, origin );
this.hexes = [];
this.hovered = [null, null]; //// [cur, prev] ///
this.selected = [null, null]; ///// [cur , prev] ///
this.dots = [];
this._list = [];
this._cel = new Cell();
this._directions = [new Cell(+1, 0, -1), new Cell(+1, -1, 0), new Cell(0, -1, +1),
new Cell(-1, 0, +1), new Cell(-1, +1, 0), new Cell(0, +1, -1)];
this.generate();
this.add_neighbors();
this.mouse = new Point();
this.mouse_events( new Point( ctx_pos ) );
}
Grid.prototype = {
constructor: Grid,
layout_types: {
"pointy": [
[ Math.sqrt(3.0), Math.sqrt(3.0) / 2.0, 0.0, 3.0 / 2.0], //// 2x2 forward matrix
[ Math.sqrt(3.0) / 3.0, -1.0 / 3.0, 0.0, 2.0 / 3.0], ///// 2x2 inverse matrix
0.5
], //// starting angle in multiples of 60° /////
"flat": [
[3.0 / 2.0, 0.0, Math.sqrt(3.0) / 2.0, Math.sqrt(3.0)], //// 2x2 forward matrix
[2.0 / 3.0, 0.0, -1.0 / 3.0, Math.sqrt(3.0) / 3.0], ///// 2x2 inverse matrix
1.0
]
},
set_layout: function( orn_type , hex_s_, ogn_ ){
return {
orientation: this.set_orientation( orn_type ), ///// orientation type ///
size: new Point( [ hex_s_ , hex_s_ ] ), ///// hex size ///
origin: new Point( ogn_ ) //// Grid center /////
}
},
set_orientation: function( opts ){ /// [0] : forward_matrix, [1] : inverse_matrix, [2] : starting_angle
return {
f0: opts[0][0], f1: opts[0][1], f2: opts[0][2], f3: opts[0][3], b0: opts[1][0], b1: opts[1][1], b2: opts[1][2], b3: opts[1][3], start_angle: opts[2]
}
},
get_hex_at_p: function( p ){ //// point ///
var M = this.layout.orientation;
var pt = new Point( [ (p.x - this.layout.origin.x) / this.layout.size.x, (p.y - this.layout.origin.y) / this.layout.size.y ] );
var q = M.b0 * pt.x + M.b1 * pt.y;
var r = M.b2 * pt.x + M.b3 * pt.y;
var c = this._cel.set( q, r, -q-r );
return c.round();
},
generate: function(){
var n_hex = null;
for (var q = -this.grid_r; q <= this.grid_r; q++) {
var r1 = Math.max(-this.grid_r, -q - this.grid_r);
var r2 = Math.min(this.grid_r, -q + this.grid_r);
for (var r = r1; r <= r2; r++) {
n_hex = new Hex( [ q, r, -q-r ], this.layout );
this.hexes[ n_hex.coords.getHashID() ] = n_hex;
}
}
},
_selectHexesInRange: function( hex, range ){
var center = this._cel.copy( hex.coords );
var dx = range - center.q;
var dy = range - center.r;
var results = [];
for (var q = -range; q <= dx; q++ ) {
var r1 = Math.max(-range, -q - range);
var r2 = Math.min(range, -q + range);
for ( var r = r1; r <= r2; r++ ) {
var c = new Cell(q, r, -q-r)
results.push( c.add( center ) );
}
}
for( var h in results){
if( typeof( this.hexes[results[h].getHashID()]) !== "undefined" ){
this.hexes[results[h].getHashID()].select()
}
}
//console.log( results )
},
hex_corner_offset : function ( corner ) {
var size = this.layout.size;
var angle = 2.0 * Math.PI * (this.layout.orientation.start_angle - corner) / 6;
return new Point([size.x * Math.cos(angle), size.y * Math.sin(angle)]);
},
point_add : function(p, q) {
return new Point([p.x + q.x, p.y + q.y]);
},
add_neighbors: function(){
var nbor = null, hex = null;
for( var h in this.hexes ){
hex = this.hexes[h];
var i, n, l = this._directions.length;
this._list.length = 0;//// reset array ///
for ( i = 0; i < l; i++ ) {
this._cel.copy( hex.coords );
this._cel.add( this._directions[i] );
n = this.hexes[ this._cel.getHashID() ];
if (typeof(n) == "undefined") { ///// if doesn't exists ////
this._list.push( null );
continue;
}
this._list.push(n);
}
hex.neighbors = this._list.slice(); //// take copy of the array ////
}
},
draw: function( ctx ){
for( var h in this.hexes ){
this.hexes[h].draw( ctx );
}
},
checkCollisions: function(){
var h_pos = this.get_hex_at_p( this.mouse );
var hex = this.hexes[ h_pos.getHashID() ];
if( typeof(hex) !== "undefined" ){
if( this.hovered[0] == null ){ //// cur
this.hovered[0] = hex;
this.hovered[0].hover();
}else{
this.hovered[1] = this.hovered[0];
this.hovered[0] = hex;
if( this.hovered[0].coords._hashID != this.hovered[1].coords._hashID ){
this.hovered[1].clear_hover();
this.hovered[1] = null;
}
}
this.hovered[0].hover();
}
},
mouse_events: function( ctx_pos ){
var self = this;
window.addEventListener( 'mousemove', function(e){
self.mouse.x = ( e.clientX - ctx_pos.x );
self.mouse.y = ( e.clientY - ctx_pos.y );
});
window.addEventListener( 'mousedown', function(e){
//console.log( "neighbors : ",self.hovered[0].neighbors )
self._selectHexesInRange( self.hovered[0], 2);
});
}
}
</script>
<script id="main">
var c_el = document.getElementById("myCanvas");
var ctx = c_el.getContext("2d");
var nGrid = new Grid( 6, 25, [ c_el.width / 2, c_el.height / 2 ], [c_el.getBoundingClientRect().left, c_el.getBoundingClientRect().top], "pointy" );
function animate(){
window.requestAnimationFrame( animate );
ctx.clearRect(0, 0, c_el.width, c_el.height);
nGrid.checkCollisions();
nGrid.draw( ctx);
}
animate();
</script>
Just take the coordinates x, y, z and then search all fields to one of this calculations:
z is const, x is plus/minus 1, y is minus/plus 1
x is const, z is plus/minus 1, y is minus/plus 1
y is const, z is plus/minus 1, x is minus/plus 1
This should be all neighbors
Example: Filed 0, 1, -1 (x,y,z)
z is const and x is plus/minus 1 => [-1, 2,-1], [ 1, 0,-1]
x is const and z is plus/minus 1 => [ 0, 2,-2], [ 0, 0, 0]
y is const and z is plus/minus 1 => [ 1, 1,-2], [-1, 1, 0]
For a faster search you can store your cells inside a Object like this:
var cells = new Object();
for(x=-2; x<3; x++){
cells[x] = new Object();
for(y=-2; y<3; y++){
cells[x][y] = new Object();
for(z=-2; z<3; z++){
cells[x][y][z] = cell;
}
}
}
Then you can access the cells by there coordinates:
var x = 0;
var y = 1;
var z = -1;
var neighbors = new Array();
neighbors.push(cells[x-1][y+1][z]);
neighbors.push(cells[x+1][y-1][z]);
neighbors.push(cells[x][y+1][z-1]);
neighbors.push(cells[x][y-1][z+1]);
neighbors.push(cells[x+1][y][z-1]);
neighbors.push(cells[x-1][y][z+1]);

Using HTML over canvas, nothing has worked

I'm trying to get my OVERLAY tag to appear on top of my canvas javascript. I've gone through all the questions on here but nothing has worked!
Please help! Code:
page.html
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id='container'>
<canvas id='canvas'></canvas>
<script src="test-script.js"></script>
<div id='overlay'>OVERLAY
<br></br>
OVERLAY
<br></br>
OVERLAY
</div>
</div>
</body>
</html>
style.css
#canvas {position: fixed; z-index: -1;}
#overlay {margin-top: -50px; z-index:0; position: relative;}
test-script.js
var ns = ns || {};
(function draw() {
var c;
var ctx;
var trails = [];
document.body.onload = function() {
c = document.getElementById( 'canvas' );
c.width = 2000;
c.height = 2000;
document.body.appendChild( c );
ctx = c.getContext( "2d" );
trails.push( new ns.trailer( [990000, 990000, 990000, 600000, 600000 ]));
// trails.push( new ns.trailer( [ 600000,600000,600000,600000,600000,600000,600000 ] ));
trails.push( new ns.trailer( [ 8000000, 8000000, 8000000, 990000, 990000 ] ));
document.onmousedown = reset;
reset();
setInterval( compute, 0 );
}
function reset() {
ctx.fillStyle = "white";
ctx.fillRect( 0,0,c.width,c.height );
for( var i =0; i < trails.length; i++ ) {
trails[ i ].reset();
}
}
function compute() {
for( var i =0; i < trails.length; i++ ) {
trails[ i ].compute( ctx );
}
}
})();
ns.trailer = function( colors ) {
this.points = [];
this.stroke = new ns.stroke( null, 100, 10, colors[ 0 ] );
this.colorIterator = 10;
this.colors = colors;
}
ns.trailer.prototype = {
reset : function() {
this.points = [];
this.width = document.body.offsetWidth;
this.height = document.body.offsetHeight;
this.radius = Math.max( this.width, this.height );
this.center = new ns.point( this.width / 2, this.height / 2 );
this.a0 = Math.random() * Math.PI * 2;
this.a1 = Math.random() * Math.PI * 2;
this.a2 = Math.random() * Math.PI * 2;
var mul = 1 + Math.random() * 2;
if( Math.random() > .5 ) mul *= 5;
else mul /= 2;
this.s0 = ( Math.random() - .5 ) * mul / 180 * Math.PI;
this.s1 = ( Math.random() - .5 ) * mul / 180 * Math.PI;
this.s2 = ( Math.random() - .5 ) * mul / 180 * Math.PI;
},
compute : function( ctx ) {
with( this ) {
a0 += s0;
a1 += s1;
a2 += s2;
var c = Math.cos( a0 ) * Math.cos( a1 ) * Math.cos( a2 );
var s = Math.sin( a0 ) * Math.sin( a1 ) * Math.sin( a2 );
points.push( new ns.point( center.x + c * radius,
center.y + s * radius ) );
if( points.length > 10 ) points.shift();
stroke.anchors = points;
stroke.draw( ctx );
var t = .5 + (Math.sin( new Date().getTime() * .001 ) * .5 );
stroke.color = colors[ Math.floor( t * colors.length ) ];
stroke.width = 25 + ( 1 - t ) * 50;
//stroke.strokeCount = 5 + t * 5;
stroke.strokeCount = 5;
}
}
}
ns.point = function( x,y ) {
this.x = x;
this.y = y;
}
ns.point.prototype = {
add : function( p ) {
return new ns.point( this.x + p.x, this.y + p.y );
}.
sub : function( p ) {
return new ns.point( this.x - p.x, this.y - p.y );
},
negate : function() {
this.x *= -1;
this.y *= -1;
return this;
},
clone : function() {
return new ns.point( this.x, this.y );
},
length : function() {
return Math.sqrt( this.x * this.x + this.y * this.y );
},
normalize : function ( scale ) {
scale = scale || 1;
var l = this.length();
this.x /= l;
this.x *= scale;
this.y /= l;
this.y *= scale;
return this;
}
}
ns.stroke = function( anchors, width, strokeCount, color ) {
this.anchors = anchors;
this.width = width;
this.strokeCount = strokeCount;
this.color = color;
}
ns.stroke.prototype = {
normal : function( p0, p1 ){
return new ns.point( -( p1.y - p0.y ), ( p1.x - p0.x ) );
},
draw : function( ctx ) {
if( this.anchors == undefined ) return;
var half = this.height * .5;
var p, c, n, pnorm, pln, prn, cnorm, cln, crn;
with( this ) {
for( var j = 0; j < strokeCount; j++ ) {
half = width * .5 * Math.random();
var col = ns.variation( color, 35 );
ctx.lineWidth = .1 + Math.random() * 2;
for( var i = 0; i < anchors.length - 2; i++ ) {
p = anchors[ i ];
c = anchors[ i+1 ];
n = anchors[ i+2 ];
pnorm = normal( p, c );
cnorm = normal( c, n );
half += ( Math.random() - .5 );
pnorm.normalize( half );
pln = p.add( pnorm );
pnorm.normalize( -half );
prn = p.add( pnorm );
half += ( Math.random() - .5 );
cnorm.normalize( half );
cln = c.add( cnorm );
cnorm.normalize( -half );
crn = c.add( cnorm );
ctx.beginPath();
ctx.strokeStyle = col;
ctx.moveTo( prn.x, prn.y );
ctx.lineTo( crn.x, crn.y );
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.strokeStyle = col;
ctx.moveTo( pln.x, pln.y );
ctx.lineTo( cln.x, cln.y );
ctx.stroke();
ctx.closePath();
}
}
}
}
}
ns.variation = function( color, amount ) {
amount = amount || 25;
var r = color >> 16 & 0xFF;
var g = color >> 8 & 0xFF;
var b = color & 0xFF;
r += Math.floor( ( Math.random() - .5 ) * amount );
g += Math.floor( ( Math.random() - .5 ) * amount );
b += Math.floor( ( Math.random() - .5 ) * amount );
r = r > 0xFF ? 0xFF : r < 0 ? 0 : r;
g = g > 0xFF ? 0xFF : g < 0 ? 0 : g;
b = b > 0xFF ? 0xFF : b < 0 ? 0 : b;
return "rgba("+r+','+g+','+b+','+Math.random()+');';
}
**I've added my Javascript code
You need to use absolute position. Also mention width and height to 100%. z-index should be higher to place element over other elements.
#canvas {
position: fixed;
}
#overlay {
z-index: 9;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.3);
}
<div id='container'>
<canvas id='canvas'></canvas>
<div id='overlay'>OVERLAY
<br>OVERLAY
<br>OVERLAY
</div>
</div>
CSS
#container {
position: relative;
}
#overlay {
position:absolute;
top:50px;
left:150px;
z-index:10;
}
Adjust the "top" and "left" amounts to get OVERLAY positioned on top of the canvas.
It was the JavaScript.
Run my code snippet.
var ns = ns || {};
(function draw() {
var c;
var ctx;
var trails = [];
document.body.onload = function() {
c = document.getElementById( 'canvas' );
c.width = 2000;
c.height = 2000;
document.body.appendChild( c );
ctx = c.getContext( "2d" );
trails.push( new ns.trailer( [990000, 990000, 990000, 600000, 600000 ]));
// trails.push( new ns.trailer( [ 600000,600000,600000,600000,600000,600000,600000 ] ));
trails.push( new ns.trailer( [ 8000000, 8000000, 8000000, 990000, 990000 ] ));
document.onmousedown = reset;
reset();
setInterval( compute, 0 );
};
function reset() {
ctx.fillStyle = "white";
ctx.fillRect( 0,0,c.width,c.height );
for( var i =0; i < trails.length; i++ ) {
trails[ i ].reset();
}
}
function compute() {
for( var i =0; i < trails.length; i++ ) {
trails[ i ].compute( ctx );
}
}
})();
ns.trailer = function( colors ) {
this.points = [];
this.stroke = new ns.stroke( null, 100, 10, colors[ 0 ] );
this.colorIterator = 10;
this.colors = colors;
};
ns.trailer.prototype = {
reset : function() {
this.points = [];
this.width = document.body.offsetWidth;
this.height = document.body.offsetHeight;
this.radius = Math.max( this.width, this.height );
this.center = new ns.point( this.width / 2, this.height / 2 );
this.a0 = Math.random() * Math.PI * 2;
this.a1 = Math.random() * Math.PI * 2;
this.a2 = Math.random() * Math.PI * 2;
var mul = 1 + Math.random() * 2;
if( Math.random() > .5 ) mul *= 5;
else mul /= 2;
this.s0 = ( Math.random() - .5 ) * mul / 180 * Math.PI;
this.s1 = ( Math.random() - .5 ) * mul / 180 * Math.PI;
this.s2 = ( Math.random() - .5 ) * mul / 180 * Math.PI;
},
compute : function( ctx ) {
with( this ) {
a0 += s0;
a1 += s1;
a2 += s2;
var c = Math.cos( a0 ) * Math.cos( a1 ) * Math.cos( a2 );
var s = Math.sin( a0 ) * Math.sin( a1 ) * Math.sin( a2 );
points.push( new ns.point( center.x + c * radius,
center.y + s * radius ) );
if( points.length > 10 ) points.shift();
stroke.anchors = points;
stroke.draw( ctx );
var t = .5 + (Math.sin( new Date().getTime() * .001 ) * .5 );
stroke.color = colors[ Math.floor( t * colors.length ) ];
stroke.width = 25 + ( 1 - t ) * 50;
//stroke.strokeCount = 5 + t * 5;
stroke.strokeCount = 5;
}
}
};
ns.point = function( x,y ) {
this.x = x;
this.y = y;
};
ns.point.prototype = {
add : function( p ) {
return new ns.point( this.x + p.x, this.y + p.y );
},
sub : function( p ) {
return new ns.point( this.x - p.x, this.y - p.y );
},
negate : function() {
this.x *= -1;
this.y *= -1;
return this;
},
clone : function() {
return new ns.point( this.x, this.y );
},
length : function() {
return Math.sqrt( this.x * this.x + this.y * this.y );
},
normalize : function ( scale ) {
scale = scale || 1;
var l = this.length();
this.x /= l;
this.x *= scale;
this.y /= l;
this.y *= scale;
return this;
}
};
ns.stroke = function( anchors, width, strokeCount, color ) {
this.anchors = anchors;
this.width = width;
this.strokeCount = strokeCount;
this.color = color;
};
ns.stroke.prototype = {
normal : function( p0, p1 ){
return new ns.point( -( p1.y - p0.y ), ( p1.x - p0.x ) );
},
draw : function( ctx ) {
if( this.anchors === undefined ) return;
var half = this.height * .5;
var p, c, n, pnorm, pln, prn, cnorm, cln, crn;
with( this ) {
for( var j = 0; j < strokeCount; j++ ) {
half = width * .5 * Math.random();
var col = ns.variation( color, 35 );
ctx.lineWidth = .1 + Math.random() * 2;
for( var i = 0; i < anchors.length - 2; i++ ) {
p = anchors[ i ];
c = anchors[ i+1 ];
n = anchors[ i+2 ];
pnorm = normal( p, c );
cnorm = normal( c, n );
half += ( Math.random() - .5 );
pnorm.normalize( half );
pln = p.add( pnorm );
pnorm.normalize( -half );
prn = p.add( pnorm );
half += ( Math.random() - .5 );
cnorm.normalize( half );
cln = c.add( cnorm );
cnorm.normalize( -half );
crn = c.add( cnorm );
ctx.beginPath();
ctx.strokeStyle = col;
ctx.moveTo( prn.x, prn.y );
ctx.lineTo( crn.x, crn.y );
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.strokeStyle = col;
ctx.moveTo( pln.x, pln.y );
ctx.lineTo( cln.x, cln.y );
ctx.stroke();
ctx.closePath();
}
}
}
}
};
ns.variation = function( color, amount ) {
amount = amount || 25;
var r = color && 16 && 0xFF;
var g = color && 8 && 0xFF;
var b = color && 0xFF;
r += Math.floor( ( Math.random() - .5 ) * amount );
g += Math.floor( ( Math.random() - .5 ) * amount );
b += Math.floor( ( Math.random() - .5 ) * amount );
r = r > 0xFF ? 0xFF : r < 0 ? 0 : r;
g = g > 0xFF ? 0xFF : g < 0 ? 0 : g;
b = b > 0xFF ? 0xFF : b < 0 ? 0 : b;
return "rgba("+r+','+g+','+b+','+Math.random()+');';
};
#container {
position: relative;
}
#overlay {
position:absolute;
top:50px;
left:150px;
z-index:10;
}
<body>
<div id='container'>
<div id='overlay'>
<h1>
OVERLAY
</h1>
</div>
<canvas id='canvas'>
</canvas>
</div>
<!-- scripts -->
<script type="text/javascript" src="test-script.js"></script>
</body>

Morphing Geometry - Three.Js

So I have this code that will generate the user's desired dimension and display it on a customized new THREE.Geometry() . This may be an off topic to most of you. But hey, I'm just new to Three.js
My problem is that:
I can't find a way to insert the geometry.morphTargets. Or simply, I don't know how to use it properly
So here's my code:
//custom Object height and width
customHeightWidth(customWidth, customHeight);
function customHeightWidth(width, height){
material = new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture(uploadedFile),
side: THREE.DoubleSide,
overdraw: true,
wireframe: false
});
//objects
combined = new THREE.PlaneGeometry(width, height, 30, 10);
geometry = new THREE.Geometry();
geometry.name: "target1", vertices.push( new THREE.Vector3( -(width), height, 0 ) );
geometry.name: "target2", vertices.push( new THREE.Vector3( -(width), -(height), 0 ) );
geometry.name: "target3", vertices.push( new THREE.Vector3( width, -(height), 0 ) );
geometry.computeBoundingSphere();
geometry.faces.push( new THREE.Face3( 0, 1, 2 ) );
geometry1 = new THREE.Geometry();
geometry1.vertices.push( new THREE.Vector3( width, height, 0 ) );
geometry1.vertices.push( new THREE.Vector3( -(width), height, 0 ) );
geometry1.vertices.push( new THREE.Vector3( width, -(height), 0 ) );
geometry1.computeBoundingSphere();
geometry1.faces.push( new THREE.Face3( 0, 1, 2 ) );
// 1st box
var mesh1 = new THREE.Mesh(geometry);
var mesh2 = new THREE.Mesh(geometry1);
//activating the meshs
THREE.GeometryUtils.merge(combined, mesh1);
THREE.GeometryUtils.merge(combined, mesh2);
mesh = new THREE.Mesh(combined, material);
this.scene.add(mesh);
};
}
var animate = function() {
requestAnimationFrame(animate);
//mesh.rotation.x += 0.01;
//mesh.rotation.y -= 0.006;
renderer.render(scene, camera);
}
init();
animate();
I recommend reviewing how JSONLoader loads morph targets to the Geometry.morphTargets array in the Geometry class.
function parseMorphing( scale ) {
if ( json.morphTargets !== undefined ) {
var i, l, v, vl, dstVertices, srcVertices;
for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) {
geometry.morphTargets[ i ] = {};
geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
geometry.morphTargets[ i ].vertices = [];
dstVertices = geometry.morphTargets[ i ].vertices;
srcVertices = json.morphTargets [ i ].vertices;
for( v = 0, vl = srcVertices.length; v < vl; v += 3 ) {
var vertex = new THREE.Vector3();
vertex.x = srcVertices[ v ] * scale;
vertex.y = srcVertices[ v + 1 ] * scale;
vertex.z = srcVertices[ v + 2 ] * scale;
dstVertices.push( vertex );
}
}
}
//Reading morphTargets
for(i=o;i<geometry.morphTargets.length;i++) {
morphTargets = geometry.morphTargets[i].vertices;
return morphTargets;
}
//loading morphTargets
loadMorphTargets = function (morphTargets) {
if (morphTargets !== undefined) {
var i, l, v, vl, dstVertices, srcVertices;
//for (i = 0, l = morphTargets.length; i < l; i++) {
geometry.morphTargets[i] = {};
geometry.morphTargets[i].name = morphTargets.name;
geometry.morphTargets[i].vertices = [];
var dstVertices = geometry.morphTargets[i].vertices;
var srcVertices = morphTargets.vertices;
for (v = 0, vl = srcVertices.length; v < vl; v += 3) {
var vertex = new THREE.Vector3();
vertex.x = srcVertices[ v ];
vertex.y = srcVertices[ v + 1 ];
vertex.z = srcVertices[ v + 2 ];
dstVertices.push(vertex);
}
}
};
I guess it will be useful to you.

Categories