Skip to content

Commit

Permalink
✨ Particles, the feature that never ends
Browse files Browse the repository at this point in the history
  • Loading branch information
benc-uk committed Aug 16, 2023
1 parent 0083b3c commit 2dd118a
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 29 deletions.
14 changes: 12 additions & 2 deletions dist-bundle/gsots3d.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist-bundle/gsots3d.js.map

Large diffs are not rendered by default.

36 changes: 20 additions & 16 deletions examples/particles/main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,36 @@ import { Context, Material, TextureCache, setLogLevel } from '../../dist-bundle/

const ctx = await Context.init()
ctx.camera.position = [0, 130, 150]
ctx.camera.enableFPControls(0, -0.04, 0.002, 4)
ctx.camera.enableFPControls(0, -0.24, 0.002, 4)
ctx.camera.far = 1800
ctx.gamma = 1.0
ctx.gamma = 1.1
setLogLevel(1)

ctx.globalLight.setAsPosition(5, 20, 18)
const amb = 0.1
ctx.globalLight.setAsPosition(5, 20, 12)
const amb = 0.2
ctx.globalLight.ambient = [amb, amb, amb]
ctx.globalLight.enableShadows({
mapSize: 512,
scatter: 0.8,
mapSize: 1024,
// scatter: 0.4,
zoom: 180.0,
polygonOffsetFactor: 2.5,
})

// ctx.setEnvmap(
// true,
// '../_textures/skybox-dungeon/right.png',
// '../_textures/skybox-dungeon/left.png',
// '../_textures/skybox-dungeon/up.png',
// '../_textures/skybox-dungeon/down.png',
// '../_textures/skybox-dungeon/front.png',
// '../_textures/skybox-dungeon/back.png'
// )
ctx.setEnvmap(
true,
'../_textures/skybox-dungeon/right.png',
'../_textures/skybox-dungeon/left.png',
'../_textures/skybox-dungeon/up.png',
'../_textures/skybox-dungeon/down.png',
'../_textures/skybox-dungeon/front.png',
'../_textures/skybox-dungeon/back.png'
)

await ctx.loadModel('../_objects/box', 'box.obj')

const floorMat = Material.createBasicTexture('../_textures/wood-floor.png')
ctx.createPlaneInstance(floorMat, 1000, 1000, 1, 1, 6)
const f = ctx.createPlaneInstance(floorMat, 1000, 1000, 1, 1, 6)
f.receiveShadow = true

const pipeMat = Material.createBasicTexture('../_textures/sci-fi.png')
pipeMat.addNormalTexture('../_textures/sci-fi_normal.png')
Expand Down Expand Up @@ -107,6 +110,7 @@ part3.ageColour = [0, 0, 0, 3.0]
part3.gravity = [0, -2, 0]
part3.timeScale = 1
part3.preColour = [0.0, 0.7, 0.0, 1.0]
part3.blendSource = ctx.gl.SRC_COLOR

