diff --git a/e2e/case/camera-ssao.ts b/e2e/case/camera-ssao.ts index 200d0f9ce..6992f91ed 100644 --- a/e2e/case/camera-ssao.ts +++ b/e2e/case/camera-ssao.ts @@ -4,8 +4,10 @@ */ import { AmbientLight, + AmbientOcclusionQuality, AssetType, BackgroundMode, + BlendFactor, Camera, Color, DirectLight, @@ -13,20 +15,33 @@ import { MeshRenderer, PBRMaterial, PrimitiveMesh, + RenderQueueType, + Shader, SkyBoxMaterial, - AmbientOcclusionQuality, Vector3, WebGLEngine, WebGLMode } from "@galacean/engine"; +import { PBRSource, registerIncludes } from "@galacean/engine-shader"; +import { ShaderLab } from "@galacean/engine-shaderlab"; import { initScreenshot, updateForE2E } from "./.mockForE2E"; Logger.enable(); -WebGLEngine.create({ canvas: "canvas", graphicDeviceOptions: { webGLMode: WebGLMode.WebGL1 } }).then((engine) => { + +registerIncludes(); + +// Create engine +WebGLEngine.create({ + canvas: "canvas", + shaderLab: new ShaderLab(), + graphicDeviceOptions: { webGLMode: WebGLMode.WebGL1 } +}).then((engine) => { engine.canvas.resizeByClientSize(2); + const scene = engine.sceneManager.activeScene; const rootEntity = scene.createRootEntity(); - const { ambientLight, background } = scene; + + const pbrShader = Shader.create(PBRSource); // camera const cameraEntity = rootEntity.createChild("camera_node"); @@ -34,46 +49,62 @@ WebGLEngine.create({ canvas: "canvas", graphicDeviceOptions: { webGLMode: WebGLM const camera = cameraEntity.addComponent(Camera); scene.ambientOcclusion.enabled = true; - // scene.ambientOcclusion.radius = 0.4; - // scene.ambientOcclusion.intensity = 3; - // scene.ambientOcclusion.power = 1.0; - // scene.ambientOcclusion.bias = 0.0005; - // scene.ambientOcclusion.bilateralThreshold = 0.01; scene.ambientOcclusion.quality = AmbientOcclusionQuality.High; const lightNode = rootEntity.createChild("light_node"); lightNode.addComponent(DirectLight).color = new Color(1, 1, 1); lightNode.transform.rotate(new Vector3(-45, 60, 0)); + const { background } = scene; const sky = background.sky; const skyMaterial = new SkyBoxMaterial(engine); background.mode = BackgroundMode.Sky; sky.material = skyMaterial; sky.mesh = PrimitiveMesh.createCuboid(engine, 1, 1, 1); + // Sphere const sphereMaterial = new PBRMaterial(engine); sphereMaterial.baseColor = new Color(1, 1, 1, 1); + sphereMaterial.shader = pbrShader; + sphereMaterial.shaderData.setInt("depthWriteEnabled", 1); const sphere = rootEntity.createChild("sphere"); - const { transform } = sphere; - transform.setPosition(0, 1, 0); - transform.setRotation(45, 45, 0); + sphere.transform.setPosition(0, 1, 0); + sphere.transform.setRotation(45, 45, 0); const meshRenderer = sphere.addComponent(MeshRenderer); meshRenderer.mesh = PrimitiveMesh.createSubdivisionSurfaceSphere(engine); meshRenderer.setMaterial(sphereMaterial); - const box = rootEntity.createChild("box"); + // Box const boxMaterial = new PBRMaterial(engine); boxMaterial.baseColor = new Color(1, 1, 1, 1); + boxMaterial.shader = pbrShader; + boxMaterial.shaderData.setInt("depthWriteEnabled", 1); + const box = rootEntity.createChild("box"); box.transform.setPosition(1, 0.9, 0.1); box.transform.setRotation(30, 30, 0); const boxMeshRenderer = box.addComponent(MeshRenderer); boxMeshRenderer.mesh = PrimitiveMesh.createCuboid(engine); boxMeshRenderer.setMaterial(boxMaterial); - const capsule = rootEntity.createChild("capsule"); + // Capsule (transparent) const capsuleMaterial = new PBRMaterial(engine); - capsuleMaterial.isTransparent = true; capsuleMaterial.baseColor = new Color(1, 1, 1, 0.5); + capsuleMaterial.isTransparent = true; + capsuleMaterial.shader = pbrShader; + { + const shaderData = capsuleMaterial.shaderData; + shaderData.setInt("depthWriteEnabled", 1); + shaderData.setInt("blendEnabled", 1); + shaderData.setInt("renderQueueType", RenderQueueType.Transparent); + shaderData.enableMacro("MATERIAL_IS_TRANSPARENT"); + + shaderData.setInt("sourceColorBlendFactor", BlendFactor.SourceAlpha); + shaderData.setInt("destinationColorBlendFactor", BlendFactor.OneMinusSourceAlpha); + shaderData.setInt("sourceAlphaBlendFactor", BlendFactor.One); + shaderData.setInt("destinationAlphaBlendFactor", BlendFactor.OneMinusSourceAlpha); + } + + const capsule = rootEntity.createChild("capsule"); capsule.transform.setPosition(1, 0.9, 0.1); capsule.transform.setRotation(30, 30, 0); const capsuleMeshRenderer = capsule.addComponent(MeshRenderer); diff --git a/packages/shader/src/shaders/Common.glsl b/packages/shader/src/shaders/Common.glsl index 3e6d8e618..21fba2277 100644 --- a/packages/shader/src/shaders/Common.glsl +++ b/packages/shader/src/shaders/Common.glsl @@ -69,10 +69,26 @@ vec4 outputSRGBCorrection(vec4 linearIn){ vec4 camera_DepthBufferParams; -float remapDepthBufferLinear01(float z){ - return 1.0/ (camera_DepthBufferParams.x * z + camera_DepthBufferParams.y); +float remapDepthBufferLinear01(float depth){ + return 1.0 / (camera_DepthBufferParams.x * depth + camera_DepthBufferParams.y); } +float remapDepthBufferEyeDepth(float depth){ + #ifdef CAMERA_ORTHOGRAPHIC + return camera_ProjectionParams.y + (camera_ProjectionParams.z - camera_ProjectionParams.y) * depth; + #else + return 1.0 / (camera_DepthBufferParams.z * depth + camera_DepthBufferParams.w); + #endif +} + +// From Next Generation Post Processing in Call of Duty: Advanced Warfare [Jimenez 2014] +// http://advances.realtimerendering.com/s2014/index.html +// sampleCoord must not be normalized (e.g. window coordinates) +float interleavedGradientNoise(vec2 sampleCoord) +{ + const vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189); + return fract(magic.z * fract(dot(sampleCoord, magic.xy))); +} #ifdef GRAPHICS_API_WEBGL2 #define INVERSE_MAT(mat) inverse(mat) diff --git a/packages/shader/src/shaders/PBR.gs b/packages/shader/src/shaders/PBR.gs index 049d72e9f..7ea0b81c5 100644 --- a/packages/shader/src/shaders/PBR.gs +++ b/packages/shader/src/shaders/PBR.gs @@ -90,6 +90,7 @@ Shader "PBRShaderName" { SubShader "Default" { UsePass "pbr/Default/ShadowCaster" + UsePass "pbr/Default/DepthOnly" Pass "Forward Pass" { Tags { pipelineStage = "Forward"} diff --git a/packages/shader/src/shaders/shadingPBR/BSDF.glsl b/packages/shader/src/shaders/shadingPBR/BSDF.glsl index 95087784d..06f0b5123 100644 --- a/packages/shader/src/shaders/shadingPBR/BSDF.glsl +++ b/packages/shader/src/shaders/shadingPBR/BSDF.glsl @@ -26,6 +26,7 @@ struct SurfaceData{ // geometry vec3 position; + vec4 positionCS; vec3 normal; #ifdef NEED_TANGENT @@ -426,6 +427,17 @@ vec3 envBRDFApprox(vec3 f0, float f90, float roughness, float dotNV ) { } #endif +#ifdef SCENE_ENABLE_AMBIENT_OCCLUSION + sampler2D camera_AOTexture; + float evaluateAmbientOcclusion(vec2 uv){ + #ifdef MATERIAL_IS_TRANSPARENT + return 1.0; + #else + return texture2D(camera_AOTexture, uv).r; + #endif + } +#endif + void initBSDFData(SurfaceData surfaceData, out BSDFData bsdfData){ vec3 albedoColor = surfaceData.albedoColor; float metallic = surfaceData.metallic; @@ -463,6 +475,11 @@ void initBSDFData(SurfaceData surfaceData, out BSDFData bsdfData){ bsdfData.diffuseAO = surfaceData.ambientOcclusion; + #ifdef SCENE_ENABLE_AMBIENT_OCCLUSION + float ambientAO = evaluateAmbientOcclusion((surfaceData.positionCS.xy / surfaceData.positionCS.w) * 0.5 + 0.5); + bsdfData.diffuseAO = min(bsdfData.diffuseAO, ambientAO); + #endif + #ifdef MATERIAL_ENABLE_CLEAR_COAT bsdfData.clearCoatRoughness = max(MIN_PERCEPTUAL_ROUGHNESS, min(surfaceData.clearCoatRoughness + getAARoughnessFactor(surfaceData.clearCoatNormal), 1.0)); bsdfData.clearCoatSpecularColor = vec3(0.04); diff --git a/packages/shader/src/shaders/shadingPBR/ForwardPassPBR.glsl b/packages/shader/src/shaders/shadingPBR/ForwardPassPBR.glsl index 6c88419af..99e441102 100644 --- a/packages/shader/src/shaders/shadingPBR/ForwardPassPBR.glsl +++ b/packages/shader/src/shaders/shadingPBR/ForwardPassPBR.glsl @@ -55,6 +55,8 @@ Varyings PBRVertex(Attributes attributes) { gl_Position = renderer_MVPMat * vertexInputs.positionOS; + varyings.positionCS = gl_Position; + return varyings; } diff --git a/packages/shader/src/shaders/shadingPBR/FragmentPBR.glsl b/packages/shader/src/shaders/shadingPBR/FragmentPBR.glsl index d1d4523e1..5f29c14e8 100644 --- a/packages/shader/src/shaders/shadingPBR/FragmentPBR.glsl +++ b/packages/shader/src/shaders/shadingPBR/FragmentPBR.glsl @@ -174,6 +174,7 @@ SurfaceData getSurfaceData(Varyings v, vec2 aoUV, bool isFrontFacing){ // Geometry surfaceData.position = v.positionWS; + surfaceData.positionCS = v.positionCS; #ifdef CAMERA_ORTHOGRAPHIC surfaceData.viewDir = -camera_Forward; diff --git a/packages/shader/src/shaders/shadingPBR/LightIndirectFunctions.glsl b/packages/shader/src/shaders/shadingPBR/LightIndirectFunctions.glsl index 877504515..9f71098ad 100644 --- a/packages/shader/src/shaders/shadingPBR/LightIndirectFunctions.glsl +++ b/packages/shader/src/shaders/shadingPBR/LightIndirectFunctions.glsl @@ -45,10 +45,10 @@ vec3 getLightProbeRadiance(SurfaceData surfaceData, vec3 normal, float roughness float evaluateSpecularOcclusion(float dotNV, float diffuseAO, float roughness){ float specularAOFactor = 1.0; - #if defined(MATERIAL_HAS_OCCLUSION_TEXTURE) && defined(SCENE_USE_SPECULAR_ENV) + #if (defined(MATERIAL_HAS_OCCLUSION_TEXTURE) || defined(SCENE_ENABLE_AMBIENT_OCCLUSION)) && defined(SCENE_USE_SPECULAR_ENV) specularAOFactor = saturate( pow(dotNV + diffuseAO, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + diffuseAO ); #endif return specularAOFactor; -} +} #endif \ No newline at end of file diff --git a/packages/shader/src/shaders/shadingPBR/VaryingsPBR.glsl b/packages/shader/src/shaders/shadingPBR/VaryingsPBR.glsl index bf111d43d..139cefb8c 100644 --- a/packages/shader/src/shaders/shadingPBR/VaryingsPBR.glsl +++ b/packages/shader/src/shaders/shadingPBR/VaryingsPBR.glsl @@ -29,6 +29,8 @@ struct Varyings{ #if defined(NEED_CALCULATE_SHADOWS) && (SCENE_SHADOW_CASCADED_COUNT == 1) vec3 shadowCoord; #endif + + vec4 positionCS; }; diff --git a/tests/src/shader-lab/ShaderLab.test.ts b/tests/src/shader-lab/ShaderLab.test.ts index f9f1cde62..98ba2625a 100644 --- a/tests/src/shader-lab/ShaderLab.test.ts +++ b/tests/src/shader-lab/ShaderLab.test.ts @@ -34,17 +34,18 @@ describe("ShaderLab", async () => { const shader = shaderLabVerbose._parseShaderSource(PBRSource); const subShader = shader.subShaders[0]; const passList = subShader.passes; - const pass1 = passList[1]; + const pass1 = passList[2]; // shader name expect(shader.name).to.equal("PBRShaderName"); expect(subShader.name).to.equal("Default"); expect(pass1.name).to.equal("Forward Pass"); - expect(passList.length).to.eq(2); + expect(passList.length).to.eq(3); // Pass expect(passList[0].isUsePass).to.be.true; - expect(passList[1].name).eq("Forward Pass"); + expect(passList[1].isUsePass).to.be.true; + expect(passList[2].name).eq("Forward Pass"); // renderState expect(pass1.renderStates).not.be.null;