hefeihvac_java/node_modules/echarts-gl/lib/chart/flowGL/VectorFieldParticleSurface.js

404 lines
13 KiB
JavaScript
Raw Permalink Normal View History

2024-04-07 18:15:00 +08:00
import Pass from 'claygl/src/compositor/Pass';
import Geometry from 'claygl/src/Geometry';
import Mesh from 'claygl/src/Mesh';
import Material from 'claygl/src/Material';
import Shader from 'claygl/src/Shader';
import Texture2D from 'claygl/src/Texture2D';
import Texture from 'claygl/src/Texture';
import OrthoCamera from 'claygl/src/camera/Orthographic';
import PlaneGeometry from 'claygl/src/geometry/Plane';
import FrameBuffer from 'claygl/src/FrameBuffer';
import Line2DGeometry from './Line2D'; // import TemporalSS from '../../effect/TemporalSuperSampling';
import vectorFieldParticleGLSL from './vectorFieldParticle.glsl.js';
Shader['import'](vectorFieldParticleGLSL);
function createSpriteCanvas(size) {
var canvas = document.createElement('canvas');
canvas.width = canvas.height = size;
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#fff';
ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
ctx.fill();
return canvas;
} // import spriteUtil from '../../util/sprite';
var VectorFieldParticleSurface = function () {
/**
* @type {number}
*/
this.motionBlurFactor = 0.99;
/**
* Vector field lookup image
* @type {clay.Texture2D}
*/
this.vectorFieldTexture = new Texture2D({
type: Texture.FLOAT,
// minFilter: Texture.NEAREST,
// magFilter: Texture.NEAREST,
flipY: false
});
/**
* Particle life range
* @type {Array.<number>}
*/
this.particleLife = [5, 20];
this._particleType = 'point';
/**
* @type {number}
*/
this._particleSize = 1;
/**
* @type {Array.<number>}
*/
this.particleColor = [1, 1, 1, 1];
/**
* @type {number}
*/
this.particleSpeedScaling = 1.0;
/**
* @type {clay.Texture2D}
*/
this._thisFrameTexture = null;
this._particlePass = null;
this._spawnTexture = null;
this._particleTexture0 = null;
this._particleTexture1 = null;
this._particlePointsMesh = null;
this._surfaceFrameBuffer = null;
this._elapsedTime = 0.0;
this._scene = null;
this._camera = null;
this._lastFrameTexture = null; // this._temporalSS = new TemporalSS(50);
// this._antialising = false;
this._supersampling = 1;
this._downsampleTextures = [];
this._width = 512;
this._height = 512;
this.init();
};
VectorFieldParticleSurface.prototype = {
constructor: VectorFieldParticleSurface,
init: function () {
var parameters = {
type: Texture.FLOAT,
minFilter: Texture.NEAREST,
magFilter: Texture.NEAREST,
useMipmap: false
};
this._spawnTexture = new Texture2D(parameters);
this._particleTexture0 = new Texture2D(parameters);
this._particleTexture1 = new Texture2D(parameters);
this._frameBuffer = new FrameBuffer({
depthBuffer: false
});
this._particlePass = new Pass({
fragment: Shader.source('ecgl.vfParticle.particle.fragment')
});
this._particlePass.setUniform('velocityTexture', this.vectorFieldTexture);
this._particlePass.setUniform('spawnTexture', this._spawnTexture);
this._downsamplePass = new Pass({
fragment: Shader.source('clay.compositor.downsample')
});
var particlePointsMesh = new Mesh({
// Render after last frame full quad
renderOrder: 10,
material: new Material({
shader: new Shader(Shader.source('ecgl.vfParticle.renderPoints.vertex'), Shader.source('ecgl.vfParticle.renderPoints.fragment'))
}),
mode: Mesh.POINTS,
geometry: new Geometry({
dynamic: true,
mainAttribute: 'texcoord0'
})
});
var particleLinesMesh = new Mesh({
// Render after last frame full quad
renderOrder: 10,
material: new Material({
shader: new Shader(Shader.source('ecgl.vfParticle.renderLines.vertex'), Shader.source('ecgl.vfParticle.renderLines.fragment'))
}),
geometry: new Line2DGeometry(),
culling: false
});
var lastFrameFullQuad = new Mesh({
material: new Material({
shader: new Shader(Shader.source('ecgl.color.vertex'), Shader.source('ecgl.color.fragment')) // DO NOT BLEND Blend will multiply alpha
// transparent: true
}),
geometry: new PlaneGeometry()
});
lastFrameFullQuad.material.enableTexture('diffuseMap');
this._particlePointsMesh = particlePointsMesh;
this._particleLinesMesh = particleLinesMesh;
this._lastFrameFullQuadMesh = lastFrameFullQuad;
this._camera = new OrthoCamera();
this._thisFrameTexture = new Texture2D();
this._lastFrameTexture = new Texture2D();
},
setParticleDensity: function (width, height) {
var nVertex = width * height;
var spawnTextureData = new Float32Array(nVertex * 4);
var off = 0;
var lifeRange = this.particleLife;
for (var i = 0; i < width; i++) {
for (var j = 0; j < height; j++, off++) {
// x position, range [0 - 1]
spawnTextureData[off * 4] = Math.random(); // y position, range [0 - 1]
spawnTextureData[off * 4 + 1] = Math.random(); // Some property
spawnTextureData[off * 4 + 2] = Math.random();
var life = (lifeRange[1] - lifeRange[0]) * Math.random() + lifeRange[0]; // Particle life
spawnTextureData[off * 4 + 3] = life;
}
}
if (this._particleType === 'line') {
this._setLineGeometry(width, height);
} else {
this._setPointsGeometry(width, height);
}
this._spawnTexture.width = width;
this._spawnTexture.height = height;
this._spawnTexture.pixels = spawnTextureData;
this._particleTexture0.width = this._particleTexture1.width = width;
this._particleTexture0.height = this._particleTexture1.height = height;
this._particlePass.setUniform('textureSize', [width, height]);
},
_setPointsGeometry: function (width, height) {
var nVertex = width * height;
var geometry = this._particlePointsMesh.geometry;
var attributes = geometry.attributes;
attributes.texcoord0.init(nVertex);
var off = 0;
for (var i = 0; i < width; i++) {
for (var j = 0; j < height; j++, off++) {
attributes.texcoord0.value[off * 2] = i / width;
attributes.texcoord0.value[off * 2 + 1] = j / height;
}
}
geometry.dirty();
},
_setLineGeometry: function (width, height) {
var nLine = width * height;
var geometry = this._getParticleMesh().geometry;
geometry.setLineCount(nLine);
geometry.resetOffset();
for (var i = 0; i < width; i++) {
for (var j = 0; j < height; j++) {
geometry.addLine([i / width, j / height]);
}
}
geometry.dirty();
},
_getParticleMesh: function () {
return this._particleType === 'line' ? this._particleLinesMesh : this._particlePointsMesh;
},
update: function (renderer, api, deltaTime, firstFrame) {
var particleMesh = this._getParticleMesh();
var frameBuffer = this._frameBuffer;
var particlePass = this._particlePass;
if (firstFrame) {
this._updateDownsampleTextures(renderer, api);
}
particleMesh.material.set('size', this._particleSize * this._supersampling);
particleMesh.material.set('color', this.particleColor);
particlePass.setUniform('speedScaling', this.particleSpeedScaling);
frameBuffer.attach(this._particleTexture1);
particlePass.setUniform('firstFrameTime', firstFrame ? (this.particleLife[1] + this.particleLife[0]) / 2 : 0);
particlePass.setUniform('particleTexture', this._particleTexture0);
particlePass.setUniform('deltaTime', deltaTime);
particlePass.setUniform('elapsedTime', this._elapsedTime);
particlePass.render(renderer, frameBuffer);
particleMesh.material.set('particleTexture', this._particleTexture1);
particleMesh.material.set('prevParticleTexture', this._particleTexture0);
frameBuffer.attach(this._thisFrameTexture);
frameBuffer.bind(renderer);
renderer.gl.clear(renderer.gl.DEPTH_BUFFER_BIT | renderer.gl.COLOR_BUFFER_BIT);
var lastFrameFullQuad = this._lastFrameFullQuadMesh;
lastFrameFullQuad.material.set('diffuseMap', this._lastFrameTexture);
lastFrameFullQuad.material.set('color', [1, 1, 1, this.motionBlurFactor]);
this._camera.update(true);
renderer.renderPass([lastFrameFullQuad, particleMesh], this._camera);
frameBuffer.unbind(renderer);
this._downsample(renderer);
this._swapTexture();
this._elapsedTime += deltaTime;
},
_downsample: function (renderer) {
var downsampleTextures = this._downsampleTextures;
if (downsampleTextures.length === 0) {
return;
}
var current = 0;
var sourceTexture = this._thisFrameTexture;
var targetTexture = downsampleTextures[current];
while (targetTexture) {
this._frameBuffer.attach(targetTexture);
this._downsamplePass.setUniform('texture', sourceTexture);
this._downsamplePass.setUniform('textureSize', [sourceTexture.width, sourceTexture.height]);
this._downsamplePass.render(renderer, this._frameBuffer);
sourceTexture = targetTexture;
targetTexture = downsampleTextures[++current];
}
},
getSurfaceTexture: function () {
var downsampleTextures = this._downsampleTextures;
return downsampleTextures.length > 0 ? downsampleTextures[downsampleTextures.length - 1] : this._lastFrameTexture;
},
setRegion: function (region) {
this._particlePass.setUniform('region', region);
},
resize: function (width, height) {
this._lastFrameTexture.width = width * this._supersampling;
this._lastFrameTexture.height = height * this._supersampling;
this._thisFrameTexture.width = width * this._supersampling;
this._thisFrameTexture.height = height * this._supersampling;
this._width = width;
this._height = height;
},
setParticleSize: function (size) {
var particleMesh = this._getParticleMesh();
if (size <= 2) {
particleMesh.material.disableTexture('spriteTexture');
particleMesh.material.transparent = false;
return;
}
if (!this._spriteTexture) {
this._spriteTexture = new Texture2D();
}
if (!this._spriteTexture.image || this._spriteTexture.image.width !== size) {
this._spriteTexture.image = createSpriteCanvas(size);
this._spriteTexture.dirty();
}
particleMesh.material.transparent = true;
particleMesh.material.enableTexture('spriteTexture');
particleMesh.material.set('spriteTexture', this._spriteTexture);
this._particleSize = size;
},
setGradientTexture: function (gradientTexture) {
var material = this._getParticleMesh().material;
material[gradientTexture ? 'enableTexture' : 'disableTexture']('gradientTexture');
material.setUniform('gradientTexture', gradientTexture);
},
setColorTextureImage: function (colorTextureImg, api) {
var material = this._getParticleMesh().material;
material.setTextureImage('colorTexture', colorTextureImg, api, {
flipY: true
});
},
setParticleType: function (type) {
this._particleType = type;
},
clearFrame: function (renderer) {
var frameBuffer = this._frameBuffer;
frameBuffer.attach(this._lastFrameTexture);
frameBuffer.bind(renderer);
renderer.gl.clear(renderer.gl.DEPTH_BUFFER_BIT | renderer.gl.COLOR_BUFFER_BIT);
frameBuffer.unbind(renderer);
},
setSupersampling: function (supersampling) {
this._supersampling = supersampling;
this.resize(this._width, this._height);
},
_updateDownsampleTextures: function (renderer, api) {
var downsampleTextures = this._downsampleTextures;
var upScale = Math.max(Math.floor(Math.log(this._supersampling / api.getDevicePixelRatio()) / Math.log(2)), 0);
var scale = 2;
var width = this._width * this._supersampling;
var height = this._height * this._supersampling;
for (var i = 0; i < upScale; i++) {
downsampleTextures[i] = downsampleTextures[i] || new Texture2D();
downsampleTextures[i].width = width / scale;
downsampleTextures[i].height = height / scale;
scale *= 2;
}
for (; i < downsampleTextures.length; i++) {
downsampleTextures[i].dispose(renderer);
}
downsampleTextures.length = upScale;
},
_swapTexture: function () {
var tmp = this._particleTexture0;
this._particleTexture0 = this._particleTexture1;
this._particleTexture1 = tmp;
var tmp = this._thisFrameTexture;
this._thisFrameTexture = this._lastFrameTexture;
this._lastFrameTexture = tmp;
},
dispose: function (renderer) {
renderer.disposeFrameBuffer(this._frameBuffer); // Dispose textures
renderer.disposeTexture(this.vectorFieldTexture);
renderer.disposeTexture(this._spawnTexture);
renderer.disposeTexture(this._particleTexture0);
renderer.disposeTexture(this._particleTexture1);
renderer.disposeTexture(this._thisFrameTexture);
renderer.disposeTexture(this._lastFrameTexture);
renderer.disposeGeometry(this._particleLinesMesh.geometry);
renderer.disposeGeometry(this._particlePointsMesh.geometry);
renderer.disposeGeometry(this._lastFrameFullQuadMesh.geometry);
if (this._spriteTexture) {
renderer.disposeTexture(this._spriteTexture);
}
this._particlePass.dispose(renderer);
this._downsamplePass.dispose(renderer);
this._downsampleTextures.forEach(function (texture) {
texture.dispose(renderer);
});
}
};
export default VectorFieldParticleSurface;