Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
718 additions
and
325 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,266 @@ | ||
import { ParticleBuffer, Target, TextureAtlas, UniqueList } from '../common'; | ||
import { fragmentShader, vertexShader } from './shaders'; | ||
|
||
import BaseRenderer from '../../BaseRenderer'; | ||
import { DEFAULT_RENDERER_OPTIONS } from '../common/constants'; | ||
import { Pool } from '../../../core'; | ||
import { RENDERER_TYPE_GPU_DESKTOP } from '../../types'; | ||
|
||
let THREE; | ||
|
||
/** | ||
* GPURenderer for devices that support floating point textures. | ||
* | ||
* @author thrax <manthrax@gmail.com> | ||
* @author rohan-deshpande <rohan@creativelifeform.com> | ||
*/ | ||
export default class DesktopGPURenderer extends BaseRenderer { | ||
constructor(container, three, options = DEFAULT_RENDERER_OPTIONS) { | ||
super(RENDERER_TYPE_GPU_DESKTOP); | ||
|
||
THREE = this.three = three; | ||
const props = { ...DEFAULT_RENDERER_OPTIONS, ...options }; | ||
const { | ||
camera, | ||
maxParticles, | ||
baseColor, | ||
blending, | ||
depthTest, | ||
depthWrite, | ||
transparent, | ||
shouldDebugTextureAtlas, | ||
} = props; | ||
const particleBuffer = new ParticleBuffer(maxParticles, THREE); | ||
const material = new THREE.ShaderMaterial({ | ||
uniforms: { | ||
baseColor: { value: new THREE.Color(baseColor) }, | ||
uTexture: { value: null }, | ||
atlasIndex: { value: null }, | ||
}, | ||
vertexShader: vertexShader(), | ||
fragmentShader: fragmentShader(), | ||
blending: THREE[blending], | ||
depthTest, | ||
depthWrite, | ||
transparent, | ||
}); | ||
|
||
this.camera = camera; | ||
this.targetPool = new Pool(); | ||
this.uniqueList = new UniqueList(maxParticles); | ||
this.particleBuffer = particleBuffer; | ||
this.buffer = particleBuffer.buffer; | ||
this.stride = particleBuffer.stride; | ||
this.geometry = particleBuffer.geometry; | ||
this.material = material; | ||
this.points = new THREE.Points(this.geometry, this.material); | ||
this.points.frustumCulled = false; | ||
this.shouldDebugTextureAtlas = shouldDebugTextureAtlas; | ||
|
||
container.add(this.points); | ||
} | ||
|
||
onSystemUpdate(system) { | ||
super.onSystemUpdate(system); | ||
|
||
this.buffer.needsUpdate = true; | ||
|
||
DesktopGPURenderer.textureAtlas && DesktopGPURenderer.textureAtlas.update(); | ||
} | ||
|
||
/** | ||
* Pools the particle target if it does not exist. | ||
* Updates the target and maps particle properties to the point. | ||
* | ||
* @param {Particle} | ||
*/ | ||
onParticleCreated(particle) { | ||
if (!particle.target) { | ||
particle.target = this.targetPool.get(Target, THREE); | ||
this.uniqueList.add(particle.id); | ||
} | ||
|
||
this.updateTarget(particle).mapParticleTargetPropsToPoint(particle); | ||
} | ||
|
||
/** | ||
* Maps particle properties to the point if the particle has a target. | ||
* | ||
* @param {Particle} | ||
*/ | ||
onParticleUpdate(particle) { | ||
if (!particle.target) { | ||
return; | ||
} | ||
|
||
this.updateTarget(particle).mapParticleTargetPropsToPoint(particle); | ||
} | ||
|
||
/** | ||
* Resets and clears the particle target. | ||
* | ||
* @param {Particle} | ||
*/ | ||
onParticleDead(particle) { | ||
if (!particle.target) { | ||
return; | ||
} | ||
|
||
particle.target.reset(); | ||
this.mapParticleTargetPropsToPoint(particle); | ||
|
||
particle.target = null; | ||
} | ||
|
||
/** | ||
* Maps all mutable properties from the particle to the target. | ||
* | ||
* @param {Particle} | ||
* @return {DesktopGPURenderer} | ||
*/ | ||
updateTarget(particle) { | ||
const { position, scale, radius, color, alpha, body, id } = particle; | ||
const { r, g, b } = color; | ||
|
||
particle.target.position.copy(position); | ||
particle.target.size = scale * radius; | ||
particle.target.color.setRGB(r, g, b); | ||
particle.target.alpha = alpha; | ||
particle.target.index = this.uniqueList.find(id); | ||
|
||
if (body && body instanceof THREE.Sprite) { | ||
const { map } = body.material; | ||
|
||
particle.target.texture = map; | ||
particle.target.textureIndex = DesktopGPURenderer.getTextureID( | ||
this, | ||
map, | ||
this.shouldDebugTextureAtlas | ||
); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
/** | ||
* Entry point for mapping particle properties to buffer geometry points. | ||
* | ||
* @param {Particle} particle - The particle containing the properties to map | ||
* @return {DesktopGPURenderer} | ||
*/ | ||
mapParticleTargetPropsToPoint(particle) { | ||
this.updatePointPosition(particle) | ||
.updatePointSize(particle) | ||
.updatePointColor(particle) | ||
.updatePointAlpha(particle) | ||
.updatePointTextureIndex(particle); | ||
|
||
return this; | ||
} | ||
|
||
/** | ||
* Updates the point's position according to the particle's target position. | ||
* | ||
* @param {Particle} particle - The particle containing the target position. | ||
* @return {DesktopGPURenderer} | ||
*/ | ||
updatePointPosition(particle) { | ||
const attribute = 'position'; | ||
const { geometry, stride, buffer } = this; | ||
const { target } = particle; | ||
const { offset } = geometry.attributes[attribute]; | ||
|
||
buffer.array[target.index * stride + offset + 0] = target.position.x; | ||
buffer.array[target.index * stride + offset + 1] = target.position.y; | ||
buffer.array[target.index * stride + offset + 2] = target.position.z; | ||
|
||
return this; | ||
} | ||
|
||
/** | ||
* Updates the point's size relative to the particle's target scale and radius. | ||
* | ||
* @param {Particle} particle - The particle containing the target scale. | ||
* @return {DesktopGPURenderer} | ||
*/ | ||
updatePointSize(particle) { | ||
const attribute = 'size'; | ||
const { geometry, stride, buffer } = this; | ||
const { target } = particle; | ||
const { offset } = geometry.attributes[attribute]; | ||
|
||
buffer.array[target.index * stride + offset + 0] = target.size; | ||
|
||
return this; | ||
} | ||
|
||
/** | ||
* Updates the point's color attribute according with the particle's target color. | ||
* | ||
* @param {Particle} particle - The particle containing the target color and alpha. | ||
* @return {DesktopGPURenderer} | ||
*/ | ||
updatePointColor(particle) { | ||
const attribute = 'color'; | ||
const { geometry, stride, buffer } = this; | ||
const { target } = particle; | ||
const { offset } = geometry.attributes[attribute]; | ||
|
||
buffer.array[target.index * stride + offset + 0] = target.color.r; | ||
buffer.array[target.index * stride + offset + 1] = target.color.g; | ||
buffer.array[target.index * stride + offset + 2] = target.color.b; | ||
|
||
return this; | ||
} | ||
|
||
/** | ||
* Updates the point alpha attribute with the particle's target alpha. | ||
* | ||
* @param {Particle} particle - The particle containing the target alpha. | ||
* @return {DesktopGPURenderer} | ||
*/ | ||
updatePointAlpha(particle) { | ||
const attribute = 'alpha'; | ||
const { geometry, stride, buffer } = this; | ||
const { target } = particle; | ||
const { offset } = geometry.attributes[attribute]; | ||
|
||
buffer.array[target.index * stride + offset + 0] = target.alpha; | ||
|
||
return this; | ||
} | ||
|
||
/** | ||
* Updates the point texture attribute with the particle's target texture. | ||
* | ||
* @param {Particle} particle - The particle containing the target texture. | ||
* @return {DesktopGPURenderer} | ||
*/ | ||
updatePointTextureIndex(particle) { | ||
const attribute = 'texID'; | ||
const { geometry, stride, buffer } = this; | ||
const { target } = particle; | ||
const { offset } = geometry.attributes[attribute]; | ||
|
||
buffer.array[target.index * stride + offset + 0] = target.textureIndex; | ||
|
||
return this; | ||
} | ||
} | ||
|
||
DesktopGPURenderer.getTextureID = (renderer, texture, debug) => { | ||
if (texture.textureIndex === undefined) { | ||
let atlas = DesktopGPURenderer.textureAtlas; | ||
|
||
if (!atlas) { | ||
atlas = DesktopGPURenderer.textureAtlas = new TextureAtlas( | ||
renderer, | ||
debug | ||
); | ||
} | ||
|
||
atlas.addTexture(texture); | ||
} | ||
|
||
return texture.textureIndex; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
20 changes: 10 additions & 10 deletions
20
...derer/GPURenderer/shaders/vertexShader.js → ...URenderer/Desktop/shaders/vertexShader.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.