Files
2025-11-30 08:35:03 +02:00

3128 lines
117 KiB
JavaScript

/**
* three.quarks v0.15.6 build Fri Jan 17 2025
* https://quarks.art
* Copyright 2025 Alchemist0823 <the.forrest.sun@gmail.com>, MIT
*/
'use strict';
var three = require('three');
var quarks_core = require('quarks.core');
var soft_fragment = `
#ifdef SOFT_PARTICLES
/* #ifdef LOGDEPTH
float distSample = linearize_depth_log(sampleDepth, near, far);
#else
float distSample = ortho ? linearize_depth_ortho(sampleDepth, near, far) : linearize_depth(sampleDepth, near, far);
#endif */
vec2 p2 = projPosition.xy / projPosition.w;
p2 = 0.5 * p2 + 0.5;
float readDepth = texture2D(depthTexture, p2.xy).r;
float viewDepth = linearize_depth(readDepth);
float softParticlesFade = saturate(SOFT_INV_FADE_DISTANCE * ((viewDepth - SOFT_NEAR_FADE) - linearDepth));
gl_FragColor *= softParticlesFade;
//gl_FragColor = vec4(softParticlesFade , 0, 0, 1);
#endif
`;
var soft_pars_fragment = `
#ifdef SOFT_PARTICLES
uniform sampler2D depthTexture;
uniform vec4 projParams;
uniform vec2 softParams;
varying vec4 projPosition;
varying float linearDepth;
#define SOFT_NEAR_FADE softParams.x
#define SOFT_INV_FADE_DISTANCE softParams.y
#define zNear projParams.x
#define zFar projParams.y
float linearize_depth(float d)
{
return (zFar * zNear) / (zFar - d * (zFar - zNear));
}
#endif
`;
var soft_pars_vertex = `
#ifdef SOFT_PARTICLES
varying vec4 projPosition;
varying float linearDepth;
#endif
`;
var soft_vertex = `
#ifdef SOFT_PARTICLES
projPosition = gl_Position;
linearDepth = -mvPosition.z;
#endif
`;
var tile_fragment = `
#ifdef USE_MAP
vec4 texelColor = texture2D( map, vUv);
#ifdef TILE_BLEND
texelColor = mix( texelColor, texture2D( map, vUvNext ), vUvBlend );
#endif
diffuseColor *= texelColor;
#endif
`;
var tile_pars_fragment = `
#if defined( USE_UV ) || defined( USE_ANISOTROPY )
\tvarying vec2 vUv;
#ifdef TILE_BLEND
varying vec2 vUvNext;
varying float vUvBlend;
#endif
#endif
#ifdef USE_MAP
\tuniform mat3 mapTransform;
\tvarying vec2 vMapUv;
#ifdef TILE_BLEND
varying vec2 vMapUvNext;
#endif
#endif
#ifdef USE_ALPHAMAP
\tuniform mat3 alphaMapTransform;
\tvarying vec2 vAlphaMapUv;
#endif
#ifdef USE_LIGHTMAP
\tuniform mat3 lightMapTransform;
\tvarying vec2 vLightMapUv;
#endif
#ifdef USE_AOMAP
\tuniform mat3 aoMapTransform;
\tvarying vec2 vAoMapUv;
#endif
#ifdef USE_BUMPMAP
\tuniform mat3 bumpMapTransform;
\tvarying vec2 vBumpMapUv;
#endif
#ifdef USE_NORMALMAP
\tuniform mat3 normalMapTransform;
\tvarying vec2 vNormalMapUv;
#endif
#ifdef USE_DISPLACEMENTMAP
\tuniform mat3 displacementMapTransform;
\tvarying vec2 vDisplacementMapUv;
#endif
#ifdef USE_EMISSIVEMAP
\tuniform mat3 emissiveMapTransform;
\tvarying vec2 vEmissiveMapUv;
#endif
#ifdef USE_METALNESSMAP
\tuniform mat3 metalnessMapTransform;
\tvarying vec2 vMetalnessMapUv;
#endif
#ifdef USE_ROUGHNESSMAP
\tuniform mat3 roughnessMapTransform;
\tvarying vec2 vRoughnessMapUv;
#endif
#ifdef USE_ANISOTROPYMAP
\tuniform mat3 anisotropyMapTransform;
\tvarying vec2 vAnisotropyMapUv;
#endif
#ifdef USE_CLEARCOATMAP
\tuniform mat3 clearcoatMapTransform;
\tvarying vec2 vClearcoatMapUv;
#endif
#ifdef USE_CLEARCOAT_NORMALMAP
\tuniform mat3 clearcoatNormalMapTransform;
\tvarying vec2 vClearcoatNormalMapUv;
#endif
#ifdef USE_CLEARCOAT_ROUGHNESSMAP
\tuniform mat3 clearcoatRoughnessMapTransform;
\tvarying vec2 vClearcoatRoughnessMapUv;
#endif
#ifdef USE_SHEEN_COLORMAP
\tuniform mat3 sheenColorMapTransform;
\tvarying vec2 vSheenColorMapUv;
#endif
#ifdef USE_SHEEN_ROUGHNESSMAP
\tuniform mat3 sheenRoughnessMapTransform;
\tvarying vec2 vSheenRoughnessMapUv;
#endif
#ifdef USE_IRIDESCENCEMAP
\tuniform mat3 iridescenceMapTransform;
\tvarying vec2 vIridescenceMapUv;
#endif
#ifdef USE_IRIDESCENCE_THICKNESSMAP
\tuniform mat3 iridescenceThicknessMapTransform;
\tvarying vec2 vIridescenceThicknessMapUv;
#endif
#ifdef USE_SPECULARMAP
\tuniform mat3 specularMapTransform;
\tvarying vec2 vSpecularMapUv;
#endif
#ifdef USE_SPECULAR_COLORMAP
\tuniform mat3 specularColorMapTransform;
\tvarying vec2 vSpecularColorMapUv;
#endif
#ifdef USE_SPECULAR_INTENSITYMAP
\tuniform mat3 specularIntensityMapTransform;
\tvarying vec2 vSpecularIntensityMapUv;
#endif
#ifdef USE_TRANSMISSIONMAP
\tuniform mat3 transmissionMapTransform;
\tvarying vec2 vTransmissionMapUv;
#endif
#ifdef USE_THICKNESSMAP
\tuniform mat3 thicknessMapTransform;
\tvarying vec2 vThicknessMapUv;
#endif
`;
var tile_pars_vertex = `
#ifdef UV_TILE
attribute float uvTile;
uniform vec2 tileCount;
mat3 makeTileTransform(float uvTile) {
float col = mod(uvTile, tileCount.x);
float row = (tileCount.y - floor(uvTile / tileCount.x) - 1.0);
return mat3(
1.0 / tileCount.x, 0.0, 0.0,
0.0, 1.0 / tileCount.y, 0.0,
col / tileCount.x, row / tileCount.y, 1.0);
}
#else
mat3 makeTileTransform(float uvTile) {
return mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
}
#endif
#if defined( USE_UV ) || defined( USE_ANISOTROPY )
\tvarying vec2 vUv;
#ifdef TILE_BLEND
varying vec2 vUvNext;
varying float vUvBlend;
#endif
#endif
#ifdef USE_MAP
\tuniform mat3 mapTransform;
\tvarying vec2 vMapUv;
#ifdef TILE_BLEND
varying vec2 vMapUvNext;
#endif
#endif
#ifdef USE_ALPHAMAP
\tuniform mat3 alphaMapTransform;
\tvarying vec2 vAlphaMapUv;
#endif
#ifdef USE_LIGHTMAP
\tuniform mat3 lightMapTransform;
\tvarying vec2 vLightMapUv;
#endif
#ifdef USE_AOMAP
\tuniform mat3 aoMapTransform;
\tvarying vec2 vAoMapUv;
#endif
#ifdef USE_BUMPMAP
\tuniform mat3 bumpMapTransform;
\tvarying vec2 vBumpMapUv;
#endif
#ifdef USE_NORMALMAP
\tuniform mat3 normalMapTransform;
\tvarying vec2 vNormalMapUv;
#endif
#ifdef USE_DISPLACEMENTMAP
\tuniform mat3 displacementMapTransform;
\tvarying vec2 vDisplacementMapUv;
#endif
#ifdef USE_EMISSIVEMAP
\tuniform mat3 emissiveMapTransform;
\tvarying vec2 vEmissiveMapUv;
#endif
#ifdef USE_METALNESSMAP
\tuniform mat3 metalnessMapTransform;
\tvarying vec2 vMetalnessMapUv;
#endif
#ifdef USE_ROUGHNESSMAP
\tuniform mat3 roughnessMapTransform;
\tvarying vec2 vRoughnessMapUv;
#endif
#ifdef USE_ANISOTROPYMAP
\tuniform mat3 anisotropyMapTransform;
\tvarying vec2 vAnisotropyMapUv;
#endif
#ifdef USE_CLEARCOATMAP
\tuniform mat3 clearcoatMapTransform;
\tvarying vec2 vClearcoatMapUv;
#endif
#ifdef USE_CLEARCOAT_NORMALMAP
\tuniform mat3 clearcoatNormalMapTransform;
\tvarying vec2 vClearcoatNormalMapUv;
#endif
#ifdef USE_CLEARCOAT_ROUGHNESSMAP
\tuniform mat3 clearcoatRoughnessMapTransform;
\tvarying vec2 vClearcoatRoughnessMapUv;
#endif
#ifdef USE_SHEEN_COLORMAP
\tuniform mat3 sheenColorMapTransform;
\tvarying vec2 vSheenColorMapUv;
#endif
#ifdef USE_SHEEN_ROUGHNESSMAP
\tuniform mat3 sheenRoughnessMapTransform;
\tvarying vec2 vSheenRoughnessMapUv;
#endif
#ifdef USE_IRIDESCENCEMAP
\tuniform mat3 iridescenceMapTransform;
\tvarying vec2 vIridescenceMapUv;
#endif
#ifdef USE_IRIDESCENCE_THICKNESSMAP
\tuniform mat3 iridescenceThicknessMapTransform;
\tvarying vec2 vIridescenceThicknessMapUv;
#endif
#ifdef USE_SPECULARMAP
\tuniform mat3 specularMapTransform;
\tvarying vec2 vSpecularMapUv;
#endif
#ifdef USE_SPECULAR_COLORMAP
\tuniform mat3 specularColorMapTransform;
\tvarying vec2 vSpecularColorMapUv;
#endif
#ifdef USE_SPECULAR_INTENSITYMAP
\tuniform mat3 specularIntensityMapTransform;
\tvarying vec2 vSpecularIntensityMapUv;
#endif
#ifdef USE_TRANSMISSIONMAP
\tuniform mat3 transmissionMapTransform;
\tvarying vec2 vTransmissionMapUv;
#endif
#ifdef USE_THICKNESSMAP
\tuniform mat3 thicknessMapTransform;
\tvarying vec2 vThicknessMapUv;
#endif
`;
var tile_vertex = `
#ifdef UV_TILE
mat3 tileTransform = makeTileTransform(floor(uvTile));
#ifdef TILE_BLEND
mat3 nextTileTransform = makeTileTransform(ceil(uvTile));
vUvBlend = fract(uvTile);
#endif
#else
mat3 tileTransform = makeTileTransform(0.0);
#endif
#if defined( USE_UV ) || defined( USE_ANISOTROPY )
vUv = (tileTransform *vec3( uv, 1 )).xy;
#if defined( TILE_BLEND ) && defined( UV_TILE )
vUvNext = (nextTileTransform *vec3( uv, 1 )).xy;
#endif
#endif
#ifdef USE_MAP
vMapUv = ( tileTransform * (mapTransform * vec3( MAP_UV, 1 ) )).xy;
#if defined( TILE_BLEND ) && defined( UV_TILE )
vMapUvNext = (nextTileTransform * (mapTransform * vec3( MAP_UV, 1 ))).xy;
#endif
#endif
#ifdef USE_ALPHAMAP
vAlphaMapUv = ( tileTransform * (alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_LIGHTMAP
vLightMapUv = ( tileTransform * (lightMapTransform * vec3( LIGHTMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_AOMAP
vAoMapUv = ( tileTransform * (aoMapTransform * vec3( AOMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_BUMPMAP
vBumpMapUv = ( tileTransform * (bumpMapTransform * vec3( BUMPMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_NORMALMAP
vNormalMapUv = ( tileTransform * (normalMapTransform * vec3( NORMALMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_DISPLACEMENTMAP
vDisplacementMapUv = ( tileTransform * (displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_EMISSIVEMAP
vEmissiveMapUv = ( tileTransform * (emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_METALNESSMAP
vMetalnessMapUv = ( tileTransform * (metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_ROUGHNESSMAP
vRoughnessMapUv = ( tileTransform * (roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_ANISOTROPYMAP
vAnisotropyMapUv = ( tileTransform * (anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_CLEARCOATMAP
vClearcoatMapUv = ( tileTransform * (clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_CLEARCOAT_NORMALMAP
vClearcoatNormalMapUv = ( tileTransform * (clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_CLEARCOAT_ROUGHNESSMAP
vClearcoatRoughnessMapUv = ( tileTransform * (clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_IRIDESCENCEMAP
vIridescenceMapUv = ( tileTransform * (iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_IRIDESCENCE_THICKNESSMAP
vIridescenceThicknessMapUv = ( tileTransform * (iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_SHEEN_COLORMAP
vSheenColorMapUv = ( tileTransform * (sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_SHEEN_ROUGHNESSMAP
vSheenRoughnessMapUv = ( tileTransform * (sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_SPECULARMAP
vSpecularMapUv = ( tileTransform * (specularMapTransform * vec3( SPECULARMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_SPECULAR_COLORMAP
vSpecularColorMapUv = ( tileTransform * (specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_SPECULAR_INTENSITYMAP
vSpecularIntensityMapUv = ( tileTransform * (specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_TRANSMISSIONMAP
vTransmissionMapUv = ( tileTransform * transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) )).xy;
#endif
#ifdef USE_THICKNESSMAP
vThicknessMapUv = ( tileTransform * thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) )).xy;
#endif
`;
const ShaderChunk = three.ShaderChunk;
function registerShaderChunks() {
ShaderChunk['tile_pars_vertex'] = tile_pars_vertex;
ShaderChunk['tile_vertex'] = tile_vertex;
ShaderChunk['tile_pars_fragment'] = tile_pars_fragment;
ShaderChunk['tile_fragment'] = tile_fragment;
ShaderChunk['soft_pars_vertex'] = soft_pars_vertex;
ShaderChunk['soft_vertex'] = soft_vertex;
ShaderChunk['soft_pars_fragment'] = soft_pars_fragment;
ShaderChunk['soft_fragment'] = soft_fragment;
}
class ParticleEmitter extends three.Object3D {
constructor(system) {
super();
this.type = 'ParticleEmitter';
this.system = system;
}
clone() {
const system = this.system.clone();
system.emitter.copy(this, true);
return system.emitter;
}
dispose() { }
extractFromCache(cache) {
const values = [];
for (const key in cache) {
const data = cache[key];
delete data.metadata;
values.push(data);
}
return values;
}
toJSON(meta, options = {}) {
const children = this.children;
this.children = this.children.filter((child) => child.type !== 'ParticleSystemPreview');
const data = super.toJSON(meta);
this.children = children;
if (this.system !== null)
data.object.ps = this.system.toJSON(meta, options);
return data;
}
}
exports.RenderMode = void 0;
(function (RenderMode) {
RenderMode[RenderMode["BillBoard"] = 0] = "BillBoard";
RenderMode[RenderMode["StretchedBillBoard"] = 1] = "StretchedBillBoard";
RenderMode[RenderMode["Mesh"] = 2] = "Mesh";
RenderMode[RenderMode["Trail"] = 3] = "Trail";
RenderMode[RenderMode["HorizontalBillBoard"] = 4] = "HorizontalBillBoard";
RenderMode[RenderMode["VerticalBillBoard"] = 5] = "VerticalBillBoard";
})(exports.RenderMode || (exports.RenderMode = {}));
class VFXBatch extends three.Mesh {
constructor(settings) {
super();
this.type = 'VFXBatch';
this.maxParticles = 1000;
this.systems = new Set();
const layers = new three.Layers();
layers.mask = settings.layers.mask;
const newMat = settings.material.clone();
newMat.defines = {};
Object.assign(newMat.defines, settings.material.defines);
this.settings = {
instancingGeometry: settings.instancingGeometry,
renderMode: settings.renderMode,
renderOrder: settings.renderOrder,
material: newMat,
uTileCount: settings.uTileCount,
vTileCount: settings.vTileCount,
blendTiles: settings.blendTiles,
softParticles: settings.softParticles,
softNearFade: settings.softNearFade,
softFarFade: settings.softFarFade,
layers: layers,
};
this.frustumCulled = false;
this.renderOrder = this.settings.renderOrder;
}
addSystem(system) {
this.systems.add(system);
}
removeSystem(system) {
this.systems.delete(system);
}
applyDepthTexture(depthTexture) {
const uniform = this.material.uniforms['depthTexture'];
if (uniform) {
if (uniform.value !== depthTexture) {
uniform.value = depthTexture;
this.material.needsUpdate = true;
}
}
}
}
const UP = new quarks_core.Vector3(0, 0, 1);
const tempQ = new quarks_core.Quaternion();
const tempV = new quarks_core.Vector3();
const tempV2 = new quarks_core.Vector3();
new quarks_core.Vector3();
const PREWARM_FPS = 60;
const DEFAULT_GEOMETRY = new three.PlaneGeometry(1, 1, 1, 1);
class ParticleSystem {
set time(time) {
this.emissionState.time = time;
}
get time() {
return this.emissionState.time;
}
get layers() {
return this.rendererSettings.layers;
}
get texture() {
return this.rendererSettings.material.map;
}
set texture(texture) {
this.rendererSettings.material.map = texture;
this.neededToUpdateRender = true;
}
get material() {
return this.rendererSettings.material;
}
set material(material) {
this.rendererSettings.material = material;
this.neededToUpdateRender = true;
}
get uTileCount() {
return this.rendererSettings.uTileCount;
}
set uTileCount(u) {
this.rendererSettings.uTileCount = u;
this.neededToUpdateRender = true;
}
get vTileCount() {
return this.rendererSettings.vTileCount;
}
set vTileCount(v) {
this.rendererSettings.vTileCount = v;
this.neededToUpdateRender = true;
}
get blendTiles() {
return this.rendererSettings.blendTiles;
}
set blendTiles(v) {
this.rendererSettings.blendTiles = v;
this.neededToUpdateRender = true;
}
get softParticles() {
return this.rendererSettings.softParticles;
}
set softParticles(v) {
this.rendererSettings.softParticles = v;
this.neededToUpdateRender = true;
}
get softNearFade() {
return this.rendererSettings.softNearFade;
}
set softNearFade(v) {
this.rendererSettings.softNearFade = v;
this.neededToUpdateRender = true;
}
get softFarFade() {
return this.rendererSettings.softFarFade;
}
set softFarFade(v) {
this.rendererSettings.softFarFade = v;
this.neededToUpdateRender = true;
}
get instancingGeometry() {
return this.rendererSettings.instancingGeometry;
}
set instancingGeometry(geometry) {
this.restart();
this.particles.length = 0;
this.rendererSettings.instancingGeometry = geometry;
this.neededToUpdateRender = true;
}
get renderMode() {
return this.rendererSettings.renderMode;
}
set renderMode(renderMode) {
if ((this.rendererSettings.renderMode != exports.RenderMode.Trail && renderMode === exports.RenderMode.Trail) ||
(this.rendererSettings.renderMode == exports.RenderMode.Trail && renderMode !== exports.RenderMode.Trail)) {
this.restart();
this.particles.length = 0;
}
if (this.rendererSettings.renderMode !== renderMode) {
switch (renderMode) {
case exports.RenderMode.Trail:
this.rendererEmitterSettings = {
startLength: new quarks_core.ConstantValue(30),
followLocalOrigin: false,
};
break;
case exports.RenderMode.Mesh:
this.rendererEmitterSettings = {
geometry: new three.PlaneGeometry(1, 1),
};
this.startRotation = new quarks_core.AxisAngleGenerator(new quarks_core.Vector3(0, 1, 0), new quarks_core.ConstantValue(0));
break;
case exports.RenderMode.StretchedBillBoard:
this.rendererEmitterSettings = { speedFactor: 0, lengthFactor: 2 };
if (this.rendererSettings.renderMode === exports.RenderMode.Mesh) {
this.startRotation = new quarks_core.ConstantValue(0);
}
break;
case exports.RenderMode.BillBoard:
case exports.RenderMode.VerticalBillBoard:
case exports.RenderMode.HorizontalBillBoard:
this.rendererEmitterSettings = {};
if (this.rendererSettings.renderMode === exports.RenderMode.Mesh) {
this.startRotation = new quarks_core.ConstantValue(0);
}
break;
}
}
this.rendererSettings.renderMode = renderMode;
this.neededToUpdateRender = true;
}
get renderOrder() {
return this.rendererSettings.renderOrder;
}
set renderOrder(renderOrder) {
this.rendererSettings.renderOrder = renderOrder;
this.neededToUpdateRender = true;
}
get blending() {
return this.rendererSettings.material.blending;
}
set blending(blending) {
this.rendererSettings.material.blending = blending;
this.neededToUpdateRender = true;
}
constructor(parameters) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1;
this.temp = new quarks_core.Vector3();
this.travelDistance = 0;
this.normalMatrix = new quarks_core.Matrix3();
this.memory = [];
this.listeners = {};
this.firstTimeUpdate = true;
this.autoDestroy = parameters.autoDestroy === undefined ? false : parameters.autoDestroy;
this.duration = (_a = parameters.duration) !== null && _a !== void 0 ? _a : 1;
this.looping = parameters.looping === undefined ? true : parameters.looping;
this.prewarm = parameters.prewarm === undefined ? false : parameters.prewarm;
this.startLife = (_b = parameters.startLife) !== null && _b !== void 0 ? _b : new quarks_core.ConstantValue(5);
this.startSpeed = (_c = parameters.startSpeed) !== null && _c !== void 0 ? _c : new quarks_core.ConstantValue(0);
this.startRotation = (_d = parameters.startRotation) !== null && _d !== void 0 ? _d : new quarks_core.ConstantValue(0);
this.startSize = (_e = parameters.startSize) !== null && _e !== void 0 ? _e : new quarks_core.ConstantValue(1);
this.startColor = (_f = parameters.startColor) !== null && _f !== void 0 ? _f : new quarks_core.ConstantColor(new quarks_core.Vector4(1, 1, 1, 1));
this.emissionOverTime = (_g = parameters.emissionOverTime) !== null && _g !== void 0 ? _g : new quarks_core.ConstantValue(10);
this.emissionOverDistance = (_h = parameters.emissionOverDistance) !== null && _h !== void 0 ? _h : new quarks_core.ConstantValue(0);
this.emissionBursts = (_j = parameters.emissionBursts) !== null && _j !== void 0 ? _j : [];
this.onlyUsedByOther = (_k = parameters.onlyUsedByOther) !== null && _k !== void 0 ? _k : false;
this.emitterShape = (_l = parameters.shape) !== null && _l !== void 0 ? _l : new quarks_core.SphereEmitter();
this.behaviors = (_m = parameters.behaviors) !== null && _m !== void 0 ? _m : new Array();
this.worldSpace = (_o = parameters.worldSpace) !== null && _o !== void 0 ? _o : false;
this.rendererEmitterSettings = (_p = parameters.rendererEmitterSettings) !== null && _p !== void 0 ? _p : {};
if (parameters.renderMode === exports.RenderMode.StretchedBillBoard) {
const stretchedBillboardSettings = this.rendererEmitterSettings;
if (parameters.speedFactor !== undefined) {
stretchedBillboardSettings.speedFactor = parameters.speedFactor;
}
stretchedBillboardSettings.speedFactor = (_q = stretchedBillboardSettings.speedFactor) !== null && _q !== void 0 ? _q : 0;
stretchedBillboardSettings.lengthFactor = (_r = stretchedBillboardSettings.lengthFactor) !== null && _r !== void 0 ? _r : 0;
}
this.rendererSettings = {
instancingGeometry: (_s = parameters.instancingGeometry) !== null && _s !== void 0 ? _s : DEFAULT_GEOMETRY,
renderMode: (_t = parameters.renderMode) !== null && _t !== void 0 ? _t : exports.RenderMode.BillBoard,
renderOrder: (_u = parameters.renderOrder) !== null && _u !== void 0 ? _u : 0,
material: parameters.material,
uTileCount: (_v = parameters.uTileCount) !== null && _v !== void 0 ? _v : 1,
vTileCount: (_w = parameters.vTileCount) !== null && _w !== void 0 ? _w : 1,
blendTiles: (_x = parameters.blendTiles) !== null && _x !== void 0 ? _x : false,
softParticles: (_y = parameters.softParticles) !== null && _y !== void 0 ? _y : false,
softNearFade: (_z = parameters.softNearFade) !== null && _z !== void 0 ? _z : 0,
softFarFade: (_0 = parameters.softFarFade) !== null && _0 !== void 0 ? _0 : 0,
layers: (_1 = parameters.layers) !== null && _1 !== void 0 ? _1 : new three.Layers(),
};
this.neededToUpdateRender = true;
this.particles = new Array();
this.startTileIndex = parameters.startTileIndex || new quarks_core.ConstantValue(0);
this.emitter = new ParticleEmitter(this);
this.paused = false;
this.particleNum = 0;
this.emissionState = {
isBursting: false,
burstParticleIndex: 0,
burstParticleCount: 0,
burstIndex: 0,
burstWaveIndex: 0,
time: 0,
waitEmiting: 0,
travelDistance: 0,
};
this.emissionBursts.forEach((burst) => burst.count.startGen(this.memory));
this.emissionOverDistance.startGen(this.memory);
this.emitEnded = false;
this.markForDestroy = false;
this.prewarmed = false;
}
pause() {
this.paused = true;
}
play() {
this.paused = false;
}
stop() {
this.restart();
this.pause();
}
spawn(count, emissionState, matrix) {
tempQ.setFromRotationMatrix(matrix);
const translation = tempV;
const quaternion = tempQ;
const scale = tempV2;
matrix.decompose(translation, quaternion, scale);
for (let i = 0; i < count; i++) {
emissionState.burstParticleIndex = i;
this.particleNum++;
while (this.particles.length < this.particleNum) {
if (this.rendererSettings.renderMode === exports.RenderMode.Trail) {
this.particles.push(new quarks_core.TrailParticle());
}
else {
this.particles.push(new quarks_core.SpriteParticle());
}
}
const particle = this.particles[this.particleNum - 1];
particle.reset();
particle.speedModifier = 1;
this.startColor.startGen(particle.memory);
this.startColor.genColor(particle.memory, particle.startColor, this.emissionState.time);
particle.color.copy(particle.startColor);
this.startSpeed.startGen(particle.memory);
particle.startSpeed = this.startSpeed.genValue(particle.memory, emissionState.time / this.duration);
this.startLife.startGen(particle.memory);
particle.life = this.startLife.genValue(particle.memory, emissionState.time / this.duration);
particle.age = 0;
this.startSize.startGen(particle.memory);
if (this.startSize.type === "vec3function") {
this.startSize.genValue(particle.memory, particle.startSize, emissionState.time / this.duration);
}
else {
const size = this.startSize.genValue(particle.memory, emissionState.time / this.duration);
particle.startSize.set(size, size, size);
}
this.startTileIndex.startGen(particle.memory);
particle.uvTile = this.startTileIndex.genValue(particle.memory);
particle.size.copy(particle.startSize);
if (this.rendererSettings.renderMode === exports.RenderMode.Mesh ||
this.rendererSettings.renderMode === exports.RenderMode.BillBoard ||
this.rendererSettings.renderMode === exports.RenderMode.VerticalBillBoard ||
this.rendererSettings.renderMode === exports.RenderMode.HorizontalBillBoard ||
this.rendererSettings.renderMode === exports.RenderMode.StretchedBillBoard) {
const sprite = particle;
this.startRotation.startGen(particle.memory);
if (this.rendererSettings.renderMode === exports.RenderMode.Mesh) {
if (!(sprite.rotation instanceof quarks_core.Quaternion)) {
sprite.rotation = new quarks_core.Quaternion();
}
if (this.startRotation.type === 'rotation') {
this.startRotation.genValue(particle.memory, sprite.rotation, 1, emissionState.time / this.duration);
}
else {
sprite.rotation.setFromAxisAngle(UP, this.startRotation.genValue(sprite.memory, (emissionState.time / this.duration)));
}
}
else {
if (this.startRotation.type === 'rotation') {
sprite.rotation = 0;
}
else {
sprite.rotation = this.startRotation.genValue(sprite.memory, emissionState.time / this.duration);
}
}
}
else if (this.rendererSettings.renderMode === exports.RenderMode.Trail) {
const trail = particle;
this.rendererEmitterSettings.startLength.startGen(trail.memory);
trail.length = this.rendererEmitterSettings.startLength.genValue(trail.memory, emissionState.time / this.duration);
}
this.emitterShape.initialize(particle, emissionState);
if (this.rendererSettings.renderMode === exports.RenderMode.Trail &&
this.rendererEmitterSettings.followLocalOrigin) {
const trail = particle;
trail.localPosition = new quarks_core.Vector3().copy(trail.position);
}
if (this.worldSpace) {
particle.position.applyMatrix4(matrix);
particle.startSize.multiply(scale).abs();
particle.size.copy(particle.startSize);
particle.velocity.multiply(scale).applyMatrix3(this.normalMatrix);
if (particle.rotation && particle.rotation instanceof quarks_core.Quaternion) {
particle.rotation.multiplyQuaternions(tempQ, particle.rotation);
}
}
else {
if (this.onlyUsedByOther) {
particle.parentMatrix = matrix;
}
}
for (let j = 0; j < this.behaviors.length; j++) {
this.behaviors[j].initialize(particle, this);
}
}
}
endEmit() {
this.emitEnded = true;
if (this.autoDestroy) {
this.markForDestroy = true;
}
this.fire({ type: "emitEnd", particleSystem: this });
}
dispose() {
if (this._renderer)
this._renderer.deleteSystem(this);
this.emitter.dispose();
if (this.emitter.parent)
this.emitter.parent.remove(this.emitter);
this.fire({ type: "destroy", particleSystem: this });
}
restart() {
this.memory.length = 0;
this.paused = false;
this.particleNum = 0;
this.emissionState.isBursting = false;
this.emissionState.burstIndex = 0;
this.emissionState.burstWaveIndex = 0;
this.emissionState.time = 0;
this.emissionState.waitEmiting = 0;
this.behaviors.forEach((behavior) => {
behavior.reset();
});
this.emitEnded = false;
this.markForDestroy = false;
this.prewarmed = false;
this.emissionBursts.forEach((burst) => burst.count.startGen(this.memory));
this.emissionOverDistance.startGen(this.memory);
}
update(delta) {
if (this.paused)
return;
let currentParent = this.emitter;
while (currentParent.parent) {
currentParent = currentParent.parent;
}
if (currentParent.type !== 'Scene') {
this.dispose();
return;
}
if (this.firstTimeUpdate) {
this.firstTimeUpdate = false;
this.emitter.updateWorldMatrix(true, false);
}
if (this.emitEnded && this.particleNum === 0) {
if (this.markForDestroy && this.emitter.parent)
this.dispose();
return;
}
if (this.looping && this.prewarm && !this.prewarmed) {
this.prewarmed = true;
for (let i = 0; i < this.duration * PREWARM_FPS; i++) {
this.update(1.0 / PREWARM_FPS);
}
}
if (delta > 0.1) {
delta = 0.1;
}
if (this.neededToUpdateRender) {
if (this._renderer)
this._renderer.updateSystem(this);
this.neededToUpdateRender = false;
}
if (!this.onlyUsedByOther) {
this.emit(delta, this.emissionState, this.emitter.matrixWorld);
}
this.emitterShape.update(this, delta);
for (let j = 0; j < this.behaviors.length; j++) {
this.behaviors[j].frameUpdate(delta);
for (let i = 0; i < this.particleNum; i++) {
if (!this.particles[i].died) {
this.behaviors[j].update(this.particles[i], delta);
}
}
}
for (let i = 0; i < this.particleNum; i++) {
if (this.rendererEmitterSettings.followLocalOrigin &&
this.particles[i].localPosition) {
this.particles[i].position.copy(this.particles[i].localPosition);
if (this.particles[i].parentMatrix) {
this.particles[i].position.applyMatrix4(this.particles[i].parentMatrix);
}
else {
this.particles[i].position.applyMatrix4(this.emitter.matrixWorld);
}
}
else {
this.particles[i].position.addScaledVector(this.particles[i].velocity, delta * this.particles[i].speedModifier);
}
this.particles[i].age += delta;
}
if (this.rendererSettings.renderMode === exports.RenderMode.Trail) {
for (let i = 0; i < this.particleNum; i++) {
const particle = this.particles[i];
particle.update();
}
}
for (let i = 0; i < this.particleNum; i++) {
const particle = this.particles[i];
if (particle.died && (!(particle instanceof quarks_core.TrailParticle) || particle.previous.length === 0)) {
this.particles[i] = this.particles[this.particleNum - 1];
this.particles[this.particleNum - 1] = particle;
this.particleNum--;
i--;
this.fire({ type: "particleDied", particleSystem: this, particle: particle });
}
}
}
emit(delta, emissionState, emitterMatrix) {
if (emissionState.time > this.duration) {
if (this.looping) {
emissionState.time -= this.duration;
emissionState.burstIndex = 0;
this.behaviors.forEach((behavior) => {
behavior.reset();
});
}
else {
if (!this.emitEnded && !this.onlyUsedByOther) {
this.endEmit();
}
}
}
this.normalMatrix.getNormalMatrix(emitterMatrix);
const totalSpawn = Math.ceil(emissionState.waitEmiting);
this.spawn(totalSpawn, emissionState, emitterMatrix);
emissionState.waitEmiting -= totalSpawn;
while (emissionState.burstIndex < this.emissionBursts.length &&
this.emissionBursts[emissionState.burstIndex].time <= emissionState.time) {
if (Math.random() < this.emissionBursts[emissionState.burstIndex].probability) {
const count = this.emissionBursts[emissionState.burstIndex].count.genValue(this.memory, this.time);
emissionState.isBursting = true;
emissionState.burstParticleCount = count;
this.spawn(count, emissionState, emitterMatrix);
emissionState.isBursting = false;
}
emissionState.burstIndex++;
}
if (!this.emitEnded) {
emissionState.waitEmiting +=
delta * this.emissionOverTime.genValue(this.memory, emissionState.time / this.duration);
if (emissionState.previousWorldPos != undefined) {
this.temp.set(emitterMatrix.elements[12], emitterMatrix.elements[13], emitterMatrix.elements[14]);
emissionState.travelDistance += emissionState.previousWorldPos.distanceTo(this.temp);
const emitPerMeter = this.emissionOverDistance.genValue(this.memory, emissionState.time / this.duration);
if (emissionState.travelDistance * emitPerMeter > 0) {
const count = Math.floor(emissionState.travelDistance * emitPerMeter);
emissionState.travelDistance -= count / emitPerMeter;
emissionState.waitEmiting += count;
}
}
}
if (emissionState.previousWorldPos === undefined)
emissionState.previousWorldPos = new quarks_core.Vector3();
emissionState.previousWorldPos.set(emitterMatrix.elements[12], emitterMatrix.elements[13], emitterMatrix.elements[14]);
emissionState.time += delta;
}
toJSON(meta, options = {}) {
var _a;
const isRootObject = meta === undefined || typeof meta === 'string';
if (isRootObject) {
meta = {
geometries: {},
materials: {},
textures: {},
images: {},
shapes: {},
skeletons: {},
animations: {},
nodes: {},
};
}
meta.materials[this.rendererSettings.material.uuid] = this.rendererSettings.material.toJSON(meta);
if (options.useUrlForImage) {
if (((_a = this.texture) === null || _a === void 0 ? void 0 : _a.source) !== undefined) {
const image = this.texture.source;
meta.images[image.uuid] = {
uuid: image.uuid,
url: this.texture.image.url,
};
}
}
let rendererSettingsJSON;
if (this.renderMode === exports.RenderMode.Trail) {
rendererSettingsJSON = {
startLength: this.rendererEmitterSettings.startLength.toJSON(),
followLocalOrigin: this.rendererEmitterSettings.followLocalOrigin,
};
}
else if (this.renderMode === exports.RenderMode.Mesh) {
rendererSettingsJSON = {};
}
else if (this.renderMode === exports.RenderMode.StretchedBillBoard) {
rendererSettingsJSON = {
speedFactor: this.rendererEmitterSettings.speedFactor,
lengthFactor: this.rendererEmitterSettings.lengthFactor,
};
}
else {
rendererSettingsJSON = {};
}
const geometry = this.rendererSettings.instancingGeometry;
if (meta.geometries && !meta.geometries[geometry.uuid]) {
meta.geometries[geometry.uuid] = geometry.toJSON();
}
return {
version: '3.0',
autoDestroy: this.autoDestroy,
looping: this.looping,
prewarm: this.prewarm,
duration: this.duration,
shape: this.emitterShape.toJSON(),
startLife: this.startLife.toJSON(),
startSpeed: this.startSpeed.toJSON(),
startRotation: this.startRotation.toJSON(),
startSize: this.startSize.toJSON(),
startColor: this.startColor.toJSON(),
emissionOverTime: this.emissionOverTime.toJSON(),
emissionOverDistance: this.emissionOverDistance.toJSON(),
emissionBursts: this.emissionBursts.map((burst) => ({
time: burst.time,
count: burst.count.toJSON(),
probability: burst.probability,
interval: burst.interval,
cycle: burst.cycle,
})),
onlyUsedByOther: this.onlyUsedByOther,
instancingGeometry: this.rendererSettings.instancingGeometry.uuid,
renderOrder: this.renderOrder,
renderMode: this.renderMode,
rendererEmitterSettings: rendererSettingsJSON,
material: this.rendererSettings.material.uuid,
layers: this.layers.mask,
startTileIndex: this.startTileIndex.toJSON(),
uTileCount: this.uTileCount,
vTileCount: this.vTileCount,
blendTiles: this.blendTiles,
softParticles: this.rendererSettings.softParticles,
softFarFade: this.rendererSettings.softFarFade,
softNearFade: this.rendererSettings.softNearFade,
behaviors: this.behaviors.map((behavior) => behavior.toJSON()),
worldSpace: this.worldSpace,
};
}
static fromJSON(json, meta, dependencies) {
var _a, _b;
const shape = quarks_core.EmitterFromJSON(json.shape, meta);
let rendererEmitterSettings;
if (json.renderMode === exports.RenderMode.Trail) {
const trailSettings = json.rendererEmitterSettings;
rendererEmitterSettings = {
startLength: trailSettings.startLength != undefined
? quarks_core.ValueGeneratorFromJSON(trailSettings.startLength)
: new quarks_core.ConstantValue(30),
followLocalOrigin: trailSettings.followLocalOrigin,
};
}
else if (json.renderMode === exports.RenderMode.Mesh) {
rendererEmitterSettings = {};
}
else if (json.renderMode === exports.RenderMode.StretchedBillBoard) {
rendererEmitterSettings = json.rendererEmitterSettings;
if (json.speedFactor != undefined) {
rendererEmitterSettings.speedFactor = json.speedFactor;
}
}
else {
rendererEmitterSettings = {};
}
const layers = new three.Layers();
if (json.layers) {
layers.mask = json.layers;
}
const ps = new ParticleSystem({
autoDestroy: json.autoDestroy,
looping: json.looping,
prewarm: json.prewarm,
duration: json.duration,
shape: shape,
startLife: quarks_core.ValueGeneratorFromJSON(json.startLife),
startSpeed: quarks_core.ValueGeneratorFromJSON(json.startSpeed),
startRotation: quarks_core.GeneratorFromJSON(json.startRotation),
startSize: quarks_core.GeneratorFromJSON(json.startSize),
startColor: quarks_core.ColorGeneratorFromJSON(json.startColor),
emissionOverTime: quarks_core.ValueGeneratorFromJSON(json.emissionOverTime),
emissionOverDistance: quarks_core.ValueGeneratorFromJSON(json.emissionOverDistance),
emissionBursts: (_a = json.emissionBursts) === null || _a === void 0 ? void 0 : _a.map((burst) => {
var _a, _b, _c;
return ({
time: burst.time,
count: typeof burst.count === 'number'
? new quarks_core.ConstantValue(burst.count)
: quarks_core.ValueGeneratorFromJSON(burst.count),
probability: (_a = burst.probability) !== null && _a !== void 0 ? _a : 1,
interval: (_b = burst.interval) !== null && _b !== void 0 ? _b : 0.1,
cycle: (_c = burst.cycle) !== null && _c !== void 0 ? _c : 1,
});
}),
onlyUsedByOther: json.onlyUsedByOther,
instancingGeometry: meta.geometries[json.instancingGeometry],
renderMode: json.renderMode,
rendererEmitterSettings: rendererEmitterSettings,
renderOrder: json.renderOrder,
layers: layers,
material: json.material
? meta.materials[json.material]
: json.texture
? new three.MeshBasicMaterial({
map: meta.textures[json.texture],
transparent: (_b = json.transparent) !== null && _b !== void 0 ? _b : true,
blending: json.blending,
side: three.DoubleSide,
})
: new three.MeshBasicMaterial({
color: 0xffffff,
transparent: true,
blending: three.AdditiveBlending,
side: three.DoubleSide,
}),
startTileIndex: typeof json.startTileIndex === 'number'
? new quarks_core.ConstantValue(json.startTileIndex)
: quarks_core.ValueGeneratorFromJSON(json.startTileIndex),
uTileCount: json.uTileCount,
vTileCount: json.vTileCount,
blendTiles: json.blendTiles,
softParticles: json.softParticles,
softFarFade: json.softFarFade,
softNearFade: json.softNearFade,
behaviors: [],
worldSpace: json.worldSpace,
});
ps.behaviors = json.behaviors.map((behaviorJson) => {
const behavior = quarks_core.BehaviorFromJSON(behaviorJson, ps);
if (behavior.type === 'EmitSubParticleSystem') {
dependencies[behaviorJson.subParticleSystem] = behavior;
}
return behavior;
});
return ps;
}
addBehavior(behavior) {
this.behaviors.push(behavior);
}
getRendererSettings() {
return this.rendererSettings;
}
addEventListener(event, callback) {
if (!this.listeners[event])
this.listeners[event] = [];
this.listeners[event].push(callback);
}
removeAllEventListeners(event) {
if (this.listeners[event])
this.listeners[event] = [];
}
removeEventListener(event, callback) {
if (this.listeners[event]) {
const index = this.listeners[event].indexOf(callback);
if (index !== -1) {
this.listeners[event].splice(index, 1);
}
}
}
fire(event) {
if (this.listeners[event.type]) {
this.listeners[event.type].forEach(callback => callback(event));
}
}
clone() {
const newEmissionBursts = [];
for (const emissionBurst of this.emissionBursts) {
const newEmissionBurst = {};
Object.assign(newEmissionBurst, emissionBurst);
newEmissionBursts.push(newEmissionBurst);
}
const newBehaviors = [];
for (const behavior of this.behaviors) {
newBehaviors.push(behavior.clone());
}
let rendererEmitterSettings;
if (this.renderMode === exports.RenderMode.Trail) {
rendererEmitterSettings = {
startLength: this.rendererEmitterSettings.startLength.clone(),
followLocalOrigin: this.rendererEmitterSettings.followLocalOrigin,
};
}
else if (this.renderMode === exports.RenderMode.StretchedBillBoard) {
rendererEmitterSettings = {
lengthFactor: this.rendererEmitterSettings.lengthFactor,
speedFactor: this.rendererEmitterSettings.speedFactor,
};
}
else {
rendererEmitterSettings = {};
}
const layers = new three.Layers();
layers.mask = this.layers.mask;
return new ParticleSystem({
autoDestroy: this.autoDestroy,
looping: this.looping,
duration: this.duration,
shape: this.emitterShape.clone(),
startLife: this.startLife.clone(),
startSpeed: this.startSpeed.clone(),
startRotation: this.startRotation.clone(),
startSize: this.startSize.clone(),
startColor: this.startColor.clone(),
emissionOverTime: this.emissionOverTime.clone(),
emissionOverDistance: this.emissionOverDistance.clone(),
emissionBursts: newEmissionBursts,
onlyUsedByOther: this.onlyUsedByOther,
instancingGeometry: this.rendererSettings.instancingGeometry,
renderMode: this.renderMode,
renderOrder: this.renderOrder,
rendererEmitterSettings: rendererEmitterSettings,
material: this.rendererSettings.material,
startTileIndex: this.startTileIndex,
uTileCount: this.uTileCount,
vTileCount: this.vTileCount,
blendTiles: this.blendTiles,
softParticles: this.softParticles,
softFarFade: this.softFarFade,
softNearFade: this.softNearFade,
behaviors: newBehaviors,
worldSpace: this.worldSpace,
layers: layers,
});
}
}
var particle_frag = `
#include <common>
#include <color_pars_fragment>
#include <map_pars_fragment>
#include <logdepthbuf_pars_fragment>
#include <clipping_planes_pars_fragment>
#include <alphatest_pars_fragment>
#include <tile_pars_fragment>
#include <soft_pars_fragment>
void main() {
#include <clipping_planes_fragment>
vec3 outgoingLight = vec3( 0.0 );
vec4 diffuseColor = vColor;
#include <logdepthbuf_fragment>
#include <tile_fragment>
#include <alphatest_fragment>
outgoingLight = diffuseColor.rgb;
#ifdef USE_COLOR_AS_ALPHA
gl_FragColor = vec4( outgoingLight, diffuseColor.r );
#else
gl_FragColor = vec4( outgoingLight, diffuseColor.a );
#endif
#include <soft_fragment>
#include <tonemapping_fragment>
}
`;
var particle_physics_frag = `
#define STANDARD
#ifdef PHYSICAL
#define IOR
#define USE_SPECULAR
#endif
uniform vec3 diffuse;
uniform vec3 emissive;
uniform float roughness;
uniform float metalness;
uniform float opacity;
#ifdef IOR
uniform float ior;
#endif
#ifdef USE_SPECULAR
uniform float specularIntensity;
uniform vec3 specularColor;
#ifdef USE_SPECULAR_COLORMAP
uniform sampler2D specularColorMap;
#endif
#ifdef USE_SPECULAR_INTENSITYMAP
uniform sampler2D specularIntensityMap;
#endif
#endif
#ifdef USE_CLEARCOAT
uniform float clearcoat;
uniform float clearcoatRoughness;
#endif
#ifdef USE_DISPERSION
uniform float dispersion;
#endif
#ifdef USE_IRIDESCENCE
uniform float iridescence;
uniform float iridescenceIOR;
uniform float iridescenceThicknessMinimum;
uniform float iridescenceThicknessMaximum;
#endif
#ifdef USE_SHEEN
uniform vec3 sheenColor;
uniform float sheenRoughness;
#ifdef USE_SHEEN_COLORMAP
uniform sampler2D sheenColorMap;
#endif
#ifdef USE_SHEEN_ROUGHNESSMAP
uniform sampler2D sheenRoughnessMap;
#endif
#endif
#ifdef USE_ANISOTROPY
uniform vec2 anisotropyVector;
#ifdef USE_ANISOTROPYMAP
uniform sampler2D anisotropyMap;
#endif
#endif
varying vec3 vViewPosition;
#include <common>
#include <packing>
#include <dithering_pars_fragment>
#include <color_pars_fragment>
#include <uv_pars_fragment>
#include <map_pars_fragment>
#include <alphamap_pars_fragment>
#include <alphatest_pars_fragment>
#include <alphahash_pars_fragment>
#include <aomap_pars_fragment>
#include <lightmap_pars_fragment>
#include <emissivemap_pars_fragment>
#include <iridescence_fragment>
#include <cube_uv_reflection_fragment>
#include <envmap_common_pars_fragment>
#include <envmap_physical_pars_fragment>
#include <fog_pars_fragment>
#include <lights_pars_begin>
#include <normal_pars_fragment>
#include <lights_physical_pars_fragment>
#include <transmission_pars_fragment>
#include <shadowmap_pars_fragment>
#include <bumpmap_pars_fragment>
#include <normalmap_pars_fragment>
#include <clearcoat_pars_fragment>
#include <iridescence_pars_fragment>
#include <roughnessmap_pars_fragment>
#include <metalnessmap_pars_fragment>
#include <logdepthbuf_pars_fragment>
#include <clipping_planes_pars_fragment>
void main() {
vec4 diffuseColor = vec4( diffuse, opacity );
#include <clipping_planes_fragment>
ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
vec3 totalEmissiveRadiance = emissive;
#include <logdepthbuf_fragment>
#include <map_fragment>
#include <color_fragment>
#include <alphamap_fragment>
#include <alphatest_fragment>
#include <alphahash_fragment>
#include <roughnessmap_fragment>
#include <metalnessmap_fragment>
#include <normal_fragment_begin>
#include <normal_fragment_maps>
#include <clearcoat_normal_fragment_begin>
#include <clearcoat_normal_fragment_maps>
#include <emissivemap_fragment>
// accumulation
#include <lights_physical_fragment>
#include <lights_fragment_begin>
#include <lights_fragment_maps>
#include <lights_fragment_end>
// modulation
#include <aomap_fragment>
vec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;
vec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;
#include <transmission_fragment>
vec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;
#ifdef USE_SHEEN
// Sheen energy compensation approximation calculation can be found at the end of
// https://drive.google.com/file/d/1T0D1VSyR4AllqIJTQAraEIzjlb5h4FKH/view?usp=sharing
float sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );
outgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;
#endif
#ifdef USE_CLEARCOAT
float dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );
vec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );
outgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;
#endif
#include <opaque_fragment>
#include <tonemapping_fragment>
#include <colorspace_fragment>
#include <fog_fragment>
#include <premultiplied_alpha_fragment>
#include <dithering_fragment>
}`;
var particle_vert = `
#include <common>
#include <color_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
#include <tile_pars_vertex>
#include <soft_pars_vertex>
attribute vec3 offset;
attribute float rotation;
attribute vec3 size;
void main() {
vec2 alignedPosition = position.xy * size.xy;
vec2 rotatedPosition;
rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;
rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;
#ifdef HORIZONTAL
vec4 mvPosition = modelMatrix * vec4( offset, 1.0 );
mvPosition.x += rotatedPosition.x;
mvPosition.z -= rotatedPosition.y;
mvPosition = viewMatrix * mvPosition;
#elif defined(VERTICAL)
vec4 mvPosition = modelMatrix * vec4( offset, 1.0 );
mvPosition.y += rotatedPosition.y;
mvPosition = viewMatrix * mvPosition;
mvPosition.x += rotatedPosition.x;
#else
vec4 mvPosition = modelViewMatrix * vec4( offset, 1.0 );
mvPosition.xy += rotatedPosition;
#endif
vColor = color;
gl_Position = projectionMatrix * mvPosition;
#include <logdepthbuf_vertex>
#include <clipping_planes_vertex>
#include <tile_vertex>
#include <soft_vertex>
}
`;
var local_particle_vert = `
#include <common>
#include <color_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
#include <tile_pars_vertex>
#include <soft_pars_vertex>
attribute vec3 offset;
attribute vec4 rotation;
attribute vec3 size;
// attribute vec4 color;
void main() {
float x2 = rotation.x + rotation.x, y2 = rotation.y + rotation.y, z2 = rotation.z + rotation.z;
float xx = rotation.x * x2, xy = rotation.x * y2, xz = rotation.x * z2;
float yy = rotation.y * y2, yz = rotation.y * z2, zz = rotation.z * z2;
float wx = rotation.w * x2, wy = rotation.w * y2, wz = rotation.w * z2;
float sx = size.x, sy = size.y, sz = size.z;
mat4 matrix = mat4(( 1.0 - ( yy + zz ) ) * sx, ( xy + wz ) * sx, ( xz - wy ) * sx, 0.0, // 1. column
( xy - wz ) * sy, ( 1.0 - ( xx + zz ) ) * sy, ( yz + wx ) * sy, 0.0, // 2. column
( xz + wy ) * sz, ( yz - wx ) * sz, ( 1.0 - ( xx + yy ) ) * sz, 0.0, // 3. column
offset.x, offset.y, offset.z, 1.0);
vec4 mvPosition = modelViewMatrix * (matrix * vec4( position, 1.0 ));
vColor = color;
gl_Position = projectionMatrix * mvPosition;
#include <logdepthbuf_vertex>
#include <clipping_planes_vertex>
#include <tile_vertex>
#include <soft_vertex>
}
`;
var local_particle_physics_vert = `
#define STANDARD
varying vec3 vViewPosition;
#ifdef USE_TRANSMISSION
varying vec3 vWorldPosition;
#endif
#include <common>
attribute vec3 offset;
attribute vec4 rotation;
attribute vec3 size;
#include <tile_pars_vertex>
#include <displacementmap_pars_vertex>
#include <color_pars_vertex>
#include <fog_pars_vertex>
#include <normal_pars_vertex>
#include <morphtarget_pars_vertex>
#include <skinning_pars_vertex>
#include <shadowmap_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
void main() {
#include <tile_vertex>
float x2 = rotation.x + rotation.x, y2 = rotation.y + rotation.y, z2 = rotation.z + rotation.z;
float xx = rotation.x * x2, xy = rotation.x * y2, xz = rotation.x * z2;
float yy = rotation.y * y2, yz = rotation.y * z2, zz = rotation.z * z2;
float wx = rotation.w * x2, wy = rotation.w * y2, wz = rotation.w * z2;
float sx = size.x, sy = size.y, sz = size.z;
mat4 particleMatrix = mat4(( 1.0 - ( yy + zz ) ) * sx, ( xy + wz ) * sx, ( xz - wy ) * sx, 0.0, // 1. column
( xy - wz ) * sy, ( 1.0 - ( xx + zz ) ) * sy, ( yz + wx ) * sy, 0.0, // 2. column
( xz + wy ) * sz, ( yz - wx ) * sz, ( 1.0 - ( xx + yy ) ) * sz, 0.0, // 3. column
offset.x, offset.y, offset.z, 1.0);
#include <color_vertex>
#include <morphinstance_vertex>
#include <morphcolor_vertex>
#include <batching_vertex>
#include <beginnormal_vertex>
#include <morphnormal_vertex>
#include <skinbase_vertex>
#include <skinnormal_vertex>
// replace defaultnormal_vertex
vec3 transformedNormal = objectNormal;
mat3 m = mat3( particleMatrix );
transformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );
transformedNormal = m * transformedNormal;
transformedNormal = normalMatrix * transformedNormal;
#ifdef FLIP_SIDED
transformedNormal = - transformedNormal;
#endif
#ifdef USE_TANGENT
vec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;
#ifdef FLIP_SIDED
transformedTangent = - transformedTangent;
#endif
#endif
#include <normal_vertex>
#include <begin_vertex>
#include <morphtarget_vertex>
#include <skinning_vertex>
#include <displacementmap_vertex>
// replace include <project_vertex>
vec4 mvPosition = vec4( transformed, 1.0 );
mvPosition = modelViewMatrix * (particleMatrix * mvPosition);
gl_Position = projectionMatrix * mvPosition;
#include <logdepthbuf_vertex>
#include <clipping_planes_vertex>
vViewPosition = - mvPosition.xyz;
#include <worldpos_vertex>
#include <shadowmap_vertex>
#include <fog_vertex>
#ifdef USE_TRANSMISSION
vWorldPosition = worldPosition.xyz;
#endif
}
`;
var stretched_bb_particle_vert = `
#include <common>
#include <color_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
#include <tile_pars_vertex>
#include <soft_pars_vertex>
attribute vec3 offset;
attribute float rotation;
attribute vec3 size;
attribute vec4 velocity;
uniform float speedFactor;
void main() {
float lengthFactor = velocity.w;
float avgSize = (size.x + size.y) * 0.5;
#ifdef USE_SKEW
vec4 mvPosition = modelViewMatrix * vec4( offset, 1.0 );
vec3 viewVelocity = normalMatrix * velocity.xyz;
vec3 scaledPos = vec3(position.xy * size.xy, position.z);
float vlength = length(viewVelocity);
vec3 projVelocity = dot(scaledPos, viewVelocity) * viewVelocity / vlength;
mvPosition.xyz += scaledPos + projVelocity * (speedFactor / avgSize + lengthFactor / vlength);
#else
vec4 mvPosition = modelViewMatrix * vec4( offset, 1.0 );
vec3 viewVelocity = normalMatrix * velocity.xyz;
float vlength = length(viewVelocity);
mvPosition.xyz += position.y * normalize(cross(mvPosition.xyz, viewVelocity)) * avgSize; // switch the cross to match unity implementation
mvPosition.xyz -= (position.x + 0.5) * viewVelocity * (1.0 + lengthFactor / vlength) * avgSize; // minus position.x to match unity implementation
#endif
vColor = color;
gl_Position = projectionMatrix * mvPosition;
#include <logdepthbuf_vertex>
#include <clipping_planes_vertex>
#include <tile_vertex>
#include <soft_vertex>
}
`;
function getMaterialUVChannelName(value) {
if (value === 0)
return 'uv';
return `uv${value}`;
}
class ParticleMeshStandardMaterial extends three.MeshStandardMaterial {
constructor(parameters) {
super(parameters);
}
onBeforeCompile(parameters, renderer) {
super.onBeforeCompile(parameters, renderer);
parameters.vertexShader = local_particle_physics_vert;
parameters.fragmentShader = particle_physics_frag;
}
}
class ParticleMeshPhysicsMaterial extends three.MeshPhysicalMaterial {
constructor(parameters) {
super(parameters);
}
onBeforeCompile(parameters, renderer) {
super.onBeforeCompile(parameters, renderer);
parameters.vertexShader = local_particle_physics_vert;
parameters.fragmentShader = particle_physics_frag;
}
}
class SpriteBatch extends VFXBatch {
constructor(settings) {
super(settings);
this.vector_ = new quarks_core.Vector3();
this.vector2_ = new quarks_core.Vector3();
this.vector3_ = new quarks_core.Vector3();
this.quaternion_ = new quarks_core.Quaternion();
this.quaternion2_ = new quarks_core.Quaternion();
this.quaternion3_ = new quarks_core.Quaternion();
this.rotationMat_ = new quarks_core.Matrix3();
this.rotationMat2_ = new quarks_core.Matrix3();
this.maxParticles = 1000;
this.setupBuffers();
this.rebuildMaterial();
}
buildExpandableBuffers() {
this.offsetBuffer = new three.InstancedBufferAttribute(new Float32Array(this.maxParticles * 3), 3);
this.offsetBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('offset', this.offsetBuffer);
this.colorBuffer = new three.InstancedBufferAttribute(new Float32Array(this.maxParticles * 4), 4);
this.colorBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('color', this.colorBuffer);
if (this.settings.renderMode === exports.RenderMode.Mesh) {
this.rotationBuffer = new three.InstancedBufferAttribute(new Float32Array(this.maxParticles * 4), 4);
this.rotationBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('rotation', this.rotationBuffer);
}
else if (this.settings.renderMode === exports.RenderMode.BillBoard ||
this.settings.renderMode === exports.RenderMode.HorizontalBillBoard ||
this.settings.renderMode === exports.RenderMode.VerticalBillBoard ||
this.settings.renderMode === exports.RenderMode.StretchedBillBoard) {
this.rotationBuffer = new three.InstancedBufferAttribute(new Float32Array(this.maxParticles), 1);
this.rotationBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('rotation', this.rotationBuffer);
}
this.sizeBuffer = new three.InstancedBufferAttribute(new Float32Array(this.maxParticles * 3), 3);
this.sizeBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('size', this.sizeBuffer);
this.uvTileBuffer = new three.InstancedBufferAttribute(new Float32Array(this.maxParticles), 1);
this.uvTileBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('uvTile', this.uvTileBuffer);
if (this.settings.renderMode === exports.RenderMode.StretchedBillBoard) {
this.velocityBuffer = new three.InstancedBufferAttribute(new Float32Array(this.maxParticles * 4), 4);
this.velocityBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('velocity', this.velocityBuffer);
}
}
setupBuffers() {
if (this.geometry)
this.geometry.dispose();
this.geometry = new three.InstancedBufferGeometry();
this.geometry.setIndex(this.settings.instancingGeometry.getIndex());
if (this.settings.instancingGeometry.hasAttribute('normal')) {
this.geometry.setAttribute('normal', this.settings.instancingGeometry.getAttribute('normal'));
}
this.geometry.setAttribute('position', this.settings.instancingGeometry.getAttribute('position'));
this.geometry.setAttribute('uv', this.settings.instancingGeometry.getAttribute('uv'));
this.buildExpandableBuffers();
}
expandBuffers(target) {
while (target >= this.maxParticles) {
this.maxParticles *= 2;
}
this.setupBuffers();
}
rebuildMaterial() {
this.layers.mask = this.settings.layers.mask;
const uniforms = {};
const defines = {};
if (this.settings.material.type !== 'MeshStandardMaterial' &&
this.settings.material.type !== 'MeshPhysicalMaterial') {
uniforms['map'] = new three.Uniform(this.settings.material.map);
}
if (this.settings.material.alphaTest) {
defines['USE_ALPHATEST'] = '';
uniforms['alphaTest'] = new three.Uniform(this.settings.material.alphaTest);
}
defines['USE_UV'] = '';
const uTileCount = this.settings.uTileCount;
const vTileCount = this.settings.vTileCount;
if (uTileCount > 1 || vTileCount > 1) {
defines['UV_TILE'] = '';
uniforms['tileCount'] = new three.Uniform(new quarks_core.Vector2(uTileCount, vTileCount));
}
if (this.settings.material.defines &&
this.settings.material.defines['USE_COLOR_AS_ALPHA'] !== undefined) {
defines['USE_COLOR_AS_ALPHA'] = '';
}
if (this.settings.material.normalMap) {
defines['USE_NORMALMAP'] = '';
defines['NORMALMAP_UV'] = getMaterialUVChannelName(this.settings.material.normalMap.channel);
uniforms['normalMapTransform'] = new three.Uniform(new quarks_core.Matrix3().copy(this.settings.material.normalMap.matrix));
}
if (this.settings.material.map) {
defines['USE_MAP'] = '';
if (this.settings.blendTiles)
defines['TILE_BLEND'] = '';
defines['MAP_UV'] = getMaterialUVChannelName(this.settings.material.map.channel);
uniforms['mapTransform'] = new three.Uniform(new quarks_core.Matrix3().copy(this.settings.material.map.matrix));
}
defines['USE_COLOR_ALPHA'] = '';
let onBeforeRender;
if (this.settings.softParticles) {
defines['SOFT_PARTICLES'] = '';
const nearFade = this.settings.softNearFade;
const invFadeDistance = 1.0 / (this.settings.softFarFade - this.settings.softNearFade);
uniforms['softParams'] = new three.Uniform(new quarks_core.Vector2(nearFade, invFadeDistance));
uniforms['depthTexture'] = new three.Uniform(null);
const projParams = (uniforms['projParams'] = new three.Uniform(new quarks_core.Vector4()));
onBeforeRender = (_renderer, _scene, camera) => {
projParams.value.set(camera.near, camera.far, 0, 0);
};
}
let needLights = false;
if (this.settings.renderMode === exports.RenderMode.BillBoard ||
this.settings.renderMode === exports.RenderMode.VerticalBillBoard ||
this.settings.renderMode === exports.RenderMode.HorizontalBillBoard ||
this.settings.renderMode === exports.RenderMode.Mesh) {
let vertexShader;
let fragmentShader;
if (this.settings.renderMode === exports.RenderMode.Mesh) {
if (this.settings.material.type === 'MeshStandardMaterial' ||
this.settings.material.type === 'MeshPhysicalMaterial') {
defines['USE_COLOR'] = '';
vertexShader = local_particle_physics_vert;
fragmentShader = particle_physics_frag;
needLights = true;
}
else {
vertexShader = local_particle_vert;
fragmentShader = particle_frag;
}
}
else {
vertexShader = particle_vert;
fragmentShader = particle_frag;
}
if (this.settings.renderMode === exports.RenderMode.VerticalBillBoard) {
defines['VERTICAL'] = '';
}
else if (this.settings.renderMode === exports.RenderMode.HorizontalBillBoard) {
defines['HORIZONTAL'] = '';
}
let specialMats = false;
if (this.settings.renderMode === exports.RenderMode.Mesh) {
if (this.settings.material.type === 'MeshStandardMaterial') {
this.material = new ParticleMeshStandardMaterial({});
this.material.copy(this.settings.material);
this.material.uniforms = uniforms;
this.material.defines = defines;
specialMats = true;
}
else if (this.settings.material.type === 'MeshPhysicalMaterial') {
this.material = new ParticleMeshPhysicsMaterial({});
this.material.copy(this.settings.material);
this.material.uniforms = uniforms;
this.material.defines = defines;
specialMats = true;
}
}
if (!specialMats) {
this.material = new three.ShaderMaterial({
uniforms: uniforms,
defines: defines,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
transparent: this.settings.material.transparent,
depthWrite: !this.settings.material.transparent,
blending: this.settings.material.blending,
blendDst: this.settings.material.blendDst,
blendSrc: this.settings.material.blendSrc,
blendEquation: this.settings.material.blendEquation,
premultipliedAlpha: this.settings.material.premultipliedAlpha,
side: this.settings.material.side,
alphaTest: this.settings.material.alphaTest,
depthTest: this.settings.material.depthTest,
lights: needLights,
});
}
}
else if (this.settings.renderMode === exports.RenderMode.StretchedBillBoard) {
uniforms['speedFactor'] = new three.Uniform(1.0);
this.material = new three.ShaderMaterial({
uniforms: uniforms,
defines: defines,
vertexShader: stretched_bb_particle_vert,
fragmentShader: particle_frag,
transparent: this.settings.material.transparent,
depthWrite: !this.settings.material.transparent,
blending: this.settings.material.blending,
blendDst: this.settings.material.blendDst,
blendSrc: this.settings.material.blendSrc,
blendEquation: this.settings.material.blendEquation,
premultipliedAlpha: this.settings.material.premultipliedAlpha,
side: this.settings.material.side,
alphaTest: this.settings.material.alphaTest,
depthTest: this.settings.material.depthTest,
});
}
else {
throw new Error('render mode unavailable');
}
if (this.material && onBeforeRender) {
this.material.onBeforeRender = onBeforeRender;
}
}
update() {
let index = 0;
let particleCount = 0;
this.systems.forEach((system) => {
particleCount += system.particleNum;
});
if (particleCount > this.maxParticles) {
this.expandBuffers(particleCount);
}
this.systems.forEach((system) => {
if (system.emitter.updateMatrixWorld) {
system.emitter.updateWorldMatrix(true, false);
system.emitter.updateMatrixWorld(true);
}
const particles = system.particles;
const particleNum = system.particleNum;
const rotation = this.quaternion2_;
const translation = this.vector2_;
const scale = this.vector3_;
system.emitter.matrixWorld.decompose(translation, rotation, scale);
this.rotationMat_.setFromMatrix4(system.emitter.matrixWorld);
for (let j = 0; j < particleNum; j++, index++) {
const particle = particles[j];
if (this.settings.renderMode === exports.RenderMode.Mesh) {
let q;
if (system.worldSpace) {
q = particle.rotation;
}
else {
let parentQ;
if (particle.parentMatrix) {
parentQ = this.quaternion3_.setFromRotationMatrix(particle.parentMatrix);
}
else {
parentQ = rotation;
}
q = this.quaternion_;
q.copy(parentQ).multiply(particle.rotation);
}
this.rotationBuffer.setXYZW(index, q.x, q.y, q.z, q.w);
}
else if (this.settings.renderMode === exports.RenderMode.StretchedBillBoard ||
this.settings.renderMode === exports.RenderMode.VerticalBillBoard ||
this.settings.renderMode === exports.RenderMode.HorizontalBillBoard ||
this.settings.renderMode === exports.RenderMode.BillBoard) {
this.rotationBuffer.setX(index, particle.rotation);
}
let vec;
if (system.worldSpace) {
vec = particle.position;
}
else {
vec = this.vector_;
if (particle.parentMatrix) {
vec.copy(particle.position).applyMatrix4(particle.parentMatrix);
}
else {
vec.copy(particle.position).applyMatrix4(system.emitter.matrixWorld);
}
}
this.offsetBuffer.setXYZ(index, vec.x, vec.y, vec.z);
this.colorBuffer.setXYZW(index, particle.color.x, particle.color.y, particle.color.z, particle.color.w);
if (system.worldSpace) {
this.sizeBuffer.setXYZ(index, particle.size.x, particle.size.y, particle.size.z);
}
else {
if (particle.parentMatrix) {
this.sizeBuffer.setXYZ(index, particle.size.x, particle.size.y, particle.size.z);
}
else {
this.sizeBuffer.setXYZ(index, particle.size.x * Math.abs(scale.x), particle.size.y * Math.abs(scale.y), particle.size.z * Math.abs(scale.z));
}
}
this.uvTileBuffer.setX(index, particle.uvTile);
if (this.settings.renderMode === exports.RenderMode.StretchedBillBoard && this.velocityBuffer) {
let speedFactor = system.rendererEmitterSettings.speedFactor;
if (speedFactor === 0)
speedFactor = 0.001;
const lengthFactor = system.rendererEmitterSettings.lengthFactor;
let vec;
if (system.worldSpace) {
vec = particle.velocity;
}
else {
vec = this.vector_;
if (particle.parentMatrix) {
this.rotationMat2_.setFromMatrix4(particle.parentMatrix);
vec.copy(particle.velocity).applyMatrix3(this.rotationMat2_);
}
else {
vec.copy(particle.velocity).applyMatrix3(this.rotationMat_);
}
}
this.velocityBuffer.setXYZW(index, vec.x * speedFactor, vec.y * speedFactor, vec.z * speedFactor, lengthFactor);
}
}
});
this.geometry.instanceCount = index;
if (index > 0) {
this.offsetBuffer.clearUpdateRanges();
this.offsetBuffer.addUpdateRange(0, index * 3);
this.offsetBuffer.needsUpdate = true;
this.sizeBuffer.clearUpdateRanges();
this.sizeBuffer.addUpdateRange(0, index * 3);
this.sizeBuffer.needsUpdate = true;
this.colorBuffer.clearUpdateRanges();
this.colorBuffer.addUpdateRange(0, index * 4);
this.colorBuffer.needsUpdate = true;
this.uvTileBuffer.clearUpdateRanges();
this.uvTileBuffer.addUpdateRange(0, index);
this.uvTileBuffer.needsUpdate = true;
if (this.settings.renderMode === exports.RenderMode.StretchedBillBoard && this.velocityBuffer) {
this.velocityBuffer.clearUpdateRanges();
this.velocityBuffer.addUpdateRange(0, index * 4);
this.velocityBuffer.needsUpdate = true;
}
if (this.settings.renderMode === exports.RenderMode.Mesh) {
this.rotationBuffer.clearUpdateRanges();
this.rotationBuffer.addUpdateRange(0, index * 4);
this.rotationBuffer.needsUpdate = true;
}
else if (this.settings.renderMode === exports.RenderMode.StretchedBillBoard ||
this.settings.renderMode === exports.RenderMode.HorizontalBillBoard ||
this.settings.renderMode === exports.RenderMode.VerticalBillBoard ||
this.settings.renderMode === exports.RenderMode.BillBoard) {
this.rotationBuffer.clearUpdateRanges();
this.rotationBuffer.addUpdateRange(0, index);
this.rotationBuffer.needsUpdate = true;
}
}
}
dispose() {
this.geometry.dispose();
}
}
var trail_frag = `
#include <common>
#include <tile_pars_fragment>
#include <map_pars_fragment>
#include <fog_pars_fragment>
#include <logdepthbuf_pars_fragment>
#include <clipping_planes_pars_fragment>
uniform sampler2D alphaMap;
uniform float useAlphaMap;
uniform float visibility;
uniform float alphaTest;
varying vec4 vColor;
void main() {
#include <clipping_planes_fragment>
#include <logdepthbuf_fragment>
vec4 diffuseColor = vColor;
#ifdef USE_MAP
#include <tile_fragment>
#ifndef USE_COLOR_AS_ALPHA
#endif
#endif
if( useAlphaMap == 1. ) diffuseColor.a *= texture2D( alphaMap, vUv).a;
if( diffuseColor.a < alphaTest ) discard;
gl_FragColor = diffuseColor;
#include <fog_fragment>
#include <tonemapping_fragment>
}`;
var trail_vert = `
#include <common>
#include <tile_pars_vertex>
#include <color_pars_vertex>
#include <clipping_planes_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <fog_pars_vertex>
attribute vec3 previous;
attribute vec3 next;
attribute float side;
attribute float width;
uniform vec2 resolution;
uniform float lineWidth;
uniform float sizeAttenuation;
vec2 fix(vec4 i, float aspect) {
vec2 res = i.xy / i.w;
res.x *= aspect;
return res;
}
void main() {
#include <tile_vertex>
float aspect = resolution.x / resolution.y;
vColor = color;
mat4 m = projectionMatrix * modelViewMatrix;
vec4 finalPosition = m * vec4( position, 1.0 );
vec4 prevPos = m * vec4( previous, 1.0 );
vec4 nextPos = m * vec4( next, 1.0 );
vec2 currentP = fix( finalPosition, aspect );
vec2 prevP = fix( prevPos, aspect );
vec2 nextP = fix( nextPos, aspect );
float w = lineWidth * width;
vec2 dir;
if( nextP == currentP ) dir = normalize( currentP - prevP );
else if( prevP == currentP ) dir = normalize( nextP - currentP );
else {
vec2 dir1 = normalize( currentP - prevP );
vec2 dir2 = normalize( nextP - currentP );
dir = normalize( dir1 + dir2 );
vec2 perp = vec2( -dir1.y, dir1.x );
vec2 miter = vec2( -dir.y, dir.x );
//w = clamp( w / dot( miter, perp ), 0., 4., * lineWidth * width );
}
//vec2 normal = ( cross( vec3( dir, 0. ) vec3( 0., 0., 1. ) ) ).xy;
vec4 normal = vec4( -dir.y, dir.x, 0., 1. );
normal.xy *= .5 * w;
normal *= projectionMatrix;
if( sizeAttenuation == 0. ) {
normal.xy *= finalPosition.w;
normal.xy /= ( vec4( resolution, 0., 1. ) * projectionMatrix ).xy;
}
finalPosition.xy += normal.xy * side;
gl_Position = finalPosition;
#include <logdepthbuf_vertex>
#include <clipping_planes_vertex>
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
#include <fog_vertex>
}`;
class TrailBatch extends VFXBatch {
constructor(settings) {
super(settings);
this.vector_ = new quarks_core.Vector3();
this.vector2_ = new quarks_core.Vector3();
this.vector3_ = new quarks_core.Vector3();
this.quaternion_ = new quarks_core.Quaternion();
this.maxParticles = 10000;
this.setupBuffers();
this.rebuildMaterial();
}
setupBuffers() {
if (this.geometry)
this.geometry.dispose();
this.geometry = new three.BufferGeometry();
this.indexBuffer = new three.BufferAttribute(new Uint32Array(this.maxParticles * 6), 1);
this.indexBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setIndex(this.indexBuffer);
this.positionBuffer = new three.BufferAttribute(new Float32Array(this.maxParticles * 6), 3);
this.positionBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('position', this.positionBuffer);
this.previousBuffer = new three.BufferAttribute(new Float32Array(this.maxParticles * 6), 3);
this.previousBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('previous', this.previousBuffer);
this.nextBuffer = new three.BufferAttribute(new Float32Array(this.maxParticles * 6), 3);
this.nextBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('next', this.nextBuffer);
this.widthBuffer = new three.BufferAttribute(new Float32Array(this.maxParticles * 2), 1);
this.widthBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('width', this.widthBuffer);
this.sideBuffer = new three.BufferAttribute(new Float32Array(this.maxParticles * 2), 1);
this.sideBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('side', this.sideBuffer);
this.uvBuffer = new three.BufferAttribute(new Float32Array(this.maxParticles * 4), 2);
this.uvBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('uv', this.uvBuffer);
this.colorBuffer = new three.BufferAttribute(new Float32Array(this.maxParticles * 8), 4);
this.colorBuffer.setUsage(three.DynamicDrawUsage);
this.geometry.setAttribute('color', this.colorBuffer);
}
expandBuffers(target) {
while (target >= this.maxParticles) {
this.maxParticles *= 2;
}
this.setupBuffers();
}
rebuildMaterial() {
this.layers.mask = this.settings.layers.mask;
const uniforms = {
lineWidth: { value: 1 },
map: { value: null },
useMap: { value: 0 },
alphaMap: { value: null },
useAlphaMap: { value: 0 },
resolution: { value: new quarks_core.Vector2(1, 1) },
sizeAttenuation: { value: 1 },
visibility: { value: 1 },
alphaTest: { value: 0 },
};
const defines = {};
defines['USE_UV'] = '';
defines['USE_COLOR_ALPHA'] = '';
if (this.settings.material.map) {
defines['USE_MAP'] = '';
defines['MAP_UV'] = getMaterialUVChannelName(this.settings.material.map.channel);
uniforms['map'] = new three.Uniform(this.settings.material.map);
uniforms['mapTransform'] = new three.Uniform(new quarks_core.Matrix3().copy(this.settings.material.map.matrix));
}
if (this.settings.material.defines &&
this.settings.material.defines['USE_COLOR_AS_ALPHA'] !== undefined) {
defines['USE_COLOR_AS_ALPHA'] = '';
}
if (this.settings.renderMode === exports.RenderMode.Trail) {
this.material = new three.ShaderMaterial({
uniforms: uniforms,
defines: defines,
vertexShader: trail_vert,
fragmentShader: trail_frag,
transparent: this.settings.material.transparent,
depthWrite: !this.settings.material.transparent,
side: this.settings.material.side,
blending: this.settings.material.blending || three.AdditiveBlending,
blendDst: this.settings.material.blendDst,
blendSrc: this.settings.material.blendSrc,
blendEquation: this.settings.material.blendEquation,
premultipliedAlpha: this.settings.material.premultipliedAlpha,
});
}
else {
throw new Error('render mode unavailable');
}
}
update() {
let index = 0;
let triangles = 0;
let particleCount = 0;
this.systems.forEach((system) => {
for (let j = 0; j < system.particleNum; j++) {
particleCount += system.particles[j].previous.length * 2;
}
});
if (particleCount > this.maxParticles) {
this.expandBuffers(particleCount);
}
this.systems.forEach((system) => {
if (system.emitter.updateMatrixWorld) {
system.emitter.updateWorldMatrix(true, false);
system.emitter.updateMatrixWorld(true);
}
const rotation = this.quaternion_;
const translation = this.vector2_;
const scale = this.vector3_;
system.emitter.matrixWorld.decompose(translation, rotation, scale);
const particles = system.particles;
const particleNum = system.particleNum;
const uTileCount = this.settings.uTileCount;
const vTileCount = this.settings.vTileCount;
const tileWidth = 1 / uTileCount;
const tileHeight = 1 / vTileCount;
for (let j = 0; j < particleNum; j++) {
const particle = particles[j];
const col = particle.uvTile % vTileCount;
const row = Math.floor(particle.uvTile / vTileCount + 0.001);
const iter = particle.previous.values();
let curIter = iter.next();
let previous = curIter.value;
let current = previous;
if (!curIter.done)
curIter = iter.next();
let next;
if (curIter.value !== undefined) {
next = curIter.value;
}
else {
next = current;
}
for (let i = 0; i < particle.previous.length; i++, index += 2) {
this.positionBuffer.setXYZ(index, current.position.x, current.position.y, current.position.z);
this.positionBuffer.setXYZ(index + 1, current.position.x, current.position.y, current.position.z);
if (system.worldSpace) {
this.positionBuffer.setXYZ(index, current.position.x, current.position.y, current.position.z);
this.positionBuffer.setXYZ(index + 1, current.position.x, current.position.y, current.position.z);
}
else {
if (particle.parentMatrix) {
this.vector_.copy(current.position).applyMatrix4(particle.parentMatrix);
}
else {
this.vector_.copy(current.position).applyMatrix4(system.emitter.matrixWorld);
}
this.positionBuffer.setXYZ(index, this.vector_.x, this.vector_.y, this.vector_.z);
this.positionBuffer.setXYZ(index + 1, this.vector_.x, this.vector_.y, this.vector_.z);
}
if (system.worldSpace) {
this.previousBuffer.setXYZ(index, previous.position.x, previous.position.y, previous.position.z);
this.previousBuffer.setXYZ(index + 1, previous.position.x, previous.position.y, previous.position.z);
}
else {
if (particle.parentMatrix) {
this.vector_.copy(previous.position).applyMatrix4(particle.parentMatrix);
}
else {
this.vector_.copy(previous.position).applyMatrix4(system.emitter.matrixWorld);
}
this.previousBuffer.setXYZ(index, this.vector_.x, this.vector_.y, this.vector_.z);
this.previousBuffer.setXYZ(index + 1, this.vector_.x, this.vector_.y, this.vector_.z);
}
if (system.worldSpace) {
this.nextBuffer.setXYZ(index, next.position.x, next.position.y, next.position.z);
this.nextBuffer.setXYZ(index + 1, next.position.x, next.position.y, next.position.z);
}
else {
if (particle.parentMatrix) {
this.vector_.copy(next.position).applyMatrix4(particle.parentMatrix);
}
else {
this.vector_.copy(next.position).applyMatrix4(system.emitter.matrixWorld);
}
this.nextBuffer.setXYZ(index, this.vector_.x, this.vector_.y, this.vector_.z);
this.nextBuffer.setXYZ(index + 1, this.vector_.x, this.vector_.y, this.vector_.z);
}
this.sideBuffer.setX(index, -1);
this.sideBuffer.setX(index + 1, 1);
if (system.worldSpace) {
this.widthBuffer.setX(index, current.size);
this.widthBuffer.setX(index + 1, current.size);
}
else {
if (particle.parentMatrix) {
this.widthBuffer.setX(index, current.size);
this.widthBuffer.setX(index + 1, current.size);
}
else {
const objectScale = (Math.abs(scale.x) + Math.abs(scale.y) + Math.abs(scale.z)) / 3;
this.widthBuffer.setX(index, current.size * objectScale);
this.widthBuffer.setX(index + 1, current.size * objectScale);
}
}
this.uvBuffer.setXY(index, (i / particle.previous.length + col) * tileWidth, (vTileCount - row - 1) * tileHeight);
this.uvBuffer.setXY(index + 1, (i / particle.previous.length + col) * tileWidth, (vTileCount - row) * tileHeight);
this.colorBuffer.setXYZW(index, current.color.x, current.color.y, current.color.z, current.color.w);
this.colorBuffer.setXYZW(index + 1, current.color.x, current.color.y, current.color.z, current.color.w);
if (i + 1 < particle.previous.length) {
this.indexBuffer.setX(triangles * 3, index);
this.indexBuffer.setX(triangles * 3 + 1, index + 1);
this.indexBuffer.setX(triangles * 3 + 2, index + 2);
triangles++;
this.indexBuffer.setX(triangles * 3, index + 2);
this.indexBuffer.setX(triangles * 3 + 1, index + 1);
this.indexBuffer.setX(triangles * 3 + 2, index + 3);
triangles++;
}
previous = current;
current = next;
if (!curIter.done) {
curIter = iter.next();
if (curIter.value !== undefined) {
next = curIter.value;
}
}
}
}
});
this.positionBuffer.clearUpdateRanges();
this.positionBuffer.addUpdateRange(0, index * 3);
this.positionBuffer.needsUpdate = true;
this.previousBuffer.clearUpdateRanges();
this.previousBuffer.addUpdateRange(0, index * 3);
this.previousBuffer.needsUpdate = true;
this.nextBuffer.clearUpdateRanges();
this.nextBuffer.addUpdateRange(0, index * 3);
this.nextBuffer.needsUpdate = true;
this.sideBuffer.clearUpdateRanges();
this.sideBuffer.addUpdateRange(0, index);
this.sideBuffer.needsUpdate = true;
this.widthBuffer.clearUpdateRanges();
this.widthBuffer.addUpdateRange(0, index);
this.widthBuffer.needsUpdate = true;
this.uvBuffer.clearUpdateRanges();
this.uvBuffer.addUpdateRange(0, index * 2);
this.uvBuffer.needsUpdate = true;
this.colorBuffer.clearUpdateRanges();
this.colorBuffer.addUpdateRange(0, index * 4);
this.colorBuffer.needsUpdate = true;
this.indexBuffer.clearUpdateRanges();
this.indexBuffer.addUpdateRange(0, triangles * 3);
this.indexBuffer.needsUpdate = true;
this.geometry.setDrawRange(0, triangles * 3);
}
dispose() {
this.geometry.dispose();
}
}
class MeshSurfaceEmitter {
get geometry() {
return this._geometry;
}
set geometry(geometry) {
this._geometry = geometry;
if (geometry === undefined) {
return;
}
if (typeof geometry === 'string') {
return;
}
const tri = new three.Triangle();
this._triangleIndexToArea.length = 0;
let area = 0;
if (!geometry.getIndex()) {
return;
}
const array = geometry.getIndex().array;
const triCount = array.length / 3;
this._triangleIndexToArea.push(0);
for (let i = 0; i < triCount; i++) {
tri.setFromAttributeAndIndices(geometry.getAttribute('position'), array[i * 3], array[i * 3 + 1], array[i * 3 + 2]);
area += tri.getArea();
this._triangleIndexToArea.push(area);
}
geometry.userData.triangleIndexToArea = this._triangleIndexToArea;
}
constructor(geometry) {
this.type = 'mesh_surface';
this._triangleIndexToArea = [];
this._tempA = new three.Vector3();
this._tempB = new three.Vector3();
this._tempC = new three.Vector3();
if (!geometry) {
return;
}
this.geometry = geometry;
}
initialize(p) {
const geometry = this._geometry;
if (!geometry || geometry.getIndex() === null) {
p.position.set(0, 0, 0);
p.velocity.set(0, 0, 1).multiplyScalar(p.startSpeed);
return;
}
const triCount = this._triangleIndexToArea.length - 1;
let left = 0, right = triCount;
const target = Math.random() * this._triangleIndexToArea[triCount];
while (left + 1 < right) {
const mid = Math.floor((left + right) / 2);
if (target < this._triangleIndexToArea[mid]) {
right = mid;
}
else {
left = mid;
}
}
let u1 = Math.random();
let u2 = Math.random();
if (u1 + u2 > 1) {
u1 = 1 - u1;
u2 = 1 - u2;
}
const index1 = geometry.getIndex().array[left * 3];
const index2 = geometry.getIndex().array[left * 3 + 1];
const index3 = geometry.getIndex().array[left * 3 + 2];
const positionBuffer = geometry.getAttribute('position');
this._tempA.fromBufferAttribute(positionBuffer, index1);
this._tempB.fromBufferAttribute(positionBuffer, index2);
this._tempC.fromBufferAttribute(positionBuffer, index3);
this._tempB.sub(this._tempA);
this._tempC.sub(this._tempA);
this._tempA.addScaledVector(this._tempB, u1).addScaledVector(this._tempC, u2);
p.position.copy(this._tempA);
this._tempA.copy(this._tempB).cross(this._tempC).normalize();
p.velocity.copy(this._tempA).normalize().multiplyScalar(p.startSpeed);
}
toJSON() {
return {
type: 'mesh_surface',
mesh: this._geometry ? this._geometry.uuid : '',
};
}
static fromJSON(json, meta) {
return new MeshSurfaceEmitter(meta.geometries[json.geometry]);
}
clone() {
return new MeshSurfaceEmitter(this._geometry);
}
update(system, delta) { }
}
quarks_core.loadPlugin({
id: "three.quarks",
initialize: () => { },
emitterShapes: [{
type: 'mesh_surface',
params: [['geometry', ['geometry']]],
constructor: MeshSurfaceEmitter,
loadJSON: MeshSurfaceEmitter.fromJSON,
}],
behaviors: [],
});
class BatchedRenderer extends three.Object3D {
constructor() {
super();
this.batches = [];
this.systemToBatchIndex = new Map();
this.type = 'BatchedRenderer';
this.depthTexture = null;
}
static equals(a, b) {
return (a.material.side === b.material.side &&
a.material.blending === b.material.blending &&
a.material.blendSrc === b.material.blendSrc &&
a.material.blendDst === b.material.blendDst &&
a.material.blendEquation === b.material.blendEquation &&
a.material.premultipliedAlpha === b.material.premultipliedAlpha &&
a.material.transparent === b.material.transparent &&
a.material.depthTest === b.material.depthTest &&
a.material.type === b.material.type &&
a.material.alphaTest === b.material.alphaTest &&
a.material.map === b.material.map &&
a.renderMode === b.renderMode &&
a.blendTiles === b.blendTiles &&
a.softParticles === b.softParticles &&
a.softFarFade === b.softFarFade &&
a.softNearFade === b.softNearFade &&
a.uTileCount === b.uTileCount &&
a.vTileCount === b.vTileCount &&
a.instancingGeometry === b.instancingGeometry &&
a.renderOrder === b.renderOrder &&
a.layers.mask === b.layers.mask);
}
addSystem(system) {
system._renderer = this;
const settings = system.getRendererSettings();
for (let i = 0; i < this.batches.length; i++) {
if (BatchedRenderer.equals(this.batches[i].settings, settings)) {
this.batches[i].addSystem(system);
this.systemToBatchIndex.set(system, i);
return;
}
}
let batch;
switch (settings.renderMode) {
case exports.RenderMode.Trail:
batch = new TrailBatch(settings);
break;
case exports.RenderMode.Mesh:
case exports.RenderMode.BillBoard:
case exports.RenderMode.VerticalBillBoard:
case exports.RenderMode.HorizontalBillBoard:
case exports.RenderMode.StretchedBillBoard:
batch = new SpriteBatch(settings);
break;
}
if (this.depthTexture) {
batch.applyDepthTexture(this.depthTexture);
}
batch.addSystem(system);
this.batches.push(batch);
this.systemToBatchIndex.set(system, this.batches.length - 1);
this.add(batch);
}
deleteSystem(system) {
const batchIndex = this.systemToBatchIndex.get(system);
if (batchIndex != undefined) {
this.batches[batchIndex].removeSystem(system);
this.systemToBatchIndex.delete(system);
}
}
setDepthTexture(depthTexture) {
this.depthTexture = depthTexture;
for (const batch of this.batches) {
batch.applyDepthTexture(depthTexture);
}
}
updateSystem(system) {
this.deleteSystem(system);
this.addSystem(system);
}
update(delta) {
this.systemToBatchIndex.forEach((value, ps) => {
ps.update(delta);
});
for (let i = 0; i < this.batches.length; i++) {
this.batches[i].update();
}
}
}
const BatchedParticleRenderer = BatchedRenderer;
class QuarksLoader extends three.ObjectLoader {
constructor(manager) {
super(manager);
}
linkReference(object) {
const objectsMap = {};
object.traverse(function (child) {
objectsMap[child.uuid] = child;
});
object.traverse(function (child) {
if (child.type === 'ParticleEmitter') {
const system = child.system;
system.emitterShape;
for (let i = 0; i < system.behaviors.length; i++) {
if (system.behaviors[i] instanceof quarks_core.EmitSubParticleSystem) {
system.behaviors[i].subParticleSystem = objectsMap[system.behaviors[i].subParticleSystem];
}
}
}
});
}
parse(json, onLoad) {
const object = super.parse(json, onLoad);
this.linkReference(object);
return object;
}
parseObject(data, geometries, materials, textures, animations) {
let object;
function getGeometry(name) {
if (geometries[name] === undefined) {
console.warn('THREE.ObjectLoader: Undefined geometry', name);
}
return geometries[name];
}
function getMaterial(name) {
if (name === undefined)
return undefined;
if (Array.isArray(name)) {
const array = [];
for (let i = 0, l = name.length; i < l; i++) {
const uuid = name[i];
if (materials[uuid] === undefined) {
console.warn('THREE.ObjectLoader: Undefined material', uuid);
}
array.push(materials[uuid]);
}
return array;
}
if (materials[name] === undefined) {
console.warn('THREE.ObjectLoader: Undefined material', name);
}
return materials[name];
}
function getTexture(uuid) {
if (textures[uuid] === undefined) {
console.warn('THREE.ObjectLoader: Undefined texture', uuid);
}
return textures[uuid];
}
let geometry, material;
const meta = {
textures: textures,
geometries: geometries,
materials: materials,
};
const dependencies = {};
switch (data.type) {
case 'ParticleEmitter':
object = ParticleSystem.fromJSON(data.ps, meta, dependencies).emitter;
break;
case 'Scene':
object = new three.Scene();
if (data.background !== undefined) {
if (Number.isInteger(data.background)) {
object.background = new three.Color(data.background);
}
else {
object.background = getTexture(data.background);
}
}
if (data.environment !== undefined) {
object.environment = getTexture(data.environment);
}
if (data.fog !== undefined) {
if (data.fog.type === 'Fog') {
object.fog = new three.Fog(data.fog.color, data.fog.near, data.fog.far);
}
else if (data.fog.type === 'FogExp2') {
object.fog = new three.FogExp2(data.fog.color, data.fog.density);
}
if (data.fog.name !== '') {
object.fog.name = data.fog.name;
}
}
if (data.backgroundBlurriness !== undefined)
object.backgroundBlurriness = data.backgroundBlurriness;
if (data.backgroundIntensity !== undefined)
object.backgroundIntensity = data.backgroundIntensity;
if (data.backgroundRotation !== undefined)
object.backgroundRotation.fromArray(data.backgroundRotation);
if (data.environmentIntensity !== undefined)
object.environmentIntensity = data.environmentIntensity;
if (data.environmentRotation !== undefined)
object.environmentRotation.fromArray(data.environmentRotation);
break;
case 'PerspectiveCamera':
object = new three.PerspectiveCamera(data.fov, data.aspect, data.near, data.far);
if (data.focus !== undefined)
object.focus = data.focus;
if (data.zoom !== undefined)
object.zoom = data.zoom;
if (data.filmGauge !== undefined)
object.filmGauge = data.filmGauge;
if (data.filmOffset !== undefined)
object.filmOffset = data.filmOffset;
if (data.view !== undefined)
object.view = Object.assign({}, data.view);
break;
case 'OrthographicCamera':
object = new three.OrthographicCamera(data.left, data.right, data.top, data.bottom, data.near, data.far);
if (data.zoom !== undefined)
object.zoom = data.zoom;
if (data.view !== undefined)
object.view = Object.assign({}, data.view);
break;
case 'AmbientLight':
object = new three.AmbientLight(data.color, data.intensity);
break;
case 'DirectionalLight':
object = new three.DirectionalLight(data.color, data.intensity);
break;
case 'PointLight':
object = new three.PointLight(data.color, data.intensity, data.distance, data.decay);
break;
case 'RectAreaLight':
object = new three.RectAreaLight(data.color, data.intensity, data.width, data.height);
break;
case 'SpotLight':
object = new three.SpotLight(data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay);
break;
case 'HemisphereLight':
object = new three.HemisphereLight(data.color, data.groundColor, data.intensity);
break;
case 'LightProbe':
object = new three.LightProbe().fromJSON(data);
break;
case 'SkinnedMesh':
geometry = getGeometry(data.geometry);
material = getMaterial(data.material);
object = new three.SkinnedMesh(geometry, material);
if (data.bindMode !== undefined)
object.bindMode = data.bindMode;
if (data.bindMatrix !== undefined)
object.bindMatrix.fromArray(data.bindMatrix);
if (data.skeleton !== undefined)
object.skeleton = data.skeleton;
break;
case 'Mesh':
geometry = getGeometry(data.geometry);
material = getMaterial(data.material);
object = new three.Mesh(geometry, material);
break;
case 'InstancedMesh': {
geometry = getGeometry(data.geometry);
material = getMaterial(data.material);
const count = data.count;
const instanceMatrix = data.instanceMatrix;
const instanceColor = data.instanceColor;
object = new three.InstancedMesh(geometry, material, count);
object.instanceMatrix = new three.InstancedBufferAttribute(new Float32Array(instanceMatrix.array), 16);
if (instanceColor !== undefined)
object.instanceColor = new three.InstancedBufferAttribute(new Float32Array(instanceColor.array), instanceColor.itemSize);
break;
}
case 'BatchedMesh':
geometry = getGeometry(data.geometry);
material = getMaterial(data.material);
object = new three.BatchedMesh(data.maxGeometryCount, data.maxVertexCount, data.maxIndexCount, material);
object.geometry = geometry;
object.perObjectFrustumCulled = data.perObjectFrustumCulled;
object.sortObjects = data.sortObjects;
object._drawRanges = data.drawRanges;
object._reservedRanges = data.reservedRanges;
object._visibility = data.visibility;
object._active = data.active;
object._bounds = data.bounds.map((bound) => {
const box = new three.Box3();
box.min.fromArray(bound.boxMin);
box.max.fromArray(bound.boxMax);
const sphere = new three.Sphere();
sphere.radius = bound.sphereRadius;
sphere.center.fromArray(bound.sphereCenter);
return {
boxInitialized: bound.boxInitialized,
box: box,
sphereInitialized: bound.sphereInitialized,
sphere: sphere,
};
});
object._maxGeometryCount = data.maxGeometryCount;
object._maxVertexCount = data.maxVertexCount;
object._maxIndexCount = data.maxIndexCount;
object._geometryInitialized = data.geometryInitialized;
object._geometryCount = data.geometryCount;
object._matricesTexture = getTexture(data.matricesTexture.uuid);
break;
case 'LOD':
object = new three.LOD();
break;
case 'Line':
object = new three.Line(getGeometry(data.geometry), getMaterial(data.material));
break;
case 'LineLoop':
object = new three.LineLoop(getGeometry(data.geometry), getMaterial(data.material));
break;
case 'LineSegments':
object = new three.LineSegments(getGeometry(data.geometry), getMaterial(data.material));
break;
case 'PointCloud':
case 'Points':
object = new three.Points(getGeometry(data.geometry), getMaterial(data.material));
break;
case 'Sprite':
object = new three.Sprite(getMaterial(data.material));
break;
case 'Group':
object = new three.Group();
break;
case 'Bone':
object = new three.Bone();
break;
default:
object = new three.Object3D();
}
object.uuid = data.uuid;
if (data.name !== undefined)
object.name = data.name;
if (data.matrix !== undefined) {
object.matrix.fromArray(data.matrix);
if (data.matrixAutoUpdate !== undefined)
object.matrixAutoUpdate = data.matrixAutoUpdate;
if (object.matrixAutoUpdate) {
object.matrix.decompose(object.position, object.quaternion, object.scale);
if (isNaN(object.quaternion.x)) {
object.quaternion.set(0, 0, 0, 1);
}
}
}
else {
if (data.position !== undefined)
object.position.fromArray(data.position);
if (data.rotation !== undefined)
object.rotation.fromArray(data.rotation);
if (data.quaternion !== undefined)
object.quaternion.fromArray(data.quaternion);
if (data.scale !== undefined)
object.scale.fromArray(data.scale);
}
if (data.up !== undefined)
object.up.fromArray(data.up);
if (data.castShadow !== undefined)
object.castShadow = data.castShadow;
if (data.receiveShadow !== undefined)
object.receiveShadow = data.receiveShadow;
if (data.shadow) {
if (data.shadow.bias !== undefined)
object.shadow.bias = data.shadow.bias;
if (data.shadow.normalBias !== undefined)
object.normalBias = data.shadow.normalBias;
if (data.shadow.radius !== undefined)
object.radius = data.shadow.radius;
if (data.shadow.mapSize !== undefined)
object.mapSize.fromArray(data.shadow.mapSize);
if (data.shadow.camera !== undefined) {
object.camera = this.parseObject(data.shadow.camera);
}
}
if (data.visible !== undefined)
object.visible = data.visible;
if (data.frustumCulled !== undefined)
object.frustumCulled = data.frustumCulled;
if (data.renderOrder !== undefined)
object.renderOrder = data.renderOrder;
if (data.userData !== undefined)
object.userData = data.userData;
if (data.layers !== undefined)
object.layers.mask = data.layers;
if (data.children !== undefined) {
const children = data.children;
for (let i = 0; i < children.length; i++) {
object.add(this.parseObject(children[i], geometries, materials, textures, animations));
}
}
if (data.animations !== undefined) {
const objectAnimations = data.animations;
for (let i = 0; i < objectAnimations.length; i++) {
const uuid = objectAnimations[i];
object.animations.push(animations[uuid]);
}
}
if (data.type === 'LOD') {
if (data.autoUpdate !== undefined)
object.autoUpdate = data.autoUpdate;
const levels = data.levels;
for (let l = 0; l < levels.length; l++) {
const level = levels[l];
const child = object.getObjectByProperty('uuid', level.object);
if (child !== undefined) {
object.addLevel(child, level.distance);
}
}
}
return object;
}
}
class QuarksUtil {
static runOnAllParticleEmitters(obj, func) {
obj.traverse((child) => {
if (child.type === 'ParticleEmitter') {
func(child);
}
});
if (obj.type === 'ParticleEmitter') {
func(obj);
}
}
static addToBatchRenderer(obj, batchRenderer) {
QuarksUtil.runOnAllParticleEmitters(obj, (ps) => {
batchRenderer.addSystem(ps.system);
});
}
static play(obj) {
QuarksUtil.runOnAllParticleEmitters(obj, (ps) => {
ps.system.play();
});
}
static stop(obj) {
QuarksUtil.runOnAllParticleEmitters(obj, (ps) => {
ps.system.stop();
});
}
static setAutoDestroy(obj, value) {
QuarksUtil.runOnAllParticleEmitters(obj, (ps) => {
ps.system.autoDestroy = value;
});
}
static endEmit(obj) {
QuarksUtil.runOnAllParticleEmitters(obj, (ps) => {
ps.system.endEmit();
});
}
static restart(obj) {
QuarksUtil.runOnAllParticleEmitters(obj, (ps) => {
ps.system.restart();
});
}
static pause(obj) {
QuarksUtil.runOnAllParticleEmitters(obj, (ps) => {
ps.system.pause();
});
}
}
registerShaderChunks();
console.log('%c Particle system powered by three.quarks. https://quarks.art/', 'font-size: 14px; font-weight: bold;');
exports.BatchedParticleRenderer = BatchedParticleRenderer;
exports.BatchedRenderer = BatchedRenderer;
exports.MeshSurfaceEmitter = MeshSurfaceEmitter;
exports.ParticleEmitter = ParticleEmitter;
exports.ParticleMeshPhysicsMaterial = ParticleMeshPhysicsMaterial;
exports.ParticleMeshStandardMaterial = ParticleMeshStandardMaterial;
exports.ParticleSystem = ParticleSystem;
exports.QuarksLoader = QuarksLoader;
exports.QuarksUtil = QuarksUtil;
exports.SpriteBatch = SpriteBatch;
exports.TrailBatch = TrailBatch;
exports.VFXBatch = VFXBatch;
exports.registerShaderChunks = registerShaderChunks;
Object.keys(quarks_core).forEach(function (k) {
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
enumerable: true,
get: function () { return quarks_core[k]; }
});
});