Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Ablesons
three.js
提交
f75c936d
T
three.js
项目概览
Ablesons
/
three.js
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
three.js
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
f75c936d
编写于
4月 12, 2017
作者:
M
Mr.doob
提交者:
GitHub
4月 12, 2017
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #11151 from Mugen87/dev
GPUParticleSystem: Refactoring
上级
4910aaec
82934209
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
313 addition
and
321 deletion
+313
-321
examples/js/GPUParticleSystem.js
examples/js/GPUParticleSystem.js
+313
-321
未找到文件。
examples/js/GPUParticleSystem.js
浏览文件 @
f75c936d
...
...
@@ -15,156 +15,115 @@
*
*/
THREE
.
GPUParticleSystem
=
function
(
options
)
{
THREE
.
GPUParticleSystem
=
function
(
options
)
{
var
self
=
this
;
var
options
=
options
||
{};
THREE
.
Object3D
.
apply
(
this
,
arguments
);
options
=
options
||
{};
// parse options and use defaults
self
.
PARTICLE_COUNT
=
options
.
maxParticles
||
1000000
;
self
.
PARTICLE_CONTAINERS
=
options
.
containerCount
||
1
;
self
.
PARTICLE_NOISE_TEXTURE
=
options
.
particleNoiseTex
||
null
;
self
.
PARTICLE_SPRITE_TEXTURE
=
options
.
particleSpriteTex
||
null
;
self
.
PARTICLES_PER_CONTAINER
=
Math
.
ceil
(
self
.
PARTICLE_COUNT
/
self
.
PARTICLE_CONTAINERS
);
self
.
PARTICLE_CURSOR
=
0
;
self
.
time
=
0
;
// Custom vertex and fragement shader
var
GPUParticleShader
=
{
vertexShader
:
[
this
.
PARTICLE_COUNT
=
options
.
maxParticles
||
1000000
;
this
.
PARTICLE_CONTAINERS
=
options
.
containerCount
||
1
;
'
precision highp float;
'
,
'
const vec4 bitSh = vec4(256. * 256. * 256., 256. * 256., 256., 1.);
'
,
'
const vec4 bitMsk = vec4(0.,vec3(1./256.0));
'
,
'
const vec4 bitShifts = vec4(1.) / bitSh;
'
,
this
.
PARTICLE_NOISE_TEXTURE
=
options
.
particleNoiseTex
||
null
;
this
.
PARTICLE_SPRITE_TEXTURE
=
options
.
particleSpriteTex
||
null
;
'
#define FLOAT_MAX 1.70141184e38
'
,
'
#define FLOAT_MIN 1.17549435e-38
'
,
this
.
PARTICLES_PER_CONTAINER
=
Math
.
ceil
(
this
.
PARTICLE_COUNT
/
this
.
PARTICLE_CONTAINERS
);
this
.
PARTICLE_CURSOR
=
0
;
this
.
time
=
0
;
this
.
particleContainers
=
[];
this
.
rand
=
[];
'
lowp vec4 encode_float(highp float v) {
'
,
'
highp float av = abs(v);
'
,
// custom vertex and fragement shader
'
//Handle special cases
'
,
'
if(av < FLOAT_MIN) {
'
,
'
return vec4(0.0, 0.0, 0.0, 0.0);
'
,
'
} else if(v > FLOAT_MAX) {
'
,
'
return vec4(127.0, 128.0, 0.0, 0.0) / 255.0;
'
,
'
} else if(v < -FLOAT_MAX) {
'
,
'
return vec4(255.0, 128.0, 0.0, 0.0) / 255.0;
'
,
'
}
'
,
var
GPUParticleShader
=
{
'
highp vec4 c = vec4(0,0,0,0);
'
,
vertexShader
:
[
'
//Compute exponent and mantissa
'
,
'
highp float e = floor(log2(av))
;
'
,
'
highp float m = av * pow(2.0, -e) - 1.0
;
'
,
'
uniform float uTime;
'
,
'
uniform float uScale
;
'
,
'
uniform sampler2D tNoise
;
'
,
//Unpack mantissa
'
c[1] = floor(128.0 * m);
'
,
'
m -= c[1] / 128.0;
'
,
'
c[2] = floor(32768.0 * m);
'
,
'
m -= c[2] / 32768.0;
'
,
'
c[3] = floor(8388608.0 * m);
'
,
'
attribute vec3 positionStart;
'
,
'
attribute float startTime;
'
,
'
attribute vec3 velocity;
'
,
'
attribute float turbulence;
'
,
'
attribute vec3 color;
'
,
'
attribute float size;
'
,
'
attribute float lifeTime;
'
,
'
//Unpack exponent
'
,
'
highp float ebias = e + 127.0;
'
,
'
c[0] = floor(ebias / 2.0);
'
,
'
ebias -= c[0] * 2.0;
'
,
'
c[1] += floor(ebias) * 128.0;
'
,
'
varying vec4 vColor;
'
,
'
varying float lifeLeft;
'
,
'
//Unpack sign bit
'
,
'
c[0] += 128.0 * step(0.0, -v);
'
,
'
void main() {
'
,
'
//Scale back to range
'
,
'
return c / 255.0;
'
,
'
}
'
,
// unpack things from our attributes'
'
vec4 pack(const in float depth)
'
,
'
{
'
,
'
const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);
'
,
'
const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
'
,
'
vec4 res = mod(depth*bit_shift*vec4(255), vec4(256))/vec4(255);
'
,
'
res -= res.xxyz * bit_mask;
'
,
'
return res;
'
,
'
}
'
,
'
vColor = vec4( color, 1.0 );
'
,
'
float unpack(const in vec4 rgba_depth)
'
,
'
{
'
,
'
const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);
'
,
'
float depth = dot(rgba_depth, bit_shift);
'
,
'
return depth;
'
,
'
}
'
,
// convert our velocity back into a value we can use'
'
uniform float uTime;
'
,
'
uniform float uScale;
'
,
'
uniform sampler2D tNoise;
'
,
'
vec3 newPosition;
'
,
'
vec3 v;
'
,
'
attribute vec4 particlePositionsStartTime;
'
,
'
attribute vec4 particleVelColSizeLife;
'
,
'
float timeElapsed = uTime - startTime;
'
,
'
varying vec4 vColor;
'
,
'
varying float lifeLeft;
'
,
'
lifeLeft = 1.0 - ( timeElapsed / lifeTime );
'
,
'
void main() {
'
,
'
gl_PointSize = ( uScale * size ) * lifeLeft;
'
,
'
// unpack things from our attributes
'
,
'
vColor = encode_float( particleVelColSizeLife.y );
'
,
'
v.x = ( velocity.x - 0.5 ) * 3.0;
'
,
'
v.y = ( velocity.y - 0.5 ) * 3.0;
'
,
'
v.z = ( velocity.z - 0.5 ) * 3.0;
'
,
'
// convert our velocity back into a value we can use
'
,
'
vec4 velTurb = encode_float( particleVelColSizeLife.x );
'
,
'
vec3 velocity = vec3( velTurb.xyz );
'
,
'
float turbulence = velTurb.w;
'
,
'
newPosition = positionStart + ( v * 10.0 ) * ( uTime - startTime );
'
,
'
vec3 newPosition;
'
,
'
vec3 noise = texture2D( tNoise, vec2( newPosition.x * 0.015 + ( uTime * 0.05 ), newPosition.y * 0.02 + ( uTime * 0.015 ) ) ).rgb;
'
,
'
vec3 noiseVel = ( noise.rgb - 0.5 ) * 30.0;
'
,
'
float timeElapsed = uTime - particlePositionsStartTime.a
;
'
,
'
newPosition = mix( newPosition, newPosition + vec3( noiseVel * ( turbulence * 5.0 ) ), ( timeElapsed / lifeTime ) )
;
'
,
'
lifeLeft = 1. - (timeElapsed / particleVelColSizeLife.w);
'
,
'
if( v.y > 0. && v.y < .05 ) {
'
,
'
gl_PointSize = ( uScale * particleVelColSizeLife.z ) * lifeLeft
;
'
,
'
lifeLeft = 0.0
;
'
,
'
velocity.x = ( velocity.x - .5 ) * 3.;
'
,
'
velocity.y = ( velocity.y - .5 ) * 3.;
'
,
'
velocity.z = ( velocity.z - .5 ) * 3.;
'
,
'
}
'
,
'
newPosition = particlePositionsStartTime.xyz + ( velocity * 10. ) * ( uTime - particlePositionsStartTime.a );
'
,
'
if( v.x < - 1.45 ) {
'
,
'
vec3 noise = texture2D( tNoise, vec2( newPosition.x * .015 + (uTime * .05), newPosition.y * .02 + (uTime * .015) )).rgb;
'
,
'
vec3 noiseVel = ( noise.rgb - .5 ) * 30.;
'
,
'
lifeLeft = 0.0;
'
,
'
newPosition = mix(newPosition, newPosition + vec3(noiseVel * ( turbulence * 5. ) ), (timeElapsed / particleVelColSizeLife.a) );
'
,
'
}
'
,
'
if( velocity.y > 0. && velocity.y < .05 ) {
'
,
'
lifeLeft = 0.;
'
,
'
}
'
,
'
if( timeElapsed > 0.0 ) {
'
,
'
if( velocity.x < -1.45 ) {
'
,
'
lifeLeft = 0.;
'
,
'
}
'
,
'
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
'
,
'
} else {
'
,
'
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
'
,
'
lifeLeft = 0.0;
'
,
'
gl_PointSize = 0.;
'
,
'
}
'
,
'
if( timeElapsed > 0. ) {
'
,
'
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
'
,
'
} else {
'
,
'
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
'
,
'
lifeLeft = 0.;
'
,
'
gl_PointSize = 0.;
'
,
'
}
'
,
'
}
'
].
join
(
"
\n
"
),
].
join
(
'
\n
'
),
fragmentShader
:
[
'
float scaleLinear(float value, vec2 valueDomain) {
'
,
'
return (value - valueDomain.x) / (valueDomain.y - valueDomain.x);
'
,
'
float scaleLinear( float value, vec2 valueDomain ) {
'
,
'
return ( value - valueDomain.x ) / ( valueDomain.y - valueDomain.x );
'
,
'
}
'
,
'
float scaleLinear(float value, vec2 valueDomain, vec2 valueRange) {
'
,
'
return mix(valueRange.x, valueRange.y, scaleLinear(value, valueDomain));
'
,
'
float scaleLinear( float value, vec2 valueDomain, vec2 valueRange ) {
'
,
'
return mix( valueRange.x, valueRange.y, scaleLinear( value, valueDomain ) );
'
,
'
}
'
,
'
varying vec4 vColor;
'
,
...
...
@@ -174,335 +133,368 @@ THREE.GPUParticleSystem = function(options) {
'
void main() {
'
,
'
float alpha = 0.;
'
,
'
float alpha = 0.;
'
,
'
if( lifeLeft > .995 ) {
'
,
'
alpha = scaleLinear( lifeLeft, vec2(1., .995), vec2(0., 1.));//mix( 0., 1., ( lifeLeft - .95 ) * 100. ) * .75;
'
,
'
} else {
'
,
'
alpha = lifeLeft * .75;
'
,
'
}
'
,
'
if( lifeLeft > 0.995 ) {
'
,
'
alpha = scaleLinear( lifeLeft, vec2( 1.0, 0.995 ), vec2( 0.0, 1.0 ) );
'
,
'
vec4 tex = texture2D( tSprite, gl_PointCoord );
'
,
'
} else {
'
,
'
alpha = lifeLeft * 0.75;
'
,
'
}
'
,
'
vec4 tex = texture2D( tSprite, gl_PointCoord );
'
,
'
gl_FragColor = vec4( vColor.rgb * tex.a, alpha * tex.a );
'
,
'
gl_FragColor = vec4( vColor.rgb * tex.a, alpha * tex.a );
'
,
'
}
'
].
join
(
"
\n
"
)
].
join
(
'
\n
'
)
};
// preload a million random numbers
self
.
rand
=
[];
for
(
var
i
=
1
e5
;
i
>
0
;
i
--
)
{
self
.
rand
.
push
(
Math
.
random
()
-
.
5
);
var
i
;
for
(
i
=
1
e5
;
i
>
0
;
i
--
)
{
this
.
rand
.
push
(
Math
.
random
()
-
0.5
);
}
self
.
random
=
function
()
{
return
++
i
>=
self
.
rand
.
length
?
self
.
rand
[
i
=
1
]
:
self
.
rand
[
i
];
this
.
random
=
function
()
{
return
++
i
>=
this
.
rand
.
length
?
this
.
rand
[
i
=
1
]
:
this
.
rand
[
i
];
};
var
textureLoader
=
new
THREE
.
TextureLoader
();
self
.
particleNoiseTex
=
self
.
PARTICLE_NOISE_TEXTURE
||
textureLoader
.
load
(
"
textures/perlin-512.png
"
);
self
.
particleNoiseTex
.
wrapS
=
self
.
particleNoiseTex
.
wrapT
=
THREE
.
RepeatWrapping
;
this
.
particleNoiseTex
=
this
.
PARTICLE_NOISE_TEXTURE
||
textureLoader
.
load
(
'
textures/perlin-512.png
'
);
this
.
particleNoiseTex
.
wrapS
=
this
.
particleNoiseTex
.
wrapT
=
THREE
.
RepeatWrapping
;
self
.
particleSpriteTex
=
self
.
PARTICLE_SPRITE_TEXTURE
||
textureLoader
.
load
(
"
textures/particle2.png
"
);
self
.
particleSpriteTex
.
wrapS
=
self
.
particleSpriteTex
.
wrapT
=
THREE
.
RepeatWrapping
;
this
.
particleSpriteTex
=
this
.
PARTICLE_SPRITE_TEXTURE
||
textureLoader
.
load
(
'
textures/particle2.png
'
);
this
.
particleSpriteTex
.
wrapS
=
this
.
particleSpriteTex
.
wrapT
=
THREE
.
RepeatWrapping
;
self
.
particleShaderMat
=
new
THREE
.
ShaderMaterial
(
{
this
.
particleShaderMat
=
new
THREE
.
ShaderMaterial
(
{
transparent
:
true
,
depthWrite
:
false
,
uniforms
:
{
"
uTime
"
:
{
'
uTime
'
:
{
value
:
0.0
},
"
uScale
"
:
{
'
uScale
'
:
{
value
:
1.0
},
"
tNoise
"
:
{
value
:
self
.
particleNoiseTex
'
tNoise
'
:
{
value
:
this
.
particleNoiseTex
},
"
tSprite
"
:
{
value
:
self
.
particleSpriteTex
'
tSprite
'
:
{
value
:
this
.
particleSpriteTex
}
},
blending
:
THREE
.
AdditiveBlending
,
vertexShader
:
GPUParticleShader
.
vertexShader
,
fragmentShader
:
GPUParticleShader
.
fragmentShader
});
}
);
// define defaults for all values
self
.
particleShaderMat
.
defaultAttributeValues
.
particlePositionsStartTime
=
[
0
,
0
,
0
,
0
];
self
.
particleShaderMat
.
defaultAttributeValues
.
particleVelColSizeLife
=
[
0
,
0
,
0
,
0
];
self
.
particleContainers
=
[];
// extend Object3D
THREE
.
Object3D
.
apply
(
this
,
arguments
);
this
.
particleShaderMat
.
defaultAttributeValues
.
particlePositionsStartTime
=
[
0
,
0
,
0
,
0
];
this
.
particleShaderMat
.
defaultAttributeValues
.
particleVelColSizeLife
=
[
0
,
0
,
0
,
0
];
this
.
init
=
function
()
{
for
(
var
i
=
0
;
i
<
self
.
PARTICLE_CONTAINERS
;
i
++
)
{
for
(
var
i
=
0
;
i
<
this
.
PARTICLE_CONTAINERS
;
i
++
)
{
var
c
=
new
THREE
.
GPUParticleContainer
(
self
.
PARTICLES_PER_CONTAINER
,
self
);
self
.
particleContainers
.
push
(
c
);
self
.
add
(
c
);
var
c
=
new
THREE
.
GPUParticleContainer
(
this
.
PARTICLES_PER_CONTAINER
,
this
);
this
.
particleContainers
.
push
(
c
);
this
.
add
(
c
);
}
};
this
.
spawnParticle
=
function
(
options
)
{
this
.
spawnParticle
=
function
(
options
)
{
this
.
PARTICLE_CURSOR
++
;
if
(
this
.
PARTICLE_CURSOR
>=
this
.
PARTICLE_COUNT
)
{
this
.
PARTICLE_CURSOR
=
1
;
self
.
PARTICLE_CURSOR
++
;
if
(
self
.
PARTICLE_CURSOR
>=
self
.
PARTICLE_COUNT
)
{
self
.
PARTICLE_CURSOR
=
1
;
}
var
currentContainer
=
self
.
particleContainers
[
Math
.
floor
(
self
.
PARTICLE_CURSOR
/
self
.
PARTICLES_PER_CONTAINER
)
];
var
currentContainer
=
this
.
particleContainers
[
Math
.
floor
(
this
.
PARTICLE_CURSOR
/
this
.
PARTICLES_PER_CONTAINER
)
];
currentContainer
.
spawnParticle
(
options
);
currentContainer
.
spawnParticle
(
options
);
};
this
.
update
=
function
(
time
)
{
for
(
var
i
=
0
;
i
<
self
.
PARTICLE_CONTAINERS
;
i
++
)
{
this
.
update
=
function
(
time
)
{
for
(
var
i
=
0
;
i
<
this
.
PARTICLE_CONTAINERS
;
i
++
)
{
self
.
particleContainers
[
i
].
update
(
time
);
this
.
particleContainers
[
i
].
update
(
time
);
}
};
this
.
dispose
=
function
()
{
this
.
particleShaderMat
.
dispose
();
this
.
particleNoiseTex
.
dispose
();
this
.
particleSpriteTex
.
dispose
();
for
(
var
i
=
0
;
i
<
this
.
PARTICLE_CONTAINERS
;
i
++
)
{
this
.
particleContainers
[
i
].
dispose
();
}
};
this
.
init
();
};
THREE
.
GPUParticleSystem
.
prototype
=
Object
.
create
(
THREE
.
Object3D
.
prototype
);
THREE
.
GPUParticleSystem
.
prototype
=
Object
.
create
(
THREE
.
Object3D
.
prototype
);
THREE
.
GPUParticleSystem
.
prototype
.
constructor
=
THREE
.
GPUParticleSystem
;
// Subclass for particle containers, allows for very large arrays to be spread out
THREE
.
GPUParticleContainer
=
function
(
maxParticles
,
particleSystem
)
{
var
self
=
this
;
self
.
PARTICLE_COUNT
=
maxParticles
||
100000
;
self
.
PARTICLE_CURSOR
=
0
;
self
.
time
=
0
;
self
.
DPR
=
window
.
devicePixelRatio
;
self
.
GPUParticleSystem
=
particleSystem
;
var
particlesPerArray
=
Math
.
floor
(
self
.
PARTICLE_COUNT
/
self
.
MAX_ATTRIBUTES
);
// extend Object3D
THREE
.
Object3D
.
apply
(
this
,
arguments
);
// construct a couple small arrays used for packing variables into floats etc
var
UINT8_VIEW
=
new
Uint8Array
(
4
);
var
FLOAT_VIEW
=
new
Float32Array
(
UINT8_VIEW
.
buffer
);
function
decodeFloat
(
x
,
y
,
z
,
w
)
{
UINT8_VIEW
[
0
]
=
Math
.
floor
(
w
);
UINT8_VIEW
[
1
]
=
Math
.
floor
(
z
);
UINT8_VIEW
[
2
]
=
Math
.
floor
(
y
);
UINT8_VIEW
[
3
]
=
Math
.
floor
(
x
);
return
FLOAT_VIEW
[
0
]
}
function
componentToHex
(
c
)
{
var
hex
=
c
.
toString
(
16
);
return
hex
.
length
==
1
?
"
0
"
+
hex
:
hex
;
}
THREE
.
GPUParticleContainer
=
function
(
maxParticles
,
particleSystem
)
{
function
rgbToHex
(
r
,
g
,
b
)
{
return
"
#
"
+
componentToHex
(
r
)
+
componentToHex
(
g
)
+
componentToHex
(
b
);
}
THREE
.
Object3D
.
apply
(
this
,
arguments
);
function
hexToRgb
(
hex
)
{
var
r
=
hex
>>
16
;
var
g
=
(
hex
&
0x00FF00
)
>>
8
;
var
b
=
hex
&
0x0000FF
;
this
.
PARTICLE_COUNT
=
maxParticles
||
100000
;
this
.
PARTICLE_CURSOR
=
0
;
this
.
time
=
0
;
this
.
offset
=
0
;
this
.
count
=
0
;
this
.
DPR
=
window
.
devicePixelRatio
;
this
.
GPUParticleSystem
=
particleSystem
;
this
.
particleUpdate
=
false
;
if
(
r
>
0
)
r
--
;
if
(
g
>
0
)
g
--
;
if
(
b
>
0
)
b
--
;
// geometry
return
[
r
,
g
,
b
];
}
this
.
particleShaderGeo
=
new
THREE
.
BufferGeometry
();
self
.
particles
=
[];
self
.
deadParticles
=
[];
self
.
particlesAvailableSlot
=
[];
this
.
particleShaderGeo
.
addAttribute
(
'
position
'
,
new
THREE
.
BufferAttribute
(
new
Float32Array
(
this
.
PARTICLE_COUNT
*
3
),
3
)
);
this
.
particleShaderGeo
.
addAttribute
(
'
positionStart
'
,
new
THREE
.
BufferAttribute
(
new
Float32Array
(
this
.
PARTICLE_COUNT
*
3
),
3
)
);
this
.
particleShaderGeo
.
addAttribute
(
'
startTime
'
,
new
THREE
.
BufferAttribute
(
new
Float32Array
(
this
.
PARTICLE_COUNT
),
1
)
);
this
.
particleShaderGeo
.
addAttribute
(
'
velocity
'
,
new
THREE
.
BufferAttribute
(
new
Float32Array
(
this
.
PARTICLE_COUNT
*
3
),
3
)
);
this
.
particleShaderGeo
.
addAttribute
(
'
turbulence
'
,
new
THREE
.
BufferAttribute
(
new
Float32Array
(
this
.
PARTICLE_COUNT
),
1
)
);
this
.
particleShaderGeo
.
addAttribute
(
'
color
'
,
new
THREE
.
BufferAttribute
(
new
Float32Array
(
this
.
PARTICLE_COUNT
*
3
),
3
)
);
this
.
particleShaderGeo
.
addAttribute
(
'
size
'
,
new
THREE
.
BufferAttribute
(
new
Float32Array
(
this
.
PARTICLE_COUNT
),
1
)
);
this
.
particleShaderGeo
.
addAttribute
(
'
lifeTime
'
,
new
THREE
.
BufferAttribute
(
new
Float32Array
(
this
.
PARTICLE_COUNT
),
1
)
);
// create a container for particles
self
.
particleUpdate
=
false
;
// material
// Shader Based Particle System
self
.
particleShaderGeo
=
new
THREE
.
BufferGeometry
();
this
.
particleShaderMat
=
this
.
GPUParticleSystem
.
particleShaderMat
;
// new hyper compressed attributes
self
.
particleVertices
=
new
Float32Array
(
self
.
PARTICLE_COUNT
*
3
);
// position
self
.
particlePositionsStartTime
=
new
Float32Array
(
self
.
PARTICLE_COUNT
*
4
);
// position
self
.
particleVelColSizeLife
=
new
Float32Array
(
self
.
PARTICLE_COUNT
*
4
);
var
position
=
new
THREE
.
Vector3
();
var
velocity
=
new
THREE
.
Vector3
();
var
color
=
new
THREE
.
Color
();
for
(
var
i
=
0
;
i
<
self
.
PARTICLE_COUNT
;
i
++
)
{
self
.
particlePositionsStartTime
[
i
*
4
+
0
]
=
100
;
//x
self
.
particlePositionsStartTime
[
i
*
4
+
1
]
=
0
;
//y
self
.
particlePositionsStartTime
[
i
*
4
+
2
]
=
0.0
;
//z
self
.
particlePositionsStartTime
[
i
*
4
+
3
]
=
0.0
;
//startTime
this
.
spawnParticle
=
function
(
options
)
{
self
.
particleVertices
[
i
*
3
+
0
]
=
0
;
//x
self
.
particleVertices
[
i
*
3
+
1
]
=
0
;
//y
self
.
particleVertices
[
i
*
3
+
2
]
=
0.0
;
//z
var
positionStartAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
positionStart
'
);
var
startTimeAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
startTime
'
);
var
velocityAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
velocity
'
);
var
turbulenceAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
turbulence
'
);
var
colorAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
color
'
);
var
sizeAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
size
'
);
var
lifeTimeAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
lifeTime
'
);
self
.
particleVelColSizeLife
[
i
*
4
+
0
]
=
decodeFloat
(
128
,
128
,
0
,
0
);
//vel
self
.
particleVelColSizeLife
[
i
*
4
+
1
]
=
decodeFloat
(
0
,
254
,
0
,
254
);
//color
self
.
particleVelColSizeLife
[
i
*
4
+
2
]
=
1.0
;
//size
self
.
particleVelColSizeLife
[
i
*
4
+
3
]
=
0.0
;
//lifespan
}
options
=
options
||
{};
self
.
particleShaderGeo
.
addAttribute
(
'
position
'
,
new
THREE
.
BufferAttribute
(
self
.
particleVertices
,
3
));
self
.
particleShaderGeo
.
addAttribute
(
'
particlePositionsStartTime
'
,
new
THREE
.
BufferAttribute
(
self
.
particlePositionsStartTime
,
4
).
setDynamic
(
true
));
self
.
particleShaderGeo
.
addAttribute
(
'
particleVelColSizeLife
'
,
new
THREE
.
BufferAttribute
(
self
.
particleVelColSizeLife
,
4
).
setDynamic
(
true
));
// setup reasonable default values for all arguments
self
.
posStart
=
self
.
particleShaderGeo
.
getAttribute
(
'
particlePositionsStartTime
'
);
self
.
velCol
=
self
.
particleShaderGeo
.
getAttribute
(
'
particleVelColSizeLife
'
);
position
=
options
.
position
!==
undefined
?
position
.
copy
(
options
.
position
)
:
position
.
set
(
0
,
0
,
0
);
velocity
=
options
.
velocity
!==
undefined
?
velocity
.
copy
(
options
.
velocity
)
:
velocity
.
set
(
0
,
0
,
0
);
color
=
options
.
color
!==
undefined
?
color
.
set
(
options
.
color
)
:
color
.
set
(
0xffffff
);
self
.
particleShaderMat
=
self
.
GPUParticleSystem
.
particleShaderMat
;
var
positionRandomness
=
options
.
positionRandomness
!==
undefined
?
options
.
positionRandomness
:
0
;
var
velocityRandomness
=
options
.
velocityRandomness
!==
undefined
?
options
.
velocityRandomness
:
0
;
var
colorRandomness
=
options
.
colorRandomness
!==
undefined
?
options
.
colorRandomness
:
1
;
var
turbulence
=
options
.
turbulence
!==
undefined
?
options
.
turbulence
:
1
;
var
lifetime
=
options
.
lifetime
!==
undefined
?
options
.
lifetime
:
5
;
var
size
=
options
.
size
!==
undefined
?
options
.
size
:
10
;
var
sizeRandomness
=
options
.
sizeRandomness
!==
undefined
?
options
.
sizeRandomness
:
0
;
var
smoothPosition
=
options
.
smoothPosition
!==
undefined
?
options
.
smoothPosition
:
false
;
this
.
init
=
function
()
{
self
.
particleSystem
=
new
THREE
.
Points
(
self
.
particleShaderGeo
,
self
.
particleShaderMat
);
self
.
particleSystem
.
frustumCulled
=
false
;
this
.
add
(
self
.
particleSystem
);
};
if
(
this
.
DPR
!==
undefined
)
size
*=
this
.
DPR
;
var
options
=
{},
position
=
new
THREE
.
Vector3
(),
velocity
=
new
THREE
.
Vector3
(),
positionRandomness
=
0
.,
velocityRandomness
=
0
.,
color
=
0xffffff
,
colorRandomness
=
0
.,
turbulence
=
0
.,
lifetime
=
0
.,
size
=
0
.,
sizeRandomness
=
0
.,
smoothPosition
=
false
,
i
;
var
maxVel
=
2
;
var
maxSource
=
250
;
this
.
offset
=
0
;
this
.
count
=
0
;
i
=
this
.
PARTICLE_CURSOR
;
this
.
spawnParticle
=
function
(
options
)
{
// position
options
=
options
||
{};
positionStartAttribute
.
array
[
i
*
3
+
0
]
=
position
.
x
+
(
particleSystem
.
random
()
*
positionRandomness
);
positionStartAttribute
.
array
[
i
*
3
+
1
]
=
position
.
y
+
(
particleSystem
.
random
()
*
positionRandomness
);
positionStartAttribute
.
array
[
i
*
3
+
2
]
=
position
.
z
+
(
particleSystem
.
random
()
*
positionRandomness
);
if
(
smoothPosition
===
true
)
{
positionStartAttribute
.
array
[
i
*
3
+
0
]
+=
-
(
velocity
.
x
*
particleSystem
.
random
()
);
positionStartAttribute
.
array
[
i
*
3
+
1
]
+=
-
(
velocity
.
y
*
particleSystem
.
random
()
);
positionStartAttribute
.
array
[
i
*
3
+
2
]
+=
-
(
velocity
.
z
*
particleSystem
.
random
()
);
// setup reasonable default values for all arguments
position
=
options
.
position
!==
undefined
?
position
.
copy
(
options
.
position
)
:
position
.
set
(
0
.,
0
.,
0
.);
velocity
=
options
.
velocity
!==
undefined
?
velocity
.
copy
(
options
.
velocity
)
:
velocity
.
set
(
0
.,
0
.,
0
.);
positionRandomness
=
options
.
positionRandomness
!==
undefined
?
options
.
positionRandomness
:
0.0
;
velocityRandomness
=
options
.
velocityRandomness
!==
undefined
?
options
.
velocityRandomness
:
0.0
;
color
=
options
.
color
!==
undefined
?
options
.
color
:
0xffffff
;
colorRandomness
=
options
.
colorRandomness
!==
undefined
?
options
.
colorRandomness
:
1.0
;
turbulence
=
options
.
turbulence
!==
undefined
?
options
.
turbulence
:
1.0
;
lifetime
=
options
.
lifetime
!==
undefined
?
options
.
lifetime
:
5.0
;
size
=
options
.
size
!==
undefined
?
options
.
size
:
10
;
sizeRandomness
=
options
.
sizeRandomness
!==
undefined
?
options
.
sizeRandomness
:
0.0
;
smoothPosition
=
options
.
smoothPosition
!==
undefined
?
options
.
smoothPosition
:
false
;
if
(
self
.
DPR
!==
undefined
)
size
*=
self
.
DPR
;
i
=
self
.
PARTICLE_CURSOR
;
self
.
posStart
.
array
[
i
*
4
+
0
]
=
position
.
x
+
((
particleSystem
.
random
())
*
positionRandomness
);
// - ( velocity.x * particleSystem.random() ); //x
self
.
posStart
.
array
[
i
*
4
+
1
]
=
position
.
y
+
((
particleSystem
.
random
())
*
positionRandomness
);
// - ( velocity.y * particleSystem.random() ); //y
self
.
posStart
.
array
[
i
*
4
+
2
]
=
position
.
z
+
((
particleSystem
.
random
())
*
positionRandomness
);
// - ( velocity.z * particleSystem.random() ); //z
self
.
posStart
.
array
[
i
*
4
+
3
]
=
self
.
time
+
(
particleSystem
.
random
()
*
2
e
-
2
);
//startTime
if
(
smoothPosition
===
true
)
{
self
.
posStart
.
array
[
i
*
4
+
0
]
+=
-
(
velocity
.
x
*
particleSystem
.
random
());
//x
self
.
posStart
.
array
[
i
*
4
+
1
]
+=
-
(
velocity
.
y
*
particleSystem
.
random
());
//y
self
.
posStart
.
array
[
i
*
4
+
2
]
+=
-
(
velocity
.
z
*
particleSystem
.
random
());
//z
}
var
velX
=
velocity
.
x
+
(
particleSystem
.
random
())
*
velocityRandomness
;
var
velY
=
velocity
.
y
+
(
particleSystem
.
random
())
*
velocityRandomness
;
var
velZ
=
velocity
.
z
+
(
particleSystem
.
random
())
*
velocityRandomness
;
// velocity
// convert turbulence rating to something we can pack into a vec4
var
turbulence
=
Math
.
floor
(
turbulence
*
254
);
var
maxVel
=
2
;
// clamp our value to between 0. and 1.
velX
=
Math
.
floor
(
maxSource
*
((
velX
-
-
maxVel
)
/
(
maxVel
-
-
maxVel
)));
velY
=
Math
.
floor
(
maxSource
*
((
velY
-
-
maxVel
)
/
(
maxVel
-
-
maxVel
)));
velZ
=
Math
.
floor
(
maxSource
*
((
velZ
-
-
maxVel
)
/
(
maxVel
-
-
maxVel
)));
var
velX
=
velocity
.
x
+
particleSystem
.
random
()
*
velocityRandomness
;
var
velY
=
velocity
.
y
+
particleSystem
.
random
()
*
velocityRandomness
;
var
velZ
=
velocity
.
z
+
particleSystem
.
random
()
*
velocityRandomness
;
self
.
velCol
.
array
[
i
*
4
+
0
]
=
decodeFloat
(
velX
,
velY
,
velZ
,
turbulence
);
//vel
velX
=
THREE
.
Math
.
clamp
(
(
velX
-
(
-
maxVel
)
)
/
(
maxVel
-
(
-
maxVel
)
),
0
,
1
);
velY
=
THREE
.
Math
.
clamp
(
(
velY
-
(
-
maxVel
)
)
/
(
maxVel
-
(
-
maxVel
)
),
0
,
1
);
velZ
=
THREE
.
Math
.
clamp
(
(
velZ
-
(
-
maxVel
)
)
/
(
maxVel
-
(
-
maxVel
)
),
0
,
1
);
var
rgb
=
hexToRgb
(
color
);
velocityAttribute
.
array
[
i
*
3
+
0
]
=
velX
;
velocityAttribute
.
array
[
i
*
3
+
1
]
=
velY
;
velocityAttribute
.
array
[
i
*
3
+
2
]
=
velZ
;
for
(
var
c
=
0
;
c
<
rgb
.
length
;
c
++
)
{
rgb
[
c
]
=
Math
.
floor
(
rgb
[
c
]
+
((
particleSystem
.
random
())
*
colorRandomness
)
*
254
);
if
(
rgb
[
c
]
>
254
)
rgb
[
c
]
=
254
;
if
(
rgb
[
c
]
<
0
)
rgb
[
c
]
=
0
;
}
// color
color
.
r
=
THREE
.
Math
.
clamp
(
color
.
r
+
particleSystem
.
random
()
*
colorRandomness
,
0
,
1
);
color
.
g
=
THREE
.
Math
.
clamp
(
color
.
g
+
particleSystem
.
random
()
*
colorRandomness
,
0
,
1
);
color
.
b
=
THREE
.
Math
.
clamp
(
color
.
b
+
particleSystem
.
random
()
*
colorRandomness
,
0
,
1
);
colorAttribute
.
array
[
i
*
3
+
0
]
=
color
.
r
;
colorAttribute
.
array
[
i
*
3
+
1
]
=
color
.
g
;
colorAttribute
.
array
[
i
*
3
+
2
]
=
color
.
b
;
self
.
velCol
.
array
[
i
*
4
+
1
]
=
decodeFloat
(
rgb
[
0
],
rgb
[
1
],
rgb
[
2
],
254
);
//color
self
.
velCol
.
array
[
i
*
4
+
2
]
=
size
+
(
particleSystem
.
random
())
*
sizeRandomness
;
//size
self
.
velCol
.
array
[
i
*
4
+
3
]
=
lifetime
;
//lifespan
// turbulence, size, lifetime and starttime
turbulenceAttribute
.
array
[
i
]
=
turbulence
;
sizeAttribute
.
array
[
i
]
=
size
+
particleSystem
.
random
()
*
sizeRandomness
;
lifeTimeAttribute
.
array
[
i
]
=
lifetime
;
startTimeAttribute
.
array
[
i
]
=
this
.
time
+
particleSystem
.
random
()
*
2
e
-
2
;
// offset
if
(
this
.
offset
===
0
)
{
this
.
offset
=
this
.
PARTICLE_CURSOR
;
if
(
this
.
offset
==
0
)
{
this
.
offset
=
self
.
PARTICLE_CURSOR
;
}
self
.
count
++
;
// counter and cursor
self
.
PARTICLE_CURSOR
++
;
this
.
count
++
;
this
.
PARTICLE_CURSOR
++
;
if
(
this
.
PARTICLE_CURSOR
>=
this
.
PARTICLE_COUNT
)
{
this
.
PARTICLE_CURSOR
=
0
;
if
(
self
.
PARTICLE_CURSOR
>=
self
.
PARTICLE_COUNT
)
{
self
.
PARTICLE_CURSOR
=
0
;
}
self
.
particleUpdate
=
true
;
this
.
particleUpdate
=
true
;
};
this
.
update
=
function
(
time
)
{
this
.
init
=
function
(
)
{
self
.
time
=
time
;
self
.
particleShaderMat
.
uniforms
[
'
uTime
'
].
value
=
time
;
this
.
particleSystem
=
new
THREE
.
Points
(
this
.
particleShaderGeo
,
this
.
particleShaderMat
);
this
.
particleSystem
.
frustumCulled
=
false
;
this
.
add
(
this
.
particleSystem
);
};
this
.
update
=
function
(
time
)
{
this
.
time
=
time
;
this
.
particleShaderMat
.
uniforms
.
uTime
.
value
=
time
;
this
.
geometryUpdate
();
};
this
.
geometryUpdate
=
function
()
{
if
(
self
.
particleUpdate
==
true
)
{
self
.
particleUpdate
=
false
;
// if we can get away with a partial buffer update, do so
if
(
self
.
offset
+
self
.
count
<
self
.
PARTICLE_COUNT
)
{
self
.
posStart
.
updateRange
.
offset
=
self
.
velCol
.
updateRange
.
offset
=
self
.
offset
*
4
;
self
.
posStart
.
updateRange
.
count
=
self
.
velCol
.
updateRange
.
count
=
self
.
count
*
4
;
if
(
this
.
particleUpdate
===
true
)
{
this
.
particleUpdate
=
false
;
var
positionStartAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
positionStart
'
);
var
startTimeAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
startTime
'
);
var
velocityAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
velocity
'
);
var
turbulenceAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
turbulence
'
);
var
colorAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
color
'
);
var
sizeAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
size
'
);
var
lifeTimeAttribute
=
this
.
particleShaderGeo
.
getAttribute
(
'
lifeTime
'
);
if
(
this
.
offset
+
this
.
count
<
this
.
PARTICLE_COUNT
)
{
positionStartAttribute
.
updateRange
.
offset
=
this
.
offset
*
positionStartAttribute
.
itemSize
;
startTimeAttribute
.
updateRange
.
offset
=
this
.
offset
*
startTimeAttribute
.
itemSize
;
velocityAttribute
.
updateRange
.
offset
=
this
.
offset
*
velocityAttribute
.
itemSize
;
turbulenceAttribute
.
updateRange
.
offset
=
this
.
offset
*
turbulenceAttribute
.
itemSize
;
colorAttribute
.
updateRange
.
offset
=
this
.
offset
*
colorAttribute
.
itemSize
;
sizeAttribute
.
updateRange
.
offset
=
this
.
offset
*
sizeAttribute
.
itemSize
;
lifeTimeAttribute
.
updateRange
.
offset
=
this
.
offset
*
lifeTimeAttribute
.
itemSize
;
positionStartAttribute
.
updateRange
.
count
=
this
.
count
*
positionStartAttribute
.
itemSize
;
startTimeAttribute
.
updateRange
.
count
=
this
.
count
*
startTimeAttribute
.
itemSize
;
velocityAttribute
.
updateRange
.
count
=
this
.
count
*
velocityAttribute
.
itemSize
;
turbulenceAttribute
.
updateRange
.
count
=
this
.
count
*
turbulenceAttribute
.
itemSize
;
colorAttribute
.
updateRange
.
count
=
this
.
count
*
colorAttribute
.
itemSize
;
sizeAttribute
.
updateRange
.
count
=
this
.
count
*
sizeAttribute
.
itemSize
;
lifeTimeAttribute
.
updateRange
.
count
=
this
.
count
*
lifeTimeAttribute
.
itemSize
;
}
else
{
self
.
posStart
.
updateRange
.
offset
=
0
;
self
.
posStart
.
updateRange
.
count
=
self
.
velCol
.
updateRange
.
count
=
(
self
.
PARTICLE_COUNT
*
4
);
positionStartAttribute
.
updateRange
.
offset
=
0
;
startTimeAttribute
.
updateRange
.
offset
=
0
;
velocityAttribute
.
updateRange
.
offset
=
0
;
turbulenceAttribute
.
updateRange
.
offset
=
0
;
colorAttribute
.
updateRange
.
offset
=
0
;
sizeAttribute
.
updateRange
.
offset
=
0
;
lifeTimeAttribute
.
updateRange
.
offset
=
0
;
positionStartAttribute
.
updateRange
.
count
=
positionStartAttribute
.
count
;
startTimeAttribute
.
updateRange
.
count
=
startTimeAttribute
.
count
;
velocityAttribute
.
updateRange
.
count
=
velocityAttribute
.
count
;
turbulenceAttribute
.
updateRange
.
count
=
turbulenceAttribute
.
count
;
colorAttribute
.
updateRange
.
count
=
colorAttribute
.
count
;
sizeAttribute
.
updateRange
.
count
=
sizeAttribute
.
count
;
lifeTimeAttribute
.
updateRange
.
count
=
lifeTimeAttribute
.
count
;
}
self
.
posStart
.
needsUpdate
=
true
;
self
.
velCol
.
needsUpdate
=
true
;
positionStartAttribute
.
needsUpdate
=
true
;
startTimeAttribute
.
needsUpdate
=
true
;
velocityAttribute
.
needsUpdate
=
true
;
turbulenceAttribute
.
needsUpdate
=
true
;
colorAttribute
.
needsUpdate
=
true
;
sizeAttribute
.
needsUpdate
=
true
;
lifeTimeAttribute
.
needsUpdate
=
true
;
this
.
offset
=
0
;
this
.
count
=
0
;
self
.
offset
=
0
;
self
.
count
=
0
;
}
};
this
.
dispose
=
function
()
{
this
.
particleShaderGeo
.
dispose
();
};
this
.
init
();
};
THREE
.
GPUParticleContainer
.
prototype
=
Object
.
create
(
THREE
.
Object3D
.
prototype
);
THREE
.
GPUParticleContainer
.
prototype
=
Object
.
create
(
THREE
.
Object3D
.
prototype
);
THREE
.
GPUParticleContainer
.
prototype
.
constructor
=
THREE
.
GPUParticleContainer
;
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录