diff --git a/packages/dev/core/src/Engines/WebGPU/Extensions/engine.rawTexture.ts b/packages/dev/core/src/Engines/WebGPU/Extensions/engine.rawTexture.ts index 6b0ff1bf8f6..55401c44669 100644 --- a/packages/dev/core/src/Engines/WebGPU/Extensions/engine.rawTexture.ts +++ b/packages/dev/core/src/Engines/WebGPU/Extensions/engine.rawTexture.ts @@ -392,6 +392,7 @@ WebGPUEngine.prototype.createRawCubeTextureFromUrl = function ( const texture = this.createRawCubeTexture(null, size, format, type, !noMipmap, invertY, samplingMode, null); scene?.addPendingData(texture); texture.url = url; + texture.isReady = false; this._internalTexturesCache.push(texture); diff --git a/packages/dev/core/src/Layers/effectLayer.ts b/packages/dev/core/src/Layers/effectLayer.ts index 98ccd188b06..53a3665e306 100644 --- a/packages/dev/core/src/Layers/effectLayer.ts +++ b/packages/dev/core/src/Layers/effectLayer.ts @@ -30,6 +30,7 @@ import { DrawWrapper } from "../Materials/drawWrapper"; import { addClipPlaneUniforms, bindClipPlane, prepareStringDefinesForClipPlanes } from "../Materials/clipPlaneMaterialHelper"; import { BindMorphTargetParameters, PrepareAttributesForMorphTargetsInfluencers, PushAttributesForInstances } from "../Materials/materialHelper.functions"; import { GetExponentOfTwo } from "../Misc/tools.functions"; +import { ShaderLanguage } from "core/Materials/shaderLanguage"; /** * Effect layer options. This helps customizing the behaviour @@ -98,6 +99,12 @@ export abstract class EffectLayer { protected _emissiveTextureAndColor: { texture: Nullable; color: Color4 } = { texture: null, color: new Color4() }; protected _effectIntensity: { [meshUniqueId: number]: number } = {}; + /** + * Force all the effect layers to compile to glsl even on WebGPU engines. + * False by default. This is mostly meant for backward compatibility. + */ + public static ForceGLSL = false; + /** * The name of the layer */ @@ -183,6 +190,16 @@ export abstract class EffectLayer { return this._mainTexture; } + /** Shader language used by the material */ + protected _shaderLanguage = ShaderLanguage.GLSL; + + /** + * Gets the shader language used in this material. + */ + public get shaderLanguage(): ShaderLanguage { + return this._shaderLanguage; + } + /** * @internal */ @@ -239,17 +256,21 @@ export abstract class EffectLayer { * Instantiates a new effect Layer and references it in the scene. * @param name The name of the layer * @param scene The scene to use the layer in + * @param forceGLSL Use the GLSL code generation for the shader (even on WebGPU). Default is false */ constructor( /** The Friendly of the effect in the scene */ name: string, - scene?: Scene + scene?: Scene, + forceGLSL = false ) { this.name = name; this._scene = scene || EngineStore.LastCreatedScene; EffectLayer._SceneComponentInitialization(this._scene); + this._initShaderSourceAsync(forceGLSL); + this._engine = this._scene.getEngine(); this._maxSize = this._engine.getCaps().maxTextureSize; this._scene.effectLayers.push(this); @@ -261,6 +282,21 @@ export abstract class EffectLayer { this._generateVertexBuffer(); } + private _shadersLoaded = false; + protected async _initShaderSourceAsync(forceGLSL = false) { + const engine = this._scene.getEngine(); + + if (engine.isWebGPU && !forceGLSL && !EffectLayer.ForceGLSL) { + this._shaderLanguage = ShaderLanguage.WGSL; + + await Promise.all([import("../ShadersWGSL/glowMapGeneration.fragment"), import("../ShadersWGSL/glowMapGeneration.vertex")]); + } else { + await Promise.all([import("../Shaders/glowMapGeneration.fragment"), import("../Shaders/glowMapGeneration.vertex")]); + } + + this._shadersLoaded = true; + } + /** * Get the effect name of the layer. * @returns The effect name @@ -542,6 +578,10 @@ export abstract class EffectLayer { * @returns true if ready otherwise, false */ protected _isReady(subMesh: SubMesh, useInstances: boolean, emissiveTexture: Nullable): boolean { + if (!this._shadersLoaded) { + return false; + } + const engine = this._scene.getEngine(); const mesh = subMesh.getMesh(); @@ -727,7 +767,8 @@ export abstract class EffectLayer { fallbacks, undefined, undefined, - { maxSimultaneousMorphTargets: morphInfluencers } + { maxSimultaneousMorphTargets: morphInfluencers }, + this._shaderLanguage ), join ); diff --git a/packages/dev/core/src/Layers/glowLayer.ts b/packages/dev/core/src/Layers/glowLayer.ts index 3fe391d4794..6c0db7e64e2 100644 --- a/packages/dev/core/src/Layers/glowLayer.ts +++ b/packages/dev/core/src/Layers/glowLayer.ts @@ -21,11 +21,10 @@ import { RegisterClass } from "../Misc/typeStore"; import { Color4 } from "../Maths/math.color"; import type { PBRMaterial } from "../Materials/PBR/pbrMaterial"; -import "../Shaders/glowMapMerge.fragment"; -import "../Shaders/glowMapMerge.vertex"; import "../Layers/effectLayerSceneComponent"; import { SerializationHelper } from "../Misc/decorators.serialization"; import { GetExponentOfTwo } from "../Misc/tools.functions"; +import { ShaderLanguage } from "core/Materials/shaderLanguage"; declare module "../abstractScene" { export interface AbstractScene { @@ -231,6 +230,23 @@ export class GlowLayer extends EffectLayer { }); } + protected override async _initShaderSourceAsync(forceGLSL = false) { + const engine = this._scene.getEngine(); + + if (engine.isWebGPU && !forceGLSL && !EffectLayer.ForceGLSL) { + this._shaderLanguage = ShaderLanguage.WGSL; + await Promise.all([ + import("../ShadersWGSL/glowMapMerge.fragment"), + import("../ShadersWGSL/glowMapMerge.vertex"), + import("../ShadersWGSL/glowBlurPostProcess.fragment"), + ]); + } else { + await Promise.all([import("../Shaders/glowMapMerge.fragment"), import("../Shaders/glowMapMerge.vertex"), import("../Shaders/glowBlurPostProcess.fragment")]); + } + + await super._initShaderSourceAsync(forceGLSL); + } + /** * Get the effect name of the layer. * @returns The effect name @@ -251,7 +267,18 @@ export class GlowLayer extends EffectLayer { } // Effect - return this._engine.createEffect("glowMapMerge", [VertexBuffer.PositionKind], ["offset"], ["textureSampler", "textureSampler2"], defines); + return this._engine.createEffect( + "glowMapMerge", + [VertexBuffer.PositionKind], + ["offset"], + ["textureSampler", "textureSampler2"], + defines, + undefined, + undefined, + undefined, + undefined, + this.shaderLanguage + ); } /** diff --git a/packages/dev/core/src/Layers/highlightLayer.ts b/packages/dev/core/src/Layers/highlightLayer.ts index 3e0eaa6cc96..06d8dc3b921 100644 --- a/packages/dev/core/src/Layers/highlightLayer.ts +++ b/packages/dev/core/src/Layers/highlightLayer.ts @@ -26,12 +26,9 @@ import { Logger } from "../Misc/logger"; import { RegisterClass } from "../Misc/typeStore"; import { Color4, Color3 } from "../Maths/math.color"; -import "../Shaders/glowMapMerge.fragment"; -import "../Shaders/glowMapMerge.vertex"; -import "../Shaders/glowBlurPostProcess.fragment"; -import "../Layers/effectLayerSceneComponent"; import { SerializationHelper } from "../Misc/decorators.serialization"; import { GetExponentOfTwo } from "../Misc/tools.functions"; +import { ShaderLanguage } from "core/Materials/shaderLanguage"; declare module "../abstractScene" { export interface AbstractScene { @@ -54,6 +51,10 @@ AbstractScene.prototype.getHighlightLayerByName = function (name: string): Nulla return null; }; +interface IBlurPostProcess extends PostProcess { + kernel: number; +} + /** * Special Glow Blur post process only blurring the alpha channel * It enforces keeping the most luminous color in the color channel. @@ -69,7 +70,25 @@ class GlowBlurPostProcess extends PostProcess { engine?: AbstractEngine, reusable?: boolean ) { - super(name, "glowBlurPostProcess", ["screenSize", "direction", "blurWidth"], null, options, camera, samplingMode, engine, reusable); + super( + name, + "glowBlurPostProcess", + ["screenSize", "direction", "blurWidth"], + null, + options, + camera, + samplingMode, + engine, + reusable, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + true + ); this.onApplyObservable.add((effect: Effect) => { effect.setFloat2("screenSize", this.width, this.height); @@ -77,6 +96,21 @@ class GlowBlurPostProcess extends PostProcess { effect.setFloat("blurWidth", this.kernel); }); } + + protected override async _initShaderSourceAsync(forceGLSL = false) { + const engine = this.getEngine(); + + this._shadersLoaded = false; + if (engine.isWebGPU && !forceGLSL) { + this._shaderLanguage = ShaderLanguage.WGSL; + + await import("../ShadersWGSL/glowBlurPostProcess.fragment"); + } else { + await import("../Shaders/glowBlurPostProcess.fragment"); + } + + this._shadersLoaded = true; + } } /** @@ -135,6 +169,11 @@ export interface IHighlightLayerOptions { * The type of the main texture. Default: TEXTURETYPE_UNSIGNED_INT */ mainTextureType: number; + + /** + * Use the GLSL code generation for the shader (even on WebGPU). Default is false + */ + forceGLSL: boolean; } /** @@ -275,8 +314,8 @@ export class HighlightLayer extends EffectLayer { @serialize("options") private _options: IHighlightLayerOptions; private _downSamplePostprocess: PassPostProcess; - private _horizontalBlurPostprocess: GlowBlurPostProcess; - private _verticalBlurPostprocess: GlowBlurPostProcess; + private _horizontalBlurPostprocess: IBlurPostProcess; + private _verticalBlurPostprocess: IBlurPostProcess; private _blurTexture: RenderTargetTexture; private _meshes: Nullable<{ [id: string]: Nullable }> = {}; @@ -293,7 +332,8 @@ export class HighlightLayer extends EffectLayer { scene?: Scene, options?: Partial ) { - super(name, scene); + super(name, scene, options !== undefined ? !!options.forceGLSL : false); + this.neutralColor = HighlightLayer.NeutralColor; // Warn on stencil @@ -311,6 +351,7 @@ export class HighlightLayer extends EffectLayer { camera: null, renderingGroupId: -1, mainTextureType: Constants.TEXTURETYPE_UNSIGNED_INT, + forceGLSL: false, ...options, }; @@ -328,6 +369,23 @@ export class HighlightLayer extends EffectLayer { this._shouldRender = false; } + protected override async _initShaderSourceAsync(forceGLSL = false) { + const engine = this._scene.getEngine(); + + if (engine.isWebGPU && !forceGLSL && !EffectLayer.ForceGLSL) { + this._shaderLanguage = ShaderLanguage.WGSL; + await Promise.all([ + import("../ShadersWGSL/glowMapMerge.fragment"), + import("../ShadersWGSL/glowMapMerge.vertex"), + import("../ShadersWGSL/glowBlurPostProcess.fragment"), + ]); + } else { + await Promise.all([import("../Shaders/glowMapMerge.fragment"), import("../Shaders/glowMapMerge.vertex"), import("../Shaders/glowBlurPostProcess.fragment")]); + } + + await super._initShaderSourceAsync(forceGLSL); + } + /** * Get the effect name of the layer. * @returns The effect name @@ -347,7 +405,18 @@ export class HighlightLayer extends EffectLayer { */ protected _createMergeEffect(): Effect { // Effect - return this._engine.createEffect("glowMapMerge", [VertexBuffer.PositionKind], ["offset"], ["textureSampler"], this._options.isStroke ? "#define STROKE \n" : undefined); + return this._engine.createEffect( + "glowMapMerge", + [VertexBuffer.PositionKind], + ["offset"], + ["textureSampler"], + this._options.isStroke ? "#define STROKE \n" : undefined, + undefined, + undefined, + undefined, + undefined, + this._shaderLanguage + ); } /** @@ -441,10 +510,11 @@ export class HighlightLayer extends EffectLayer { false, textureType ); - this._horizontalBlurPostprocess.width = blurTextureWidth; - this._horizontalBlurPostprocess.height = blurTextureHeight; - this._horizontalBlurPostprocess.externalTextureSamplerBinding = true; - this._horizontalBlurPostprocess.onApplyObservable.add((effect) => { + const horizontalBlurPostprocess = this._horizontalBlurPostprocess as BlurPostProcess; + horizontalBlurPostprocess.width = blurTextureWidth; + horizontalBlurPostprocess.height = blurTextureHeight; + horizontalBlurPostprocess.externalTextureSamplerBinding = true; + horizontalBlurPostprocess.onApplyObservable.add((effect) => { effect.setTexture("textureSampler", this._mainTexture); }); diff --git a/packages/dev/core/src/Layers/index.ts b/packages/dev/core/src/Layers/index.ts index f4a7b0a8e50..e1eb8eb7e1f 100644 --- a/packages/dev/core/src/Layers/index.ts +++ b/packages/dev/core/src/Layers/index.ts @@ -4,3 +4,17 @@ export * from "./glowLayer"; export * from "./highlightLayer"; export * from "./layer"; export * from "./layerSceneComponent"; + +// EffectLayer +export * from "../Shaders/glowMapGeneration.fragment"; +export * from "../Shaders/glowMapGeneration.vertex"; +export * from "../ShadersWGSL/glowMapGeneration.fragment"; +export * from "../ShadersWGSL/glowMapGeneration.vertex"; + +// Highlights +export * from "../Shaders/glowMapMerge.fragment"; +export * from "../Shaders/glowMapMerge.vertex"; +export * from "../Shaders/glowBlurPostProcess.fragment"; +export * from "../ShadersWGSL/glowMapMerge.fragment"; +export * from "../ShadersWGSL/glowMapMerge.vertex"; +export * from "../ShadersWGSL/glowBlurPostProcess.fragment"; diff --git a/packages/dev/core/src/PostProcesses/blurPostProcess.ts b/packages/dev/core/src/PostProcesses/blurPostProcess.ts index 86eb0a13154..6d57bc627d7 100644 --- a/packages/dev/core/src/PostProcesses/blurPostProcess.ts +++ b/packages/dev/core/src/PostProcesses/blurPostProcess.ts @@ -30,12 +30,6 @@ export class BlurPostProcess extends PostProcess { protected _packedFloat: boolean = false; private _staticDefines: string = ""; - /** - * Force all the postprocess to compile to glsl even on WebGPU engines. - * False by default. This is mostly meant for backward compatibility. - */ - public static ForceGLSL = false; - /** The direction in which to blur the image. */ @serializeAsVector2() public direction: Vector2; @@ -105,7 +99,6 @@ export class BlurPostProcess extends PostProcess { * @param defines * @param _blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false) * @param textureFormat Format of textures used when performing the post process. (default: TEXTUREFORMAT_RGBA) - * @param forceGLSL defines a boolean indicating if the shader must be compiled in GLSL even if we are using WebGPU */ constructor( name: string, @@ -119,8 +112,7 @@ export class BlurPostProcess extends PostProcess { textureType = Constants.TEXTURETYPE_UNSIGNED_INT, defines = "", private _blockCompilation = false, - textureFormat = Constants.TEXTUREFORMAT_RGBA, - forceGLSL = false + textureFormat = Constants.TEXTUREFORMAT_RGBA ) { super( name, @@ -137,9 +129,10 @@ export class BlurPostProcess extends PostProcess { "kernelBlur", { varyingCount: 0, depCount: 0 }, true, - textureFormat + textureFormat, + undefined, + true ); - this._initShaderSourceAsync(forceGLSL); this._staticDefines = defines; this.direction = direction; this.onApplyObservable.add((effect: Effect) => { @@ -153,11 +146,11 @@ export class BlurPostProcess extends PostProcess { this.kernel = kernel; } - private _shadersLoaded = false; - private async _initShaderSourceAsync(forceGLSL = false) { + protected override async _initShaderSourceAsync(forceGLSL = false) { const engine = this.getEngine(); - if (engine.isWebGPU && !forceGLSL && !BlurPostProcess.ForceGLSL) { + this._shadersLoaded = false; + if (engine.isWebGPU && !forceGLSL) { this._shaderLanguage = ShaderLanguage.WGSL; await Promise.all([import("../ShadersWGSL/kernelBlur.fragment"), import("../ShadersWGSL/kernelBlur.vertex")]); diff --git a/packages/dev/core/src/PostProcesses/index.ts b/packages/dev/core/src/PostProcesses/index.ts index 65dbe14ec1f..fea14e87766 100644 --- a/packages/dev/core/src/PostProcesses/index.ts +++ b/packages/dev/core/src/PostProcesses/index.ts @@ -38,3 +38,9 @@ export * from "../Shaders/kernelBlur.fragment"; export * from "../Shaders/kernelBlur.vertex"; export * from "../ShadersWGSL/kernelBlur.fragment"; export * from "../ShadersWGSL/kernelBlur.vertex"; + +// Pass postprocess +export * from "../Shaders/pass.fragment"; +export * from "../Shaders/passCube.fragment"; +export * from "../ShadersWGSL/pass.fragment"; +export * from "../ShadersWGSL/passCube.fragment"; diff --git a/packages/dev/core/src/PostProcesses/passPostProcess.ts b/packages/dev/core/src/PostProcesses/passPostProcess.ts index ab5b1d5894d..4083b89f6e5 100644 --- a/packages/dev/core/src/PostProcesses/passPostProcess.ts +++ b/packages/dev/core/src/PostProcesses/passPostProcess.ts @@ -11,6 +11,7 @@ import { RegisterClass } from "../Misc/typeStore"; import { SerializationHelper } from "../Misc/decorators.serialization"; import type { Scene } from "../scene"; +import { ShaderLanguage } from "core/Materials/shaderLanguage"; /** * PassPostProcess which produces an output the same as it's input @@ -45,7 +46,23 @@ export class PassPostProcess extends PostProcess { textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false ) { - super(name, "pass", null, null, options, camera, samplingMode, engine, reusable, undefined, textureType, undefined, null, blockCompilation); + super(name, "pass", null, null, options, camera, samplingMode, engine, reusable, undefined, textureType, undefined, null, blockCompilation, undefined, undefined, true); + } + + protected override async _initShaderSourceAsync(forceGLSL = false) { + const engine = this.getEngine(); + + this._shadersLoaded = false; + + if (engine.isWebGPU && !forceGLSL) { + this._shaderLanguage = ShaderLanguage.WGSL; + + await Promise.all([import("../ShadersWGSL/pass.fragment")]); + } else { + await Promise.all([import("../Shaders/pass.fragment")]); + } + + this._shadersLoaded = true; } /** @@ -148,7 +165,39 @@ export class PassCubePostProcess extends PostProcess { textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false ) { - super(name, "passCube", null, null, options, camera, samplingMode, engine, reusable, "#define POSITIVEX", textureType, undefined, null, blockCompilation); + super( + name, + "passCube", + null, + null, + options, + camera, + samplingMode, + engine, + reusable, + "#define POSITIVEX", + textureType, + undefined, + null, + blockCompilation, + undefined, + undefined, + true + ); + } + + protected override async _initShaderSourceAsync(forceGLSL = false) { + const engine = this.getEngine(); + this._shadersLoaded = false; + if (engine.isWebGPU && !forceGLSL) { + this._shaderLanguage = ShaderLanguage.WGSL; + + await Promise.all([import("../ShadersWGSL/passCube.fragment")]); + } else { + await Promise.all([import("../Shaders/passCube.fragment")]); + } + + this._shadersLoaded = true; } /** diff --git a/packages/dev/core/src/PostProcesses/postProcess.ts b/packages/dev/core/src/PostProcesses/postProcess.ts index 4ef496036ff..df0f2e8f5f1 100644 --- a/packages/dev/core/src/PostProcesses/postProcess.ts +++ b/packages/dev/core/src/PostProcesses/postProcess.ts @@ -215,6 +215,12 @@ type TextureCache = { texture: RenderTargetWrapper; postProcessChannel: number; * See https://doc.babylonjs.com/features/featuresDeepDive/postProcesses/usePostProcesses */ export class PostProcess { + /** + * Force all the postprocesses to compile to glsl even on WebGPU engines. + * False by default. This is mostly meant for backward compatibility. + */ + public static ForceGLSL = false; + /** @internal */ public _parentContainer: Nullable = null; @@ -372,6 +378,8 @@ export class PostProcess { protected _scene: Scene; private _engine: AbstractEngine; + protected _shadersLoaded = true; + private _options: number | { width: number; height: number }; private _reusable = false; private _renderId = 0; @@ -605,7 +613,8 @@ export class PostProcess { indexParameters?: any, blockCompilation?: boolean, textureFormat?: number, - shaderLanguage?: ShaderLanguage + shaderLanguage?: ShaderLanguage, + dealyLoadShaders?: boolean ); /** @internal */ @@ -625,7 +634,8 @@ export class PostProcess { indexParameters?: any, blockCompilation = false, textureFormat = Constants.TEXTUREFORMAT_RGBA, - shaderLanguage = ShaderLanguage.GLSL + shaderLanguage = ShaderLanguage.GLSL, + dealyLoadShaders = false ) { this.name = name; let size: number | { width: number; height: number } = 1; @@ -688,6 +698,16 @@ export class PostProcess { this._indexParameters = indexParameters; this._drawWrapper = new DrawWrapper(this._engine); + this._postConstructor(blockCompilation, defines, dealyLoadShaders); + } + + protected async _initShaderSourceAsync(_forceGLSL = false) {} + + private async _postConstructor(blockCompilation: boolean, defines: Nullable = null, dealyLoadShaders: boolean = false) { + if (dealyLoadShaders) { + await this._initShaderSourceAsync(PostProcess.ForceGLSL); + } + if (!blockCompilation) { this.updateEffect(defines); } @@ -1047,6 +1067,9 @@ export class PostProcess { * @returns true if the post-process is ready (shader is compiled) */ public isReady(): boolean { + if (!this._shadersLoaded) { + return false; + } return this._drawWrapper.effect?.isReady() ?? false; } diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBRDFFunctions.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBRDFFunctions.fx index 257affba85b..37ccca12453 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBRDFFunctions.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/pbrBRDFFunctions.fx @@ -23,7 +23,7 @@ var brdfLookup: vec4f = textureSample(environmentBrdfSampler, environmentBrdfSamplerSampler, UV); #ifdef ENVIRONMENTBRDF_RGBD - brdfLookup.rgb = fromRGBD(brdfLookup.rgba); + brdfLookup = vec4f(fromRGBD(brdfLookup.rgba), brdfLookup.a); #endif return brdfLookup.rgb; diff --git a/packages/dev/core/src/ShadersWGSL/glowBlurPostProcess.fragment.fx b/packages/dev/core/src/ShadersWGSL/glowBlurPostProcess.fragment.fx new file mode 100644 index 00000000000..b25fdb05450 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/glowBlurPostProcess.fragment.fx @@ -0,0 +1,54 @@ +// Samplers +varying vUV: vec2f; +var textureSamplerSampler: sampler; +var textureSampler: texture_2d; + +// Parameters +uniform screenSize: vec2f; +uniform direction: vec2f; +uniform blurWidth: f32; + +// Transform color to luminance. +fn getLuminance(color: vec3f) -> f32 +{ + return dot(color, vec3f(0.2126, 0.7152, 0.0722)); +} + + +#define CUSTOM_FRAGMENT_DEFINITIONS + +@fragment +fn main(input: FragmentInputs) -> FragmentOutputs { + var weights: array; + weights[0] = 0.05; + weights[1] = 0.1; + weights[2] = 0.2; + weights[3] = 0.3; + weights[4] = 0.2; + weights[5] = 0.1; + weights[6] = 0.05; + + var texelSize: vec2f = vec2f(1.0 / uniforms.screenSize.x, 1.0 / uniforms.screenSize.y); + var texelStep: vec2f = texelSize * uniforms.direction * uniforms.blurWidth; + var start: vec2f = input.vUV - 3.0 * texelStep; + + var baseColor: vec4f = vec4f(0., 0., 0., 0.); + var texelOffset: vec2f = vec2f(0., 0.); + + for (var i: i32 = 0; i < 7; i++) + { + // alpha blur. + var texel: vec4f = textureSample(textureSampler, textureSamplerSampler, start + texelOffset); + baseColor = vec4f(baseColor.rgb, baseColor.a + texel.a * weights[i]); + + // Highest Luma for outline. + var luminance: f32 = getLuminance(baseColor.rgb); + var luminanceTexel: f32 = getLuminance(texel.rgb); + var choice: f32 = step(luminanceTexel, luminance); + baseColor = vec4f(choice * baseColor.rgb + (1.0 - choice) * texel.rgb, baseColor.a); + + texelOffset += texelStep; + } + + fragmentOutputs.color = baseColor; +} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/glowMapGeneration.fragment.fx b/packages/dev/core/src/ShadersWGSL/glowMapGeneration.fragment.fx new file mode 100644 index 00000000000..3ad05fe9455 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/glowMapGeneration.fragment.fx @@ -0,0 +1,95 @@ +#if defined(DIFFUSE_ISLINEAR) || defined(EMISSIVE_ISLINEAR) + #include +#endif + +#ifdef DIFFUSE +varying vUVDiffuse: vec2f; +var diffuseSamplerSampler: sampler; +var diffuseSampler: texture_2d; +#endif + +#ifdef OPACITY +varying vUVOpacity: vec2f; +var opacitySamplerSampler: sampler; +var opacitySampler: texture_2d; +uniform var opacityIntensity: f32; +#endif + +#ifdef EMISSIVE +varying vUVEmissive: vec2f; +var emissiveSamplerSampler: sampler; +var emissiveSampler: texture_2d; +#endif + +#ifdef VERTEXALPHA + varying vColor: vec4f; +#endif + +uniform glowColor: vec4f; +uniform glowIntensity: f32; + +#include + +#define CUSTOM_FRAGMENT_DEFINITIONS + +@fragment +fn main(input: FragmentInputs) -> FragmentOutputs { + +#include + +var finalColor: vec4f = uniforms.glowColor; + +// _____________________________ Alpha Information _______________________________ +#ifdef DIFFUSE + var albedoTexture: vec4f = textureSample(diffuseSampler, diffuseSamplerSampler, fragmentInputs.vUVDiffuse); + #ifdef DIFFUSE_ISLINEAR + albedoTexture = toGammaSpace(albedoTexture); + #endif + + #ifdef GLOW + // In glow mode a is used to dim the opacity + finalColor = vec4f(finalColor.rgb, finalColor.a * albedoTexture.a); + #endif + + #ifdef HIGHLIGHT + // While in highlight mode we only use the 3 colors + finalColor = vec4f(finalColor.rgb, albedoTexture.a); + #endif +#endif + +#ifdef OPACITY + var opacityMap: vec4f = textureSample(opacitySampler, opacitySamplerSampler, fragmentInputs.vUVOpacity); + + #ifdef OPACITYRGB + finalColor = vec4f(finalColor.rgb, finalColor.a * getLuminance(opacityMap.rgb)); + #else + finalColor = vec4f(finalColor.rgb, finalColor.a * opacityMap.a); + #endif + + finalColor = vec4f(finalColor.rgb, finalColor.a * opacityIntensity); +#endif + +#ifdef VERTEXALPHA + finalColor = vec4f(finalColor.rgb, finalColor.a * vColor.a); +#endif + +#ifdef ALPHATEST + if (finalColor.a < ALPHATESTVALUE) + discard; +#endif + +#ifdef EMISSIVE + var emissive: vec4f = textureSample(emissiveSampler, emissiveSamplerSampler, fragmentInputs.vUVEmissive); + #ifdef EMISSIVE_ISLINEAR + emissive = toGammaSpace(emissive); + #endif + fragmentOutputs.color = emissive * finalColor * uniforms.glowIntensity; +#else + fragmentOutputs.color = finalColor * uniforms.glowIntensity; +#endif + +#ifdef HIGHLIGHT + // a should stay untouched from the setup in highlight mode. + fragmentOutputs.color = vec4f(fragmentOutputs.color.rgb, uniforms.glowColor.a); +#endif +} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/glowMapGeneration.vertex.fx b/packages/dev/core/src/ShadersWGSL/glowMapGeneration.vertex.fx new file mode 100644 index 00000000000..638914bd19f --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/glowMapGeneration.vertex.fx @@ -0,0 +1,107 @@ +// Attribute +attribute position: vec3f; + +#include +#include + +#include +#include[0..maxSimultaneousMorphTargets] + +#include + +// Uniforms +#include + +uniform viewProjection: mat4x4f; + +varying vPosition: vec4f; + +#ifdef UV1 +attribute uv: vec2f; +#endif + +#ifdef UV2 +attribute uv2: vec2f; +#endif + +#ifdef DIFFUSE + varying vUVDiffuse: vec2f; + uniform diffuseMatrix: mat4x4f; +#endif + +#ifdef OPACITY + varying vUVOpacity: vec2f; + uniform opacityMatrix: mat4x4f; +#endif + +#ifdef EMISSIVE + varying vUVEmissive: vec2f; + uniform emissiveMatrix: mat4x4f; +#endif + +#ifdef VERTEXALPHA + attribute color: vec4f; + varying vColor: vec4f; +#endif + + +#define CUSTOM_VERTEX_DEFINITIONS + +@vertex +fn main(input : VertexInputs) -> FragmentInputs { + var positionUpdated: vec3f = input.position; +#ifdef UV1 + var uvUpdated: vec2f = input.uv; +#endif + +#include +#include[0..maxSimultaneousMorphTargets] + +#include +#include +#include + +var worldPos: vec4f = finalWorld * vec4f(positionUpdated, 1.0); + +#ifdef CUBEMAP + vertexOutputs.vPosition = worldPos; + vertexOutputs.position = uniforms.viewProjection * finalWorld * vec4f(input.position, 1.0); +#else + vertexOutputs.vPosition = uniforms.viewProjection * worldPos; + vertexOutputs.position = vertexOutputs.vPosition; +#endif + +#ifdef DIFFUSE + #ifdef DIFFUSEUV1 + vertexOutputs.vUVDiffuse = (uniforms.diffuseMatrix * vec4f(uvUpdated, 1.0, 0.0)).xy; + #endif + #ifdef DIFFUSEUV2 + vertexOutputs.vUVDiffuse = (uniforms.diffuseMatrix * vec4f(input.uv2, 1.0, 0.0)).xy; + #endif +#endif + +#ifdef OPACITY + #ifdef OPACITYUV1 + vertexOutputs.vUVOpacity = (uniforms.opacityMatrix * vec4f(uvUpdated, 1.0, 0.0)).xy; + #endif + #ifdef OPACITYUV2 + vertexOutputs.vUVOpacity = (uniforms.opacityMatrix * vec4f(input.uv2, 1.0, 0.0)).xy; + #endif +#endif + +#ifdef EMISSIVE + #ifdef EMISSIVEUV1 + vertexOutputs.vUVEmissive = (uniforms.emissiveMatrix * vec4f(uvUpdated, 1.0, 0.0)).xy; + #endif + #ifdef EMISSIVEUV2 + vertexOutputs.vUVEmissive = (uniforms.emissiveMatrix * vec4f(input.uv2, 1.0, 0.0)).xy; + #endif +#endif + +#ifdef VERTEXALPHA + vertexOutputs.vColor = color; +#endif + +#include + +} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/glowMapMerge.fragment.fx b/packages/dev/core/src/ShadersWGSL/glowMapMerge.fragment.fx new file mode 100644 index 00000000000..48aaeecfc49 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/glowMapMerge.fragment.fx @@ -0,0 +1,42 @@ +// Samplers +varying vUV: vec2f; +var textureSamplerSampler: sampler; +var textureSampler: texture_2d; +#ifdef EMISSIVE + var textureSampler2Sampler: sampler; + var textureSampler2: texture_2d; +#endif + +// Offset +uniform offset: f32; + + +#define CUSTOM_FRAGMENT_DEFINITIONS + +@fragment +fn main(input: FragmentInputs) -> FragmentOutputs { + +#define CUSTOM_FRAGMENT_MAIN_BEGIN + + var baseColor: vec4f = textureSample(textureSampler, textureSamplerSampler, input.vUV); + + #ifdef EMISSIVE + baseColor += textureSample(textureSampler2, textureSampler2Sampler, input.vUV); + baseColor *= uniforms.offset; + #else + baseColor = vec4f(baseColor.rgb, abs(uniforms.offset - baseColor.a)); + + #ifdef STROKE + var alpha: f32 = smoothstep(.0, .1, baseColor.a); + baseColor = vec4f(baseColor.rgb * alpha, alpha); + #endif + #endif + + #if LDR + baseColor = clamp(baseColor, 0., 1.0); + #endif + + fragmentOutputs.color = baseColor; + +#define CUSTOM_FRAGMENT_MAIN_END +} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/glowMapMerge.vertex.fx b/packages/dev/core/src/ShadersWGSL/glowMapMerge.vertex.fx new file mode 100644 index 00000000000..4cd4ef61264 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/glowMapMerge.vertex.fx @@ -0,0 +1,19 @@ +// Attributes +attribute position: vec2f; + +// Output +varying vUV: vec2f; + +#define CUSTOM_VERTEX_DEFINITIONS + +@vertex +fn main(input : VertexInputs) -> FragmentInputs { + const madd: vec2f = vec2f(0.5, 0.5); + +#define CUSTOM_VERTEX_MAIN_BEGIN + + vertexOutputs.vUV = input.position * madd + madd; + vertexOutputs.position = vec4f(input.position, 0.0, 1.0); + +#define CUSTOM_VERTEX_MAIN_END +} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/pass.fragment.fx b/packages/dev/core/src/ShadersWGSL/pass.fragment.fx new file mode 100644 index 00000000000..ae773521297 --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/pass.fragment.fx @@ -0,0 +1,12 @@ +// Samplers +varying vUV: vec2f; +var textureSamplerSampler: sampler; +var textureSampler: texture_2d; + + +#define CUSTOM_FRAGMENT_DEFINITIONS + +@fragment +fn main(input: FragmentInputs) -> FragmentOutputs { + fragmentOutputs.color = textureSample(textureSampler, textureSamplerSampler, input.vUV); +} \ No newline at end of file diff --git a/packages/dev/core/src/ShadersWGSL/passCube.fragment.fx b/packages/dev/core/src/ShadersWGSL/passCube.fragment.fx new file mode 100644 index 00000000000..a7f2a5b552e --- /dev/null +++ b/packages/dev/core/src/ShadersWGSL/passCube.fragment.fx @@ -0,0 +1,30 @@ +// Samplers +varying var vUV: vec2f; +var textureSamplerSampler: sampler; +var textureSampler: texture_cube; + + +#define CUSTOM_FRAGMENT_DEFINITIONS +@fragment +fn main(input: FragmentInputs) -> FragmentOutputs { + var uv: vec2f = input.vUV * 2.0 - 1.0; + +#ifdef POSITIVEX + fragmentOutputs.color = textureSample(textureSampler, textureSamplerSampler, vec3f(1.001, uv.y, uv.x)); +#endif +#ifdef NEGATIVEX + fragmentOutputs.color = textureSample(textureSampler, textureSamplerSampler, vec3f(-1.001, uv.y, uv.x)); +#endif +#ifdef POSITIVEY + fragmentOutputs.color = textureSample(textureSampler, textureSamplerSampler, vec3f(uv.y, 1.001, uv.x)); +#endif +#ifdef NEGATIVEY + fragmentOutputs.color = textureSample(textureSampler, textureSamplerSampler, vec3f(uv.y, -1.001, uv.x)); +#endif +#ifdef POSITIVEZ + fragmentOutputs.color = textureSample(textureSampler, textureSamplerSampler, vec3f(uv, 1.001)); +#endif +#ifdef NEGATIVEZ + fragmentOutputs.color = textureSample(textureSampler, textureSamplerSampler, vec3f(uv, -1.001)); +#endif +} \ No newline at end of file