window.addEventListener('keydown', (e) => {
if (e.key === '1') {
Expand Down
3 changes: 2 additions & 1 deletion shaders/particles/render.vert
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ out float v_ageNorm;

void main() {
vec3 vert_pos = position.xyz;
v_ageNorm = tf_age[0] / tf_age[1];
v_ageNorm = clamp(tf_age[0] / tf_age[1], 0.0, 1.0);
v_ageNorm = pow(v_ageNorm, 0.7);

// Rotate by tf_position[3] (rotation)
float s = sin(tf_position[3]);
Expand Down
7 changes: 4 additions & 3 deletions shaders/phong/glsl.frag
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ uniform samplerCube u_reflectionMap;
// Shadows
uniform highp sampler2DShadow u_shadowMap;
uniform float u_shadowScatter;
uniform bool u_receiveShadow;

// Global texture coords shared between functions
vec2 texCoord;
Expand Down Expand Up @@ -110,17 +111,17 @@ vec4 shadeDirLight(LightDir light, Material mat, vec3 N, vec3 V) {

// Shadow map lookup
vec3 projCoords = v_shadowCoord.xyz / v_shadowCoord.w * 0.5 + 0.5;
float shadow = 0.0;

// Carry out PCF for shadows using 4 samples of a poisson disk
float shadow = 0.0;
for (int i = 0; i < 4; i++) {
vec3 offset = poissonDisk[i] * (u_shadowScatter / 100.0);
shadow += shadowMapSample(u_shadowMap, projCoords + offset) * 0.25;
}

vec3 ambient = light.ambient * mat.ambient * diffuseCol;
vec3 diffuse = light.colour * max(diff, 0.0) * diffuseCol * shadow;
vec3 specular = light.colour * spec * specularCol * shadow;
vec3 diffuse = light.colour * max(diff, 0.0) * diffuseCol * (u_receiveShadow ? shadow : 1.0);
vec3 specular = light.colour * spec * specularCol * (u_receiveShadow ? shadow : 1.0);

// Return a vec4 to support transparency, note specular is not affected by opacity
return vec4(ambient + diffuse, mat.opacity / float(u_lightsPosCount + 1)) + vec4(specular, spec);
Expand Down
8 changes: 7 additions & 1 deletion src/core/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class Context {
public readonly hud: HUD

/** Gamma correction value, default 1.0 */
public gamma = 1.0
public gamma: number

// ==== Getters =============================================================

Expand All @@ -89,6 +89,7 @@ export class Context {
this.gl = gl
this.started = false
this.debug = false
this.gamma = 1.0

// Main global light
this.globalLight = new LightDirectional()
Expand Down Expand Up @@ -166,6 +167,10 @@ export class Context {
const shadowCam = this.globalLight.getShadowCamera()
// Switch to front face culling for shadow map, yeah it's weird but it works!
this.gl.cullFace(this.gl.FRONT)
this.gl.enable(this.gl.POLYGON_OFFSET_FILL)

const shadowOpt = this.globalLight.shadowMapOptions
this.gl.polygonOffset(shadowOpt?.polygonOffsetFactor ?? 0, 1)

// Bind the shadow map framebuffer and render the scene from the light's POV
// Using the special shadow map program as an override for the whole rendering pass
Expand All @@ -174,6 +179,7 @@ export class Context {

// Switch back to back face culling
this.gl.cullFace(this.gl.BACK)
this.gl.disable(this.gl.POLYGON_OFFSET_FILL)
}

// RENDERING - Render the scene from active camera into the main framebuffer
Expand Down
11 changes: 7 additions & 4 deletions src/engine/lights.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ export type ShadowOptions = {
/** Size of the shadow map texture. Default: 512 */
mapSize: number

/**
* Zoom level of the shadow map camera, larger will cover more of the scene,
* but results in more blocky shadows. Default 120
*/
/** Zoom level of the shadow map camera, larger will cover more of the scene, but results in more blocky shadows. Default 120 */
zoom: number

/** Far clipping pane of shadow map camera, default 1000 */
distance: number

/** Blur the edges of shadows, higher values them more random, default 0.2 */
scatter: number

/** Offset used to reduce shadow acne especially when self shadowing */
polygonOffsetFactor: number
}

/**
Expand Down Expand Up @@ -125,6 +125,9 @@ export class LightDirectional {
if (!this._shadowOptions.scatter) {
this._shadowOptions.scatter = 0.2
}
if (!this._shadowOptions.polygonOffsetFactor) {
this._shadowOptions.polygonOffsetFactor = 0
}

const gl = getGl()
if (!gl) {
Expand Down
6 changes: 5 additions & 1 deletion src/models/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ export class Instance {
/** Rotation in radians around X, Y, Z axis */
private rotate: XYZ | undefined

/** Should this instance receive shadows */
private receiveShadow = true

/**
* Create a new instace of a renderable thing
* @param {Renderable} renderable - Renderable to use for this instance
Expand Down Expand Up @@ -134,9 +137,10 @@ export class Instance {
// Finally populate u_worldViewProjection used for rendering
mat4.multiply(<mat4>uniforms.u_worldViewProjection, <mat4>uniforms.u_proj, worldView)

// Apply per instance texture flip flags
// Apply per instance uniforms for the shader
uniforms.u_flipTextureX = this.flipTextureX
uniforms.u_flipTextureY = this.flipTextureY
uniforms.u_receiveShadow = this.receiveShadow

gl.enable(gl.BLEND)
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
Expand Down

0 comments on commit 2dd118a

Please sign in to comment.