Skip to content

Commit

Permalink
First take at gpu particle systems with compute shaders
Browse files Browse the repository at this point in the history
  • Loading branch information
Popov72 committed May 16, 2021
1 parent 7966e76 commit 17e27bc
Show file tree
Hide file tree
Showing 10 changed files with 301 additions and 123 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ node_modules
!Playground/libs/*.d.ts
*.fragment.ts
*.vertex.ts
*.compute.ts
**/ShadersInclude/**/*.ts

# Split declaration file
Expand Down
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@
"proceduralTexturesLibrary/**/*.js.map": true,
"serielazers/**/*.js.map": true,
"**/*.js.fx": true,
"**/*.js.wgsl": true,
"**/*.js": {
"when": "$(basename).ts"
},
"**/*.fragment.ts": true,
"**/*.vertex.ts": true,
"**/*.compute.ts": true,
"**/ShadersInclude/**/*.ts": true
},
"files.associations": {
Expand All @@ -52,6 +54,7 @@
"dist/**/*.d.ts": true,
"**/*.fragment.ts": true,
"**/*.vertex.ts": true,
"**/*.compute.ts": true,
"**/ShadersInclude/**/*.ts": true,
"assets": true,
"**/babylonWeb**": true,
Expand Down
1 change: 1 addition & 0 deletions Tools/Config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ allModules.map(function(module) {
const shaderTSGlob = [
srcDirectory.replace(/\\/g, "/") + "/**/*.fragment.ts",
srcDirectory.replace(/\\/g, "/") + "/**/*.vertex.ts",
srcDirectory.replace(/\\/g, "/") + "/**/*.compute.ts",
srcDirectory.replace(/\\/g, "/") + "/**/ShadersInclude/*.ts",
];
const tsGlob = srcDirectory.replace(/\\/g, "/") + "/**/*.ts*";
Expand Down
4 changes: 2 additions & 2 deletions Tools/Gulp/helpers/gulp-processShaders.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Effect.##SHADERSTORE_PLACEHOLDER##[name] = shader;
function getShaderName(filename) {
let parts = filename.split('.');
if (parts[1] !== 'fx') {
return parts[0] + (parts[1] === 'fragment' ? 'Pixel' : 'Vertex') + "Shader";
return parts[0] + (parts[1] === 'fragment' ? 'Pixel' : parts[1] === 'compute' ? 'Compute' : 'Vertex') + "Shader";
} else {
return parts[0];
}
Expand Down Expand Up @@ -82,7 +82,7 @@ function main(isCore) {
const normalized = path.normalize(file.path);
const directory = path.dirname(normalized);
const shaderName = getShaderName(filename);
const tsFilename = filename.replace('.fx', '.ts');
const tsFilename = filename.replace('.fx', '.ts').replace('.wgsl', '.ts');
let fxData = file.contents.toString();

// Remove Trailing whitespace...
Expand Down
2 changes: 1 addition & 1 deletion Tools/Gulp/tasks/gulpTasks-importLint.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var buildShaders = function(settings) {
* ImportLint all typescript files from the src directory.
*/
var importLintLibrary = function(settings) {
const fxFilter = filter(['**', '!**/*.fragment.ts', '!**/*.vertex.ts', '!**/ShadersInclude/**'], { restore: false });
const fxFilter = filter(['**', '!**/*.fragment.ts', '!**/*.vertex.ts', '!**/*.compute.ts', '!**/ShadersInclude/**'], { restore: false });
return gulp.src(settings.computed.tsGlob)
.pipe(fxFilter)
.pipe(validateImports({
Expand Down
3 changes: 2 additions & 1 deletion Tools/WebpackPlugins/babylonWebpackConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ module.exports = function defaultConfig(options) {
new webpack.WatchIgnorePlugin([
/\.js$/,
/\.d\.ts$/,
/\.fx$/
/\.fx$/,
/\.wgsl$/
]),
...options.plugins
]
Expand Down
280 changes: 186 additions & 94 deletions src/Particles/gpuParticleSystem.ts

Large diffs are not rendered by default.

18 changes: 8 additions & 10 deletions src/Shaders/gpuRenderParticles.fragment.fx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
#version 300 es
precision highp float;

uniform sampler2D diffuseSampler;

in vec2 vUV;
in vec4 vColor;

out vec4 outFragColor;
varying vec2 vUV;
varying vec4 vColor;

#include<clipPlaneFragmentDeclaration2>

Expand All @@ -18,21 +16,21 @@ out vec4 outFragColor;
void main() {
#include<clipPlaneFragment>
vec4 textureColor = texture(diffuseSampler, vUV);
outFragColor = textureColor * vColor;
gl_FragColor = textureColor * vColor;

#ifdef BLENDMULTIPLYMODE
float alpha = vColor.a * textureColor.a;
outFragColor.rgb = outFragColor.rgb * alpha + vec3(1.0) * (1.0 - alpha);
gl_FragColor.rgb = gl_FragColor.rgb * alpha + vec3(1.0) * (1.0 - alpha);
#endif

// Apply image processing if relevant. As this applies in linear space,
// We first move from gamma to linear.
#ifdef IMAGEPROCESSINGPOSTPROCESS
outFragColor.rgb = toLinearSpace(outFragColor.rgb);
gl_FragColor.rgb = toLinearSpace(gl_FragColor.rgb);
#else
#ifdef IMAGEPROCESSING
outFragColor.rgb = toLinearSpace(outFragColor.rgb);
outFragColor = applyImageProcessing(outFragColor);
gl_FragColor.rgb = toLinearSpace(gl_FragColor.rgb);
gl_FragColor = applyImageProcessing(gl_FragColor);
#endif
#endif
}
30 changes: 15 additions & 15 deletions src/Shaders/gpuRenderParticles.vertex.fx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#version 300 es
precision highp float;

uniform mat4 view;
uniform mat4 projection;
Expand All @@ -9,26 +9,26 @@ uniform mat4 emitterWM;
#endif

// Particles state
in vec3 position;
in float age;
in float life;
in vec3 size;
attribute vec3 position;
attribute float age;
attribute float life;
attribute vec3 size;
#ifndef BILLBOARD
in vec3 initialDirection;
attribute vec3 initialDirection;
#endif
#ifdef BILLBOARDSTRETCHED
in vec3 direction;
attribute vec3 direction;
#endif
in float angle;
attribute float angle;
#ifdef ANIMATESHEET
in float cellIndex;
attribute float cellIndex;
#endif
in vec2 offset;
in vec2 uv;
attribute vec2 offset;
attribute vec2 uv;

out vec2 vUV;
out vec4 vColor;
out vec3 vPositionW;
varying vec2 vUV;
varying vec4 vColor;
varying vec3 vPositionW;

#if defined(BILLBOARD) && !defined(BILLBOARDY) && !defined(BILLBOARDSTRETCHED)
uniform mat4 invView;
Expand All @@ -40,7 +40,7 @@ uniform mat4 invView;
uniform sampler2D colorGradientSampler;
#else
uniform vec4 colorDead;
in vec4 color;
attribute vec4 color;
#endif

#ifdef ANIMATESHEET
Expand Down
82 changes: 82 additions & 0 deletions src/Shaders/gpuUpdateParticles.compute.fx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
struct Particle {
position : vec3<f32>;
#ifdef CUSTOMEMITTER
initialPosition : vec3<f32>;
#endif
age : f32;
life : f32;
seed : vec4<f32>;
size : vec3<f32>;
#ifndef COLORGRADIENTS
color : vec4<f32>;
#endif
direction : vec3<f32>;
#ifndef BILLBOARD
initialDirection : vec3<f32>;
#endif
#ifdef ANGULARSPEEDGRADIENTS
angle : f32;
#else
angle : vec2<f32>;
#endif
#ifdef ANIMATESHEET
cellIndex : f32;
#ifdef ANIMATESHEETRANDOMSTART
cellStartOffset : f32;
#endif
#endif
#ifdef NOISE
noiseCoordinates1 : vec3<f32>;
noiseCoordinates2 : vec3<f32>;
#endif
};
[[block]] struct SimParams {
numParticles: u32;
};
[[block]] struct Particles {
particles : array<Particle>;
};

[[binding(0), group(0)]] var<uniform> params : SimParams;
[[binding(1), group(0)]] var<storage> particlesIn : [[access(read)]] Particles;
[[binding(2), group(0)]] var<storage> particlesOut : [[access(write)]] Particles;

[[stage(compute), workgroup_size(64)]]
fn main([[builtin(global_invocation_id)]] GlobalInvocationID : vec3<u32>) {
let index : u32 = GlobalInvocationID.x;

if (index >= params.numParticles) {
return;
}

particlesOut.particles[index].position = particlesIn.particles[index].position;
#ifdef CUSTOMEMITTER
particlesOut.particles[index].initialPosition = particlesIn.particles[index].initialPosition;
#endif
particlesOut.particles[index].age = particlesIn.particles[index].age;
particlesOut.particles[index].life = particlesIn.particles[index].life;
particlesOut.particles[index].seed = particlesIn.particles[index].seed;
particlesOut.particles[index].size = particlesIn.particles[index].size;
#ifndef COLORGRADIENTS
particlesOut.particles[index].color = particlesIn.particles[index].color;
#endif
particlesOut.particles[index].direction = particlesIn.particles[index].direction;
#ifndef BILLBOARD
particlesOut.particles[index].initialDirection = particlesIn.particles[index].initialDirection;
#endif
#ifdef ANGULARSPEEDGRADIENTS
particlesOut.particles[index].angle = particlesIn.particles[index].angle;
#else
particlesOut.particles[index].angle = particlesIn.particles[index].angle;
#endif
#ifdef ANIMATESHEET
particlesOut.particles[index].cellIndex = particlesIn.particles[index].cellIndex;
#ifdef ANIMATESHEETRANDOMSTART
particlesOut.particles[index].cellStartOffset = particlesIn.particles[index].cellStartOffset;
#endif
#endif
#ifdef NOISE
particlesOut.particles[index].noiseCoordinates1 = particlesIn.particles[index].noiseCoordinates1;
particlesOut.particles[index].noiseCoordinates2 = particlesIn.particles[index].noiseCoordinates2;
#endif
}

0 comments on commit 17e27bc

Please sign in to comment.