Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
257ecbc
feat: Implement a new 3D physics engine extension with rigid-body sim…
Feb 28, 2026
d56647a
feat: Add scripts to build and import GDJS Runtime and extensions int…
Mar 1, 2026
99893dc
feat: Add 3D physics behavior extension with support for various body…
Mar 1, 2026
914db0a
feat: implement core 3D physics behavior with Jolt Physics integratio…
Mar 1, 2026
a7147e6
feat: Introduce Physics3DBehavior extension and update CMake build co…
Mar 1, 2026
514e5bb
feat: Add Physics3DBehavior extension with JavaScript and TypeScript …
Mar 1, 2026
6d37c27
feat: Introduce new dialogs for variable and object editing, a serial…
Mar 1, 2026
1b427fe
feat: Implement 3D Point Light and Spot Light filters for scene rende…
Mar 1, 2026
22123af
feat: Add Scene3D extension providing base 3D object behavior with Z-…
Mar 1, 2026
5cecb0c
feat: Add initial 3D scene support with base 3D object behavior, 3D m…
Mar 1, 2026
80dc201
feat: Introduce core 3D capabilities with a new Scene3D extension, Ba…
Mar 1, 2026
58d8a31
feat: add 3D capabilities, including a base behavior, 3D model object…
Mar 1, 2026
9ccdd74
feat: Add Screen Space Reflections (SSR) post-processing effect for 3…
Mar 1, 2026
8a77188
feat(3D): Add SpotLight filter with configurable properties, shadows,…
Mar 1, 2026
fd508da
feat: add 3D extension with base object behavior, 3D model, and new 3…
Mar 1, 2026
fb1e5c4
feat: Add Screen Space Reflections (SSR) post-processing effect for 3…
Mar 1, 2026
faa355e
feat: Add a new Screen Space Ambient Occlusion (SSAO) post-processing…
Mar 1, 2026
71c12a1
feat: introduce new 3D post-processing effects including Screen Space…
Mar 1, 2026
e97b84d
feat: add 3D post-processing effects including Depth of Field, SSAO, …
Mar 1, 2026
0b4fe0e
feat: Add new 3D effects and behaviors
Mar 2, 2026
70ed6ef
feat: Add target layer and effect properties to FlickeringLight behavior
Mar 2, 2026
85bc8d1
refactor: Simplify managedPassOrder by removing unused entries
Mar 2, 2026
42d82fc
feat: Add ToneMapping effect for enhanced 3D rendering with configura…
Mar 2, 2026
3812fb5
feat: Enhance lighting effects with new shadow properties and stabili…
Mar 2, 2026
d83320e
feat: Add new shadow properties for enhanced control over cascaded sh…
Mar 2, 2026
3704606
feat: Update shadow map size description to include 4096 for high-end…
Mar 2, 2026
651476c
feat: Add RimLight effect for enhanced rim shading in 3D scenes
Mar 2, 2026
58a2c5e
chore: clean PR noise and revert unrelated tooling changes
Mar 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Extensions/3D/BloomEffect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace gdjs {
0,
0
);
gdjs.markScene3DPostProcessingPass(this.shaderPass, 'BLOOM');
this._isEnabled = false;
}

Expand Down Expand Up @@ -57,7 +58,13 @@ namespace gdjs {
this._isEnabled = false;
return true;
}
updatePreRender(target: gdjs.EffectsTarget): any {}
updatePreRender(target: gdjs.EffectsTarget): any {
if (!(target instanceof gdjs.Layer)) {
return;
}
this.shaderPass.enabled =
gdjs.isScene3DPostProcessingEnabled(target);
}
updateDoubleParameter(parameterName: string, value: number): void {
if (parameterName === 'strength') {
this.shaderPass.strength = value;
Expand Down
233 changes: 233 additions & 0 deletions Extensions/3D/ChromaticAberrationEffect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
namespace gdjs {
interface ChromaticAberrationNetworkSyncData {
i: number;
rs: number;
e: boolean;
}

const chromaticAberrationShader = {
uniforms: {
tDiffuse: { value: null },
tSceneColor: { value: null },
intensity: { value: 0.005 },
radialScale: { value: 1.0 },
},
vertexShader: `
varying vec2 vUv;

void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
precision highp float;

uniform sampler2D tDiffuse;
uniform sampler2D tSceneColor;
uniform float intensity;
uniform float radialScale;
varying vec2 vUv;

vec2 clampUv(vec2 uv) {
return clamp(uv, vec2(0.0), vec2(1.0));
}

void main() {
vec4 baseColor = texture2D(tDiffuse, vUv);
if (intensity <= 0.0) {
gl_FragColor = baseColor;
return;
}

vec2 centered = vUv - vec2(0.5);
float distanceFromCenter = length(centered);
vec2 direction =
distanceFromCenter > 0.00001
? centered / distanceFromCenter
: vec2(0.0);

float edgeFactor = clamp(distanceFromCenter * 1.41421356237, 0.0, 1.0);
edgeFactor = pow(edgeFactor, max(0.0001, radialScale));
vec2 channelOffset = direction * intensity * edgeFactor;

vec2 uvRed = clampUv(vUv + channelOffset);
vec2 uvBlue = clampUv(vUv - channelOffset);

vec3 diffuseRed = texture2D(tDiffuse, uvRed).rgb;
vec3 diffuseCenter = texture2D(tDiffuse, vUv).rgb;
vec3 diffuseBlue = texture2D(tDiffuse, uvBlue).rgb;

// Blend in a bit of shared scene capture to keep this pass coherent
// with the centralized PostProcessingStack capture flow.
vec3 sceneRed = texture2D(tSceneColor, uvRed).rgb;
vec3 sceneBlue = texture2D(tSceneColor, uvBlue).rgb;
float captureMix = 0.18;

float red = mix(diffuseRed.r, sceneRed.r, captureMix);
float green = diffuseCenter.g;
float blue = mix(diffuseBlue.b, sceneBlue.b, captureMix);

gl_FragColor = vec4(red, green, blue, baseColor.a);
}
`,
};

gdjs.PixiFiltersTools.registerFilterCreator(
'Scene3D::ChromaticAberration',
new (class implements gdjs.PixiFiltersTools.FilterCreator {
makeFilter(
target: EffectsTarget,
effectData: EffectData
): gdjs.PixiFiltersTools.Filter {
if (typeof THREE === 'undefined') {
return new gdjs.PixiFiltersTools.EmptyFilter();
}
return new (class implements gdjs.PixiFiltersTools.Filter {
shaderPass: THREE_ADDONS.ShaderPass;
_isEnabled: boolean;
_effectEnabled: boolean;
_intensity: number;
_radialScale: number;

constructor() {
this.shaderPass = new THREE_ADDONS.ShaderPass(
chromaticAberrationShader
);
gdjs.markScene3DPostProcessingPass(this.shaderPass, 'CHROMA');
this._isEnabled = false;
this._effectEnabled = true;
this._intensity = 0.005;
this._radialScale = 1.0;
this.shaderPass.enabled = true;
}

isEnabled(target: EffectsTarget): boolean {
return this._isEnabled;
}
setEnabled(target: EffectsTarget, enabled: boolean): boolean {
if (this._isEnabled === enabled) {
return true;
}
if (enabled) {
return this.applyEffect(target);
} else {
return this.removeEffect(target);
}
}
applyEffect(target: EffectsTarget): boolean {
if (!(target instanceof gdjs.Layer)) {
return false;
}
target.getRenderer().addPostProcessingPass(this.shaderPass);
this._isEnabled = true;
return true;
}
removeEffect(target: EffectsTarget): boolean {
if (!(target instanceof gdjs.Layer)) {
return false;
}
target.getRenderer().removePostProcessingPass(this.shaderPass);
this._isEnabled = false;
return true;
}

updatePreRender(target: gdjs.EffectsTarget): any {
if (!this._isEnabled || !this._effectEnabled) {
return;
}
if (!(target instanceof gdjs.Layer)) {
return;
}

const runtimeScene = target.getRuntimeScene();
const threeRenderer = runtimeScene
.getGame()
.getRenderer()
.getThreeRenderer();
const layerRenderer = target.getRenderer();
const threeScene = layerRenderer.getThreeScene();
const threeCamera = layerRenderer.getThreeCamera();

if (!threeRenderer || !threeScene || !threeCamera) {
return;
}

if (!gdjs.isScene3DPostProcessingEnabled(target)) {
this.shaderPass.enabled = false;
return;
}

const sharedCapture = gdjs.captureScene3DSharedTextures(
target,
threeRenderer,
threeScene,
threeCamera
);
if (!sharedCapture) {
return;
}

this.shaderPass.enabled = true;
this.shaderPass.uniforms.tSceneColor.value =
sharedCapture.colorTexture;
this.shaderPass.uniforms.intensity.value = this._intensity;
this.shaderPass.uniforms.radialScale.value = this._radialScale;
}

updateDoubleParameter(parameterName: string, value: number): void {
if (parameterName === 'intensity') {
this._intensity = Math.max(0, value);
this.shaderPass.uniforms.intensity.value = this._intensity;
} else if (parameterName === 'radialScale') {
this._radialScale = Math.max(0, value);
this.shaderPass.uniforms.radialScale.value = this._radialScale;
}
}

getDoubleParameter(parameterName: string): number {
if (parameterName === 'intensity') {
return this._intensity;
}
if (parameterName === 'radialScale') {
return this._radialScale;
}
return 0;
}

updateStringParameter(parameterName: string, value: string): void {}
updateColorParameter(parameterName: string, value: number): void {}
getColorParameter(parameterName: string): number {
return 0;
}
updateBooleanParameter(parameterName: string, value: boolean): void {
if (parameterName === 'enabled') {
this._effectEnabled = value;
this.shaderPass.enabled = value;
}
}

getNetworkSyncData(): ChromaticAberrationNetworkSyncData {
return {
i: this._intensity,
rs: this._radialScale,
e: this._effectEnabled,
};
}

updateFromNetworkSyncData(
syncData: ChromaticAberrationNetworkSyncData
): void {
this._intensity = Math.max(0, syncData.i);
this._radialScale = Math.max(0, syncData.rs);
this._effectEnabled = !!syncData.e;

this.shaderPass.uniforms.intensity.value = this._intensity;
this.shaderPass.uniforms.radialScale.value = this._radialScale;
this.shaderPass.enabled = this._effectEnabled;
}
})();
}
})()
);
}
Loading