279 lines
9.3 KiB
JavaScript
279 lines
9.3 KiB
JavaScript
|
// curl noise
|
|||
|
// https://petewerner.blogspot.jp/2015/02/intro-to-curl-noise.html
|
|||
|
|
|||
|
// inspired by
|
|||
|
// https://www.clicktorelease.com/code/polygon-shredder/
|
|||
|
|
|||
|
window.onload = () => {
|
|||
|
var webgl = new Webgl();
|
|||
|
window.onresize = () => {
|
|||
|
webgl.resize();
|
|||
|
};
|
|||
|
};
|
|||
|
|
|||
|
class Webgl {
|
|||
|
constructor() {
|
|||
|
this.size = 128;
|
|||
|
this.widthW = document.body.clientWidth;
|
|||
|
this.heightW = window.innerHeight;
|
|||
|
this.init();
|
|||
|
}
|
|||
|
|
|||
|
init() {
|
|||
|
this.container = document.getElementById("wrapper");
|
|||
|
this.renderer = new THREE.WebGLRenderer({ antialias: true });
|
|||
|
// renderer.setPixelRatio( window.devicePixelRatio );
|
|||
|
this.renderer.setSize(this.widthW, this.heightW);
|
|||
|
this.container.appendChild(this.renderer.domElement);
|
|||
|
|
|||
|
this.scene = new THREE.Scene();
|
|||
|
|
|||
|
this.colorPallete = [
|
|||
|
new THREE.Color(0x0d0232),
|
|||
|
new THREE.Color(0xe50061),
|
|||
|
new THREE.Color(0x1cafc0),
|
|||
|
new THREE.Color(0xefcb03)];
|
|||
|
|
|||
|
|
|||
|
this.camera = new THREE.PerspectiveCamera(45, this.widthW / this.heightW, .01, 10000);
|
|||
|
this.scene.add(this.camera);
|
|||
|
this.camera.position.set(-0.1, 4.0, 0.1);
|
|||
|
|
|||
|
var controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
|
|||
|
|
|||
|
this.sim = new Simulation(this.renderer, this.size);
|
|||
|
|
|||
|
this.setLight();
|
|||
|
this.createObj();
|
|||
|
|
|||
|
this.time = new THREE.Clock();
|
|||
|
this.render();
|
|||
|
}
|
|||
|
|
|||
|
setLight() {
|
|||
|
this.light = new THREE.DirectionalLight(0xFFAA55);
|
|||
|
this.light.position.set(-4, -6, 10);
|
|||
|
this.light.castShadow = true;
|
|||
|
this.shadowCamera = this.light.shadow.camera;
|
|||
|
// this.shadowCamera.position.set(-4, -6, 10);
|
|||
|
this.shadowCamera.lookAt(this.scene.position);
|
|||
|
|
|||
|
this.light.shadow.matrix.set(
|
|||
|
0.5, 0.0, 0.0, 0.5,
|
|||
|
0.0, 0.5, 0.0, 0.5,
|
|||
|
0.0, 0.0, 0.5, 0.5,
|
|||
|
0.0, 0.0, 0.0, 1.0);
|
|||
|
|
|||
|
|
|||
|
this.light.shadow.matrix.multiply(this.shadowCamera.projectionMatrix);
|
|||
|
this.light.shadow.matrix.multiply(this.shadowCamera.matrixWorldInverse);
|
|||
|
|
|||
|
if (this.light.shadow.map === null) {
|
|||
|
this.light.shadow.mapSize.x = 2048;
|
|||
|
this.light.shadow.mapSize.y = 2048;
|
|||
|
|
|||
|
var pars = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat };
|
|||
|
|
|||
|
this.light.shadow.map = new THREE.WebGLRenderTarget(this.light.shadow.mapSize.x, this.light.shadow.mapSize.y, pars);
|
|||
|
// light.shadow.map.texture.name = light.name + ".shadowMap";
|
|||
|
}
|
|||
|
|
|||
|
console.log(this.light);
|
|||
|
}
|
|||
|
|
|||
|
createObj() {
|
|||
|
// var originalG = new THREE.BoxBufferGeometry(1, 1, 1);
|
|||
|
var originalG = new THREE.OctahedronBufferGeometry(1, 0);
|
|||
|
|
|||
|
|
|||
|
var geometry = new THREE.InstancedBufferGeometry();
|
|||
|
|
|||
|
// vertex
|
|||
|
var vertices = originalG.attributes.position.clone();
|
|||
|
|
|||
|
geometry.addAttribute("position", vertices);
|
|||
|
|
|||
|
var normals = originalG.attributes.normal.clone();
|
|||
|
geometry.addAttribute("normal", normals);
|
|||
|
|
|||
|
// uv
|
|||
|
var uvs = originalG.attributes.uv.clone();
|
|||
|
geometry.addAttribute("uv", uvs);
|
|||
|
|
|||
|
// index
|
|||
|
// var indices = originalG.index.clone();
|
|||
|
// geometry.setIndex(indices);
|
|||
|
|
|||
|
|
|||
|
geometry.maxInstancedCount = this.sim.size * this.sim.size;
|
|||
|
|
|||
|
var nums = new THREE.InstancedBufferAttribute(new Float32Array(this.sim.size * this.sim.size * 1), 1, 1);
|
|||
|
var randoms = new THREE.InstancedBufferAttribute(new Float32Array(this.sim.size * this.sim.size * 1), 1, 1);
|
|||
|
var colors = new THREE.InstancedBufferAttribute(new Float32Array(this.sim.size * this.sim.size * 3), 3, 1);
|
|||
|
|
|||
|
for (var i = 0; i < nums.count; i++) {
|
|||
|
var _color = this.colorPallete[Math.floor(Math.random() * this.colorPallete.length)];
|
|||
|
|
|||
|
nums.setX(i, i);
|
|||
|
randoms.setX(i, Math.random() * 0.5 + 1);
|
|||
|
colors.setXYZ(i, _color.r, _color.g, _color.b);
|
|||
|
}
|
|||
|
|
|||
|
geometry.addAttribute("aNum", nums);
|
|||
|
geometry.addAttribute("aRandom", randoms);
|
|||
|
geometry.addAttribute("aColor", colors);
|
|||
|
|
|||
|
var scale = {
|
|||
|
x: 2,
|
|||
|
y: 8,
|
|||
|
z: 2 };
|
|||
|
|
|||
|
|
|||
|
|
|||
|
this.material = new THREE.ShaderMaterial({
|
|||
|
uniforms: {
|
|||
|
posMap: { type: "t", value: this.sim.gpuCompute.getCurrentRenderTarget(this.sim.pos).texture },
|
|||
|
velMap: { type: "t", value: this.sim.gpuCompute.getCurrentRenderTarget(this.sim.vel).texture },
|
|||
|
size: { type: "f", value: this.sim.size },
|
|||
|
|
|||
|
timer: { type: 'f', value: 0 },
|
|||
|
boxScale: { type: 'v3', value: new THREE.Vector3(scale.x, scale.y, scale.z) },
|
|||
|
meshScale: { type: 'f', value: 0.7 },
|
|||
|
|
|||
|
shadowMap: { type: 't', value: this.light.shadow.map },
|
|||
|
shadowMapSize: { type: "v2", value: this.light.shadow.mapSize },
|
|||
|
shadowBias: { type: "f", value: this.light.shadow.bias },
|
|||
|
shadowRadius: { type: "f", value: this.light.shadow.radius },
|
|||
|
|
|||
|
// Line 217 in https://github.com/mrdoob/three.js/blob/dev/src/renderers/webgl/WebGLShadowMap.js
|
|||
|
shadowMatrix: { type: 'm4', value: this.light.shadow.matrix },
|
|||
|
lightPosition: { type: 'v3', value: this.light.position } },
|
|||
|
|
|||
|
|
|||
|
vertexShader: document.getElementById('vs-particles').textContent,
|
|||
|
fragmentShader: document.getElementById('fs-particles').textContent,
|
|||
|
side: THREE.DoubleSide,
|
|||
|
shading: THREE.FlatShading });
|
|||
|
|
|||
|
|
|||
|
this.mesh = new THREE.Mesh(geometry, this.material);
|
|||
|
this.scene.add(this.mesh);
|
|||
|
|
|||
|
this.shadowMaterial = new THREE.ShaderMaterial({
|
|||
|
uniforms: {
|
|||
|
posMap: { type: "t", value: this.sim.gpuCompute.getCurrentRenderTarget(this.sim.pos).texture },
|
|||
|
velMap: { type: "t", value: this.sim.gpuCompute.getCurrentRenderTarget(this.sim.vel).texture },
|
|||
|
size: { type: "f", value: this.sim.size },
|
|||
|
|
|||
|
timer: { type: 'f', value: 0 },
|
|||
|
boxScale: { type: 'v3', value: new THREE.Vector3(scale.x, scale.y, scale.z) },
|
|||
|
meshScale: { type: 'f', value: 0.7 },
|
|||
|
|
|||
|
shadowMatrix: { type: 'm4', value: this.light.shadow.matrix },
|
|||
|
lightPosition: { type: 'v3', value: this.light.position } },
|
|||
|
|
|||
|
vertexShader: document.getElementById('vs-particles').textContent,
|
|||
|
fragmentShader: document.getElementById('fs-particles-shadow').textContent,
|
|||
|
side: THREE.DoubleSide });
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
render() {
|
|||
|
var delta = this.time.getDelta() * 4;
|
|||
|
var time = this.time.elapsedTime;
|
|||
|
|
|||
|
this.sim.velUniforms.timer.value = time;
|
|||
|
this.sim.velUniforms.delta.value = delta;
|
|||
|
|
|||
|
this.sim.gpuCompute.compute();
|
|||
|
|
|||
|
this.material.uniforms.posMap.value = this.sim.gpuCompute.getCurrentRenderTarget(this.sim.pos).texture;
|
|||
|
this.material.uniforms.velMap.value = this.sim.gpuCompute.getCurrentRenderTarget(this.sim.vel).texture;
|
|||
|
|
|||
|
this.shadowMaterial.uniforms.posMap.value = this.sim.gpuCompute.getCurrentRenderTarget(this.sim.pos).texture;
|
|||
|
this.shadowMaterial.uniforms.velMap.value = this.sim.gpuCompute.getCurrentRenderTarget(this.sim.vel).texture;
|
|||
|
|
|||
|
this.material.uniforms.timer.value = this.shadowMaterial.uniforms.timer.value = time;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
this.mesh.material = this.shadowMaterial;
|
|||
|
this.renderer.render(this.scene, this.shadowCamera, this.light.shadow.map);
|
|||
|
|
|||
|
this.renderer.setClearColor(0x2e0232);
|
|||
|
this.mesh.material = this.material;
|
|||
|
this.renderer.render(this.scene, this.camera);
|
|||
|
|
|||
|
requestAnimationFrame(this.render.bind(this));
|
|||
|
}
|
|||
|
|
|||
|
resize() {
|
|||
|
this.widthW = document.body.clientWidth;
|
|||
|
this.heightW = window.innerHeight;
|
|||
|
|
|||
|
this.camera.aspect = this.widthW / this.heightW;
|
|||
|
this.camera.updateProjectionMatrix();
|
|||
|
this.renderer.setSize(this.widthW, this.heightW);
|
|||
|
}}
|
|||
|
|
|||
|
|
|||
|
class Simulation {
|
|||
|
constructor(renderer, size) {
|
|||
|
this.renderer = renderer;
|
|||
|
this.size = size;
|
|||
|
this.init();
|
|||
|
}
|
|||
|
|
|||
|
init() {
|
|||
|
this.gpuCompute = new GPUComputationRenderer(this.size, this.size, this.renderer);
|
|||
|
|
|||
|
this.dataPos = this.gpuCompute.createTexture();
|
|||
|
this.dataVel = this.gpuCompute.createTexture();
|
|||
|
this.dataDef = this.gpuCompute.createTexture();
|
|||
|
|
|||
|
|
|||
|
var posArray = this.dataPos.image.data;
|
|||
|
var velArray = this.dataVel.image.data;
|
|||
|
var defArray = this.dataDef.image.data;
|
|||
|
|
|||
|
|
|||
|
for (var i = 0, il = posArray.length; i < il; i += 4) {
|
|||
|
|
|||
|
var phi = Math.random() * 2 * Math.PI;
|
|||
|
var theta = Math.random() * Math.PI;
|
|||
|
var r = 0.8 + Math.random() * 2;
|
|||
|
|
|||
|
defArray[i + 0] = posArray[i + 0] = r * Math.sin(theta) * Math.cos(phi);
|
|||
|
defArray[i + 1] = posArray[i + 1] = r * Math.sin(theta) * Math.sin(phi);
|
|||
|
defArray[i + 2] = posArray[i + 2] = r * Math.cos(theta);
|
|||
|
|
|||
|
velArray[i + 3] = Math.random() * 100; // frames life
|
|||
|
// if(i < 50) console.log(velArray[ i + 3 ])
|
|||
|
}
|
|||
|
|
|||
|
this.def = this.gpuCompute.addVariable("defTex", document.getElementById('simulation_def').textContent, this.dataDef);
|
|||
|
this.vel = this.gpuCompute.addVariable("velTex", document.getElementById('simulation_vel').textContent, this.dataVel);
|
|||
|
this.pos = this.gpuCompute.addVariable("posTex", document.getElementById('simulation_pos').textContent, this.dataPos);
|
|||
|
|
|||
|
this.gpuCompute.setVariableDependencies(this.def, [this.pos, this.vel, this.def]);
|
|||
|
this.gpuCompute.setVariableDependencies(this.vel, [this.pos, this.vel, this.def]);
|
|||
|
this.gpuCompute.setVariableDependencies(this.pos, [this.pos, this.vel, this.def]);
|
|||
|
|
|||
|
|
|||
|
// var posUniforms = this.pos.material.uniforms;
|
|||
|
this.velUniforms = this.vel.material.uniforms;
|
|||
|
|
|||
|
this.velUniforms.timer = { value: 0.0 };
|
|||
|
this.velUniforms.delta = { value: 0.0 };
|
|||
|
this.velUniforms.speed = { value: 0.5 };
|
|||
|
this.velUniforms.factor = { value: 0.5 };
|
|||
|
this.velUniforms.evolution = { value: 0.5 };
|
|||
|
this.velUniforms.radius = { value: 2.0 };
|
|||
|
|
|||
|
var error = this.gpuCompute.init();
|
|||
|
if (error !== null) {
|
|||
|
console.error(error);
|
|||
|
}
|
|||
|
}}
|