vanta
Version:
3D animated backgrounds for your website
203 lines (178 loc) • 6.16 kB
JavaScript
import VantaBase, { VANTA } from './_base.js'
import {rn,ri,sample} from './helpers.js'
let THREE = (typeof window == 'object' && window.THREE)
const defaultOptions = {
color: 0x005588,
shininess: 30,
waveHeight: 15,
waveSpeed: 1,
zoom: 1
}
class Waves extends VantaBase {
static initClass() {
this.prototype.ww = 100;
this.prototype.hh = 80;
this.prototype.waveNoise = 4; // Choppiness of water
}
constructor(userOptions) {
THREE = userOptions.THREE || THREE
super(userOptions)
}
getMaterial() {
const options = {
color: this.options.color,
shininess: this.options.shininess,
flatShading: true,
side: THREE.DoubleSide
};
return new THREE.MeshPhongMaterial(options);
}
onInit() {
let i, j;
const CELLSIZE = 18;
const material = this.getMaterial();
const geometry = new THREE.BufferGeometry();
// Add vertices
this.gg = [];
const points = [];
for (i=0; i<=this.ww; i++){
this.gg[i] = [];
for (j=0; j<=this.hh; j++){
const id = points.length;
const newVertex = new THREE.Vector3(
(i - (this.ww * 0.5)) * CELLSIZE,
rn(0, this.waveNoise) - 10,
((this.hh * 0.5) - j) * CELLSIZE
);
points.push(newVertex);
this.gg[i][j] = id;
}
}
geometry.setFromPoints(points);
// Add faces
// a b
// c d <-- Looking from the bottom right point
const indices = [];
for (i=1; i<=this.ww; i++){
for (j=1; j<=this.hh; j++){
let face1, face2
const d = this.gg[i][j]
const b = this.gg[i][j-1]
const c = this.gg[i-1][j]
const a = this.gg[i-1][j-1]
if (ri(0,1)) {
face1 = [a, b, c]
face2 = [b, c, d]
} else {
face1 = [a, b, d]
face2 = [a, c, d]
}
indices.push(...face1, ...face2)
}
}
geometry.setIndex(indices);
this.plane = new THREE.Mesh(geometry, material);
this.scene.add(this.plane);
// WIREFRAME
// lightColor = 0x55aaee
// darkColor = 0x225577
// thresholdAngle = 2
// geo = new THREE.EdgesGeometry(geometry, thresholdAngle)
// mat = new THREE.LineBasicMaterial( { color: lightColor, linewidth: 2 } )
// @wireframe = new THREE.LineSegments( geo, mat )
// @scene.add( @wireframe )
// LIGHTS
const ambience = new THREE.AmbientLight( 0xffffff, 0.9 );
this.scene.add(ambience);
const pointLight = new THREE.PointLight( 0xffffff, 0.9 );
pointLight.position.set(-100,250,-100);
this.scene.add(pointLight);
// CAMERA
this.camera = new THREE.PerspectiveCamera(
35,
this.width / this.height,
50, 10000);
const xOffset = -10;
const zOffset = -10;
this.cameraPosition = new THREE.Vector3( 250+xOffset, 200, 400+zOffset );
this.cameraTarget = new THREE.Vector3( 150+xOffset, -30, 200+zOffset );
this.camera.position.copy(this.cameraPosition);
this.scene.add(this.camera);
}
onUpdate() {
// Update options
let diff;
this.plane.material.color.set(this.options.color)
this.plane.material.shininess = this.options.shininess
this.camera.ox = this.cameraPosition.x / this.options.zoom
this.camera.oy = this.cameraPosition.y / this.options.zoom
this.camera.oz = this.cameraPosition.z / this.options.zoom
if (this.controls != null) {
this.controls.update()
}
const c = this.camera
if (Math.abs(c.tx - c.position.x) > 0.01) {
diff = c.tx - c.position.x
c.position.x += diff * 0.02
}
if (Math.abs(c.ty - c.position.y) > 0.01) {
diff = c.ty - c.position.y
c.position.y += diff * 0.02
}
if (Math.abs(c.tz - c.position.z) > 0.01) {
diff = c.tz - c.position.z
c.position.z += diff * 0.02
}
c.lookAt( this.cameraTarget )
// Fix flickering problems
// c.near = Math.max((c.position.y * 0.5) - 20, 1);
// c.updateMatrix();
// WAVES
this.oy = this.oy || {}
for (let i = 0; i < this.plane.geometry.attributes.position.array.length; i += 3) {
const v = {
x: this.plane.geometry.attributes.position.array[i],
y: this.plane.geometry.attributes.position.array[i + 1],
z: this.plane.geometry.attributes.position.array[i + 2],
oy: this.oy[i]
};
if (!v.oy) { // INIT
this.oy[i] = v.y
} else {
const s = this.options.waveSpeed
const crossChop = Math.sqrt(s) * Math.cos(-v.x - (v.z*0.7)) // + s * (i % 229) / 229 * 5
const delta = Math.sin((((s*this.t*0.02) - (s*v.x*0.025)) + (s*v.z*0.015) + crossChop))
const trochoidDelta = Math.pow(delta + 1, 2) / 4
v.y = v.oy + (trochoidDelta * this.options.waveHeight)
this.plane.geometry.attributes.position.array[i + 1] = v.y
}
}
// @wireframe.geometry.vertices[i].y = v.y
this.plane.geometry.attributes.position.setUsage(THREE.DynamicDrawUsage)
this.plane.geometry.computeVertexNormals()
this.plane.geometry.attributes.position.needsUpdate = true
// @scene.remove( @wireframe )
// geo = new THREE.EdgesGeometry(@plane.geometry)
// mat = new THREE.LineBasicMaterial( { color: 0x55aaee, linewidth: 2} )
// @wireframe = new THREE.LineSegments( geo, mat )
// @scene.add( @wireframe )
if (this.wireframe) {
this.wireframe.geometry.fromGeometry(this.plane.geometry)
this.wireframe.geometry.computeFaceNormals()
}
}
onMouseMove(x,y) {
const c = this.camera;
if (!c.oy) {
c.oy = c.position.y;
c.ox = c.position.x;
c.oz = c.position.z;
}
c.tx = c.ox + (((x-0.5) * 100) / this.options.zoom);
c.ty = c.oy + (((y-0.5) * -100) / this.options.zoom);
return c.tz = c.oz + (((x-0.5) * -50) / this.options.zoom);
}
}
Waves.prototype.defaultOptions = defaultOptions
Waves.initClass()
export default VANTA.register('WAVES', Waves)