diff --git a/packages/shader-shaderlab/README.md b/packages/shader-shaderlab/README.md new file mode 100644 index 0000000000..0bbc88fe5f --- /dev/null +++ b/packages/shader-shaderlab/README.md @@ -0,0 +1 @@ +A subpackage of `@galacean/engine`. \ No newline at end of file diff --git a/packages/shader-shaderlab/package.json b/packages/shader-shaderlab/package.json new file mode 100644 index 0000000000..04a3e9060e --- /dev/null +++ b/packages/shader-shaderlab/package.json @@ -0,0 +1,36 @@ +{ + "name": "@galacean/engine-shader-shaderlab", + "version": "1.4.0-alpha.0", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, + "repository": { + "url": "https://github.com/galacean/engine.git" + }, + "license": "MIT", + "main": "dist/main.js", + "module": "dist/module.js", + "debug": "src/index.ts", + "browser": "dist/browser.js", + "types": "types/index.d.ts", + "scripts": { + "b:types": "tsc" + }, + "umd": { + "name": "Galacean.ShaderShaderLab", + "globals": { + "@galacean/engine": "Galacean" + } + }, + "files": [ + "dist/**/*", + "types/**/*" + ], + "devDependencies": { + "@galacean/engine": "workspace:*" + }, + "peerDependencies": { + "@galacean/engine": "workspace:*" + } +} diff --git a/packages/shader-shaderlab/src/global.d.ts b/packages/shader-shaderlab/src/global.d.ts new file mode 100644 index 0000000000..d0abf1234f --- /dev/null +++ b/packages/shader-shaderlab/src/global.d.ts @@ -0,0 +1,9 @@ +declare module "*.glsl" { + const value: string; + export default value; +} + +declare module "*.gs" { + const value: string; + export default value; +} diff --git a/packages/shader-shaderlab/src/index.ts b/packages/shader-shaderlab/src/index.ts new file mode 100644 index 0000000000..d144ddf44b --- /dev/null +++ b/packages/shader-shaderlab/src/index.ts @@ -0,0 +1,28 @@ +import { Shader, ShaderFactory } from "@galacean/engine"; +import { PBRSource, fragmentList } from "./shaders"; + +let includeRegistered = false; +let shaderRegistered = false; + +export function registerIncludes() { + if (includeRegistered) return; + + for (const sourceFragment of fragmentList) { + ShaderFactory.registerInclude(sourceFragment.includeKey, sourceFragment.source); + } + + includeRegistered = true; +} + +export function registerShader() { + if (shaderRegistered) return; + + Shader.create(PBRSource); + + shaderRegistered = true; +} + +/** + * @internal + */ +export { fragmentList }; diff --git a/packages/shader-shaderlab/src/shaders/BlendShape.glsl b/packages/shader-shaderlab/src/shaders/BlendShape.glsl new file mode 100644 index 0000000000..05a69f0249 --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/BlendShape.glsl @@ -0,0 +1,105 @@ +#ifndef BLENDSHAPE_INCLUDED +#define BLENDSHAPE_INCLUDED + +#ifdef RENDERER_HAS_BLENDSHAPE + #ifdef RENDERER_BLENDSHAPE_USE_TEXTURE + mediump sampler2DArray renderer_BlendShapeTexture; + ivec3 renderer_BlendShapeTextureInfo; + float renderer_BlendShapeWeights[RENDERER_BLENDSHAPE_COUNT]; + + vec3 getBlendShapeVertexElement(int blendShapeIndex, int vertexElementIndex){ + int y = vertexElementIndex / renderer_BlendShapeTextureInfo.y; + int x = vertexElementIndex - y * renderer_BlendShapeTextureInfo.y; + ivec3 uv = ivec3(x, y , blendShapeIndex); + return (texelFetch(renderer_BlendShapeTexture, uv, 0)).xyz; + } + #else + #if defined( RENDERER_BLENDSHAPE_HAS_NORMAL ) && defined( RENDERER_BLENDSHAPE_HAS_TANGENT ) + float renderer_BlendShapeWeights[2]; + #else + #if defined( RENDERER_BLENDSHAPE_HAS_NORMAL ) || defined( RENDERER_BLENDSHAPE_HAS_TANGENT ) + float renderer_BlendShapeWeights[4]; + #else + float renderer_BlendShapeWeights[8]; + #endif + #endif + #endif + + void calculateBlendShape(Attributes attributes, inout vec4 position + #ifdef RENDERER_HAS_NORMAL + ,inout vec3 normal + #ifdef RENDERER_HAS_TANGENT + ,inout vec4 tangent + #endif + #endif + + ){ + #ifdef RENDERER_BLENDSHAPE_USE_TEXTURE + int vertexOffset = gl_VertexID * renderer_BlendShapeTextureInfo.x; + for(int i = 0; i < RENDERER_BLENDSHAPE_COUNT; i++){ + int vertexElementOffset = vertexOffset; + float weight = renderer_BlendShapeWeights[i]; + // Warnning: Multiplying by 0 creates weird precision issues, causing rendering anomalies in Ace2 Android13 + if(weight != 0.0){ + position.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight; + + #if defined( RENDERER_HAS_NORMAL ) && defined( RENDERER_BLENDSHAPE_HAS_NORMAL ) + vertexElementOffset += 1; + normal += getBlendShapeVertexElement(i, vertexElementOffset) * weight; + #endif + + #if defined( RENDERER_HAS_TANGENT ) && defined(RENDERER_BLENDSHAPE_HAS_TANGENT) + vertexElementOffset += 1; + tangent.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight; + #endif + } + + } + #else + position.xyz += attributes.POSITION_BS0 * renderer_BlendShapeWeights[0]; + position.xyz += attributes.POSITION_BS1 * renderer_BlendShapeWeights[1]; + + #if defined( RENDERER_BLENDSHAPE_HAS_NORMAL ) && defined( RENDERER_BLENDSHAPE_HAS_TANGENT ) + #ifdef RENDERER_HAS_NORMAL + normal += attributes.NORMAL_BS0 * renderer_BlendShapeWeights[0]; + normal += attributes.NORMAL_BS1 * renderer_BlendShapeWeights[1]; + #endif + + #ifdef RENDERER_HAS_TANGENT + tangent.xyz += attributes.TANGENT_BS0 * renderer_BlendShapeWeights[0]; + tangent.xyz += attributes.TANGENT_BS1 * renderer_BlendShapeWeights[1]; + #endif + #else + #if defined( RENDERER_BLENDSHAPE_HAS_NORMAL ) || defined( RENDERER_BLENDSHAPE_HAS_TANGENT ) + position.xyz += attributes.POSITION_BS2 * renderer_BlendShapeWeights[2]; + position.xyz += attributes.POSITION_BS3 * renderer_BlendShapeWeights[3]; + + #if defined( RENDERER_BLENDSHAPE_HAS_NORMAL ) && defined( RENDERER_HAS_NORMAL ) + normal += attributes.NORMAL_BS0 * renderer_BlendShapeWeights[0]; + normal += attributes.NORMAL_BS1 * renderer_BlendShapeWeights[1]; + normal += attributes.NORMAL_BS2 * renderer_BlendShapeWeights[2]; + normal += attributes.NORMAL_BS3 * renderer_BlendShapeWeights[3]; + #endif + + #if defined(RENDERER_BLENDSHAPE_HAS_TANGENT) && defined( RENDERER_HAS_TANGENT ) + tangent.xyz += attributes.TANGENT_BS0 * renderer_BlendShapeWeights[0]; + tangent.xyz += attributes.TANGENT_BS1 * renderer_BlendShapeWeights[1]; + tangent.xyz += attributes.TANGENT_BS2 * renderer_BlendShapeWeights[2]; + tangent.xyz += attributes.TANGENT_BS3 * renderer_BlendShapeWeights[3]; + #endif + #else + position.xyz += attributes.POSITION_BS2 * renderer_BlendShapeWeights[2]; + position.xyz += attributes.POSITION_BS3 * renderer_BlendShapeWeights[3]; + position.xyz += attributes.POSITION_BS4 * renderer_BlendShapeWeights[4]; + position.xyz += attributes.POSITION_BS5 * renderer_BlendShapeWeights[5]; + position.xyz += attributes.POSITION_BS6 * renderer_BlendShapeWeights[6]; + position.xyz += attributes.POSITION_BS7 * renderer_BlendShapeWeights[7]; + #endif + #endif + #endif + } + +#endif + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/Common.glsl b/packages/shader-shaderlab/src/shaders/Common.glsl new file mode 100644 index 0000000000..46ac04ad5f --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/Common.glsl @@ -0,0 +1,101 @@ +#ifndef COMMON_INCLUDED +#define COMMON_INCLUDED + +#define PI 3.14159265359 +#define RECIPROCAL_PI 0.31830988618 +#define EPSILON 1e-6 +#define LOG2 1.442695 + +#define saturate( a ) clamp( a, 0.0, 1.0 ) + +float pow2(float x ) { + return x * x; +} + +vec4 RGBMToLinear(vec4 value, float maxRange ) { + return vec4( value.rgb * value.a * maxRange, 1.0 ); +} + +vec4 gammaToLinear(vec4 srgbIn){ + return vec4( pow(srgbIn.rgb, vec3(2.2)), srgbIn.a); +} + +vec4 linearToGamma(vec4 linearIn){ + linearIn = max(linearIn, 0.0); + return vec4( pow(linearIn.rgb, vec3(1.0 / 2.2)), linearIn.a); +} + +vec4 camera_DepthBufferParams; + +float remapDepthBufferLinear01(float z){ + return 1.0/ (camera_DepthBufferParams.x * z + camera_DepthBufferParams.y); +} + + +#ifdef GRAPHICS_API_WEBGL2 + #define INVERSE_MAT(mat) inverse(mat) +#else + mat2 inverseMat(mat2 m) { + return mat2(m[1][1],-m[0][1], + -m[1][0], m[0][0]) / (m[0][0]*m[1][1] - m[0][1]*m[1][0]); + } + mat3 inverseMat(mat3 m) { + float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2]; + float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2]; + float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2]; + + float b01 = a22 * a11 - a12 * a21; + float b11 = -a22 * a10 + a12 * a20; + float b21 = a21 * a10 - a11 * a20; + + float det = a00 * b01 + a01 * b11 + a02 * b21; + + return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11), + b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10), + b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det; + } + mat4 inverseMat(mat4 m) { + float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3], + a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3], + a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3], + a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + return mat4( + a11 * b11 - a12 * b10 + a13 * b09, + a02 * b10 - a01 * b11 - a03 * b09, + a31 * b05 - a32 * b04 + a33 * b03, + a22 * b04 - a21 * b05 - a23 * b03, + a12 * b08 - a10 * b11 - a13 * b07, + a00 * b11 - a02 * b08 + a03 * b07, + a32 * b02 - a30 * b05 - a33 * b01, + a20 * b05 - a22 * b02 + a23 * b01, + a10 * b10 - a11 * b08 + a13 * b06, + a01 * b08 - a00 * b10 - a03 * b06, + a30 * b04 - a31 * b02 + a33 * b00, + a21 * b02 - a20 * b04 - a23 * b00, + a11 * b07 - a10 * b09 - a12 * b06, + a00 * b09 - a01 * b07 + a02 * b06, + a31 * b01 - a30 * b03 - a32 * b00, + a20 * b03 - a21 * b01 + a22 * b00) / det; + } + + #define INVERSE_MAT(mat) inverseMat(mat) +#endif + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/Fog.glsl b/packages/shader-shaderlab/src/shaders/Fog.glsl new file mode 100644 index 0000000000..a9d920c9ad --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/Fog.glsl @@ -0,0 +1,30 @@ +#ifndef FOG_INCLUDED +#define FOG_INCLUDED + +#if SCENE_FOG_MODE != 0 + vec4 scene_FogColor; + vec4 scene_FogParams; // (-1/(end-start), end/(end-start), density/ln(2),density/sprt(ln(2))); + + vec4 fog(vec4 color, vec3 positionVS){ + float fogDepth = length(positionVS); + + #if SCENE_FOG_MODE == 1 + // (end-z) / (end-start) = z * (-1/(end-start)) + (end/(end-start)) + float fogIntensity = clamp(fogDepth * scene_FogParams.x + scene_FogParams.y, 0.0, 1.0); + #elif SCENE_FOG_MODE == 2 + // exp(-z * density) = exp2((-z * density)/ln(2)) = exp2(-z * density/ln(2)) + float fogIntensity = clamp(exp2(-fogDepth * scene_FogParams.z), 0.0, 1.0); + #elif SCENE_FOG_MODE == 3 + // exp(-(z * density)^2) = exp2(-(z * density)^2/ln(2)) = exp2(-(z * density/sprt(ln(2)))^2) + float factor = fogDepth * scene_FogParams.w; + float fogIntensity = clamp(exp2(-factor * factor), 0.0, 1.0); + #endif + + color.rgb = mix(scene_FogColor.rgb, color.rgb, fogIntensity); + + return color; + } +#endif + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/Light.glsl b/packages/shader-shaderlab/src/shaders/Light.glsl new file mode 100644 index 0000000000..3101ae1cf1 --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/Light.glsl @@ -0,0 +1,137 @@ +#ifndef LIGHT_INCLUDED +#define LIGHT_INCLUDED + + +ivec4 renderer_Layer; +#ifndef GRAPHICS_API_WEBGL2 + bool isBitSet(float value, float mask, float bitIndex){ + return mod(floor(value / pow(2.0, bitIndex)), 2.0) == 1.0 && mod(floor(mask / pow(2.0, bitIndex)), 2.0) == 1.0; + } +#endif + +bool isRendererCulledByLight(ivec2 rendererLayer, ivec2 lightCullingMask){ + #ifdef GRAPHICS_API_WEBGL2 + return !((rendererLayer.x & lightCullingMask.x) != 0 || (rendererLayer.y & lightCullingMask.y) != 0); + #else + for (int i = 0; i < 16; i++) { + if (isBitSet( float(rendererLayer.x), float(lightCullingMask.x), float(i)) || isBitSet( float(rendererLayer.y), float(lightCullingMask.y), float(i))) { + return false; + } + } + return true; + #endif +} + +// Directional light +#ifdef SCENE_DIRECT_LIGHT_COUNT + + struct DirectLight { + vec3 color; + vec3 direction; + }; + + ivec2 scene_DirectLightCullingMask[SCENE_DIRECT_LIGHT_COUNT]; + vec3 scene_DirectLightColor[SCENE_DIRECT_LIGHT_COUNT]; + vec3 scene_DirectLightDirection[SCENE_DIRECT_LIGHT_COUNT]; + + #ifdef GRAPHICS_API_WEBGL2 + DirectLight getDirectLight(int index){ + DirectLight light; + light.color = scene_DirectLightColor[index]; + light.direction = scene_DirectLightDirection[index]; + + return light; + } + #endif + +#endif + + +// Point light +#ifdef SCENE_POINT_LIGHT_COUNT + + struct PointLight { + vec3 color; + vec3 position; + float distance; + }; + + ivec2 scene_PointLightCullingMask[ SCENE_POINT_LIGHT_COUNT ]; + vec3 scene_PointLightColor[ SCENE_POINT_LIGHT_COUNT ]; + vec3 scene_PointLightPosition[ SCENE_POINT_LIGHT_COUNT ]; + float scene_PointLightDistance[ SCENE_POINT_LIGHT_COUNT ]; + + #ifdef GRAPHICS_API_WEBGL2 + PointLight getPointLight(int index){ + PointLight light; + light.color = scene_PointLightColor[index]; + light.position = scene_PointLightPosition[index]; + light.distance = scene_PointLightDistance[index]; + + return light; + } + #endif + +#endif + + +// Spot light +#ifdef SCENE_SPOT_LIGHT_COUNT + + struct SpotLight { + vec3 color; + vec3 position; + vec3 direction; + float distance; + float angleCos; + float penumbraCos; + }; + + ivec2 scene_SpotLightCullingMask[ SCENE_SPOT_LIGHT_COUNT ]; + vec3 scene_SpotLightColor[ SCENE_SPOT_LIGHT_COUNT ]; + vec3 scene_SpotLightPosition[ SCENE_SPOT_LIGHT_COUNT ]; + vec3 scene_SpotLightDirection[ SCENE_SPOT_LIGHT_COUNT ]; + float scene_SpotLightDistance[ SCENE_SPOT_LIGHT_COUNT ]; + float scene_SpotLightAngleCos[ SCENE_SPOT_LIGHT_COUNT ]; + float scene_SpotLightPenumbraCos[ SCENE_SPOT_LIGHT_COUNT ]; + + #ifdef GRAPHICS_API_WEBGL2 + SpotLight getSpotLight(int index){ + SpotLight light; + light.color = scene_SpotLightColor[index]; + light.position = scene_SpotLightPosition[index]; + light.direction = scene_SpotLightDirection[index]; + light.distance = scene_SpotLightDistance[index]; + light.angleCos = scene_SpotLightAngleCos[index]; + light.penumbraCos = scene_SpotLightPenumbraCos[index]; + + return light; + } + #endif + + +#endif + +// Ambient light +struct EnvMapLight { + vec3 diffuse; + float mipMapLevel; + float diffuseIntensity; + float specularIntensity; +}; + + +EnvMapLight scene_EnvMapLight; + +#ifdef SCENE_USE_SH + vec3 scene_EnvSH[9]; +#endif + +#ifdef SCENE_USE_SPECULAR_ENV + samplerCube scene_EnvSpecularSampler; +#endif + + + + +#endif diff --git a/packages/shader-shaderlab/src/shaders/Normal.glsl b/packages/shader-shaderlab/src/shaders/Normal.glsl new file mode 100644 index 0000000000..c077f32aea --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/Normal.glsl @@ -0,0 +1,37 @@ +#ifndef NORMAL_INCLUDED +#define NORMAL_INCLUDED + + +vec3 getNormalByNormalTexture(mat3 tbn, sampler2D normalTexture, float normalIntensity, vec2 uv, bool isFrontFacing){ + vec3 normal = (texture2D(normalTexture, uv)).rgb; + normal = normalize(tbn * ((2.0 * normal - 1.0) * vec3(normalIntensity, normalIntensity, 1.0))); + normal *= float( isFrontFacing ) * 2.0 - 1.0; + + return normal; +} + +mat3 getTBNByDerivatives(vec2 uv, vec3 normal, vec3 position, bool isFrontFacing){ + #ifdef HAS_DERIVATIVES + uv = isFrontFacing? uv: -uv; + // ref: http://www.thetenthplanet.de/archives/1180 + // get edge vectors of the pixel triangle + vec3 dp1 = dFdx(position); + vec3 dp2 = dFdy(position); + vec2 duv1 = dFdx(uv); + vec2 duv2 = dFdy(uv); + // solve the linear system + vec3 dp2perp = cross(dp2, normal); + vec3 dp1perp = cross(normal, dp1); + vec3 tangent = dp2perp * duv1.x + dp1perp * duv2.x; + vec3 bitangent = dp2perp * duv1.y + dp1perp * duv2.y; + // construct a scale-invariant frame + float denom = max( dot(tangent, tangent), dot(bitangent, bitangent) ); + float invmax = (denom == 0.0) ? 0.0 : camera_ProjectionParams.x / sqrt( denom ); + return mat3(tangent * invmax, bitangent * invmax, normal); + #else + return mat3(vec3(0.0), vec3(0.0), normal); + #endif +} + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/PBR.gs b/packages/shader-shaderlab/src/shaders/PBR.gs new file mode 100644 index 0000000000..8bea8bb27a --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/PBR.gs @@ -0,0 +1,78 @@ +Shader "PBR.gs" { + EditorProperties { + Header("Base"){ + material_IOR("IOR", Range(0, 5, 0.01)) = 1.5; + material_BaseColor("BaseColor", Color) = (1, 1, 1, 1); + material_BaseTexture("BaseTexture", Texture2D); + } + + Header("Metal Roughness") { + material_Metal( "Metal", Range(0,1,0.01) ) = 1; + material_Roughness( "Roughness", Range( 0, 1, 0.01 ) ) = 1; + material_RoughnessMetallicTexture("RoughnessMetallicTexture", Texture2D); + } + + Header("Anisotropy") { + material_AnisotropyInfo("AnisotropyInfo", Vector3) = (1, 0, 0); + material_AnisotropyTexture("AnisotropyTexture", Texture2D); + } + + Header("Normal") { + material_NormalTexture("NormalTexture", Texture2D); + material_NormalIntensity("NormalIntensity", Range(0, 5, 0.01)) = 1; + } + + Header("Emissive") { + material_EmissiveColor("EmissiveColor", Color ) = (0, 0, 0, 1); + material_EmissiveTexture("EmissiveTexture", Texture2D); + } + + Header("Occlusion") { + material_OcclusionTexture("OcclusionTexture", Texture2D); + material_OcclusionIntensity("OcclusionIntensity", Range(0, 5, 0.01)) = 1; + material_OcclusionTextureCoord("OcclusionTextureCoord", Float) = 0; + } + + Header("Clear Coat") { + material_ClearCoat("ClearCoat", Range(0, 1, 0.01)) = 0; + material_ClearCoatTexture("ClearCoatTexture", Texture2D); + material_ClearCoatRoughness("ClearCoatRoughness", Range(0, 1, 0.01)) = 0; + material_ClearCoatRoughnessTexture("ClearCoatRoughnessTexture", Texture2D); + material_ClearCoatNormalTexture("ClearCoatNormalTexture", Texture2D); + } + + Header("Thin Film Iridescence"){ + material_IridescenceInfo("IridescenceInfo", Vector4) = (0, 1.3, 100, 400); + material_IridescenceThicknessTexture("IridescenceThicknessTexture", Texture2D); + material_IridescenceTexture("IridescenceTexture", Texture2D); + } + + Header("Sheen"){ + ui_SheenIntensity("Intensity", Range(0, 1, 0.01)) = 0; + ui_SheenColor("Color", Color ) = (0, 0, 0, 0); + material_SheenRoughness("Roughness", Range(0, 1, 0.01)) = 0; + material_SheenTexture("ColorTexture", Texture2D); + material_SheenRoughnessTexture("RoughnessTexture", Texture2D); + } + + Header("Common") { + material_AlphaCutoff( "AlphaCutoff", Range(0, 1, 0.01) ) = 0; + material_TilingOffset("TilingOffset", Vector4) = (1, 1, 0, 0); + } + } + + SubShader "Default" { + UsePass "pbr/Default/ShadowCaster" + + Pass "Forward Pass" { + Tags { pipelineStage = "Forward"} + + #define IS_METALLIC_WORKFLOW + + VertexShader = PBRVertex; + FragmentShader = PBRFragment; + + #include "ForwardPassPBR.glsl" + } + } + } \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/Shadow.glsl b/packages/shader-shaderlab/src/shaders/Shadow.glsl new file mode 100644 index 0000000000..77823162cf --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/Shadow.glsl @@ -0,0 +1,179 @@ +#ifndef SHADOW_INCLUDED +#define SHADOW_INCLUDED + +#include "Transform.glsl" +#include "Common.glsl" + +#if defined(SCENE_SHADOW_TYPE) && defined(RENDERER_IS_RECEIVE_SHADOWS) + #define NEED_CALCULATE_SHADOWS +#endif + + +#ifdef NEED_CALCULATE_SHADOWS + mat4 scene_ShadowMatrices[SCENE_SHADOW_CASCADED_COUNT + 1]; + vec4 scene_ShadowSplitSpheres[4]; + + mediump int computeCascadeIndex(vec3 positionWS) { + vec3 fromCenter0 = positionWS - scene_ShadowSplitSpheres[0].xyz; + vec3 fromCenter1 = positionWS - scene_ShadowSplitSpheres[1].xyz; + vec3 fromCenter2 = positionWS - scene_ShadowSplitSpheres[2].xyz; + vec3 fromCenter3 = positionWS - scene_ShadowSplitSpheres[3].xyz; + + mediump vec4 comparison = vec4( + (dot(fromCenter0, fromCenter0) < scene_ShadowSplitSpheres[0].w), + (dot(fromCenter1, fromCenter1) < scene_ShadowSplitSpheres[1].w), + (dot(fromCenter2, fromCenter2) < scene_ShadowSplitSpheres[2].w), + (dot(fromCenter3, fromCenter3) < scene_ShadowSplitSpheres[3].w)); + comparison.yzw = clamp(comparison.yzw - comparison.xyz,0.0,1.0);//keep the nearest + mediump vec4 indexCoefficient = vec4(4.0,3.0,2.0,1.0); + mediump int index = 4 - int(dot(comparison, indexCoefficient)); + return index; + } + + vec3 getShadowCoord(vec3 positionWS) { + #if SCENE_SHADOW_CASCADED_COUNT == 1 + mediump int cascadeIndex = 0; + #else + mediump int cascadeIndex = computeCascadeIndex(positionWS); + #endif + + #ifdef GRAPHICS_API_WEBGL2 + mat4 shadowMatrix = scene_ShadowMatrices[cascadeIndex]; + #else + mat4 shadowMatrix; + #if SCENE_SHADOW_CASCADED_COUNT == 4 + if (cascadeIndex == 0) { + shadowMatrix = scene_ShadowMatrices[0]; + } else if (cascadeIndex == 1) { + shadowMatrix = scene_ShadowMatrices[1]; + } else if (cascadeIndex == 2) { + shadowMatrix = scene_ShadowMatrices[2]; + } else if (cascadeIndex == 3) { + shadowMatrix = scene_ShadowMatrices[3]; + } else { + shadowMatrix = scene_ShadowMatrices[4]; + } + #endif + #if SCENE_SHADOW_CASCADED_COUNT == 2 + if (cascadeIndex == 0) { + shadowMatrix = scene_ShadowMatrices[0]; + } else if (cascadeIndex == 1) { + shadowMatrix = scene_ShadowMatrices[1]; + } else { + shadowMatrix = scene_ShadowMatrices[2]; + } + #endif + #if SCENE_SHADOW_CASCADED_COUNT == 1 + if (cascadeIndex == 0) { + shadowMatrix = scene_ShadowMatrices[0]; + } else { + shadowMatrix = scene_ShadowMatrices[1]; + } + #endif + #endif + + vec4 shadowCoord = shadowMatrix * vec4(positionWS, 1.0); + return shadowCoord.xyz; + } +#endif + + +#ifdef NEED_CALCULATE_SHADOWS + // intensity, null, fadeScale, fadeBias + vec4 scene_ShadowInfo; + vec4 scene_ShadowMapSize; + + #ifdef GRAPHICS_API_WEBGL2 + mediump sampler2DShadow scene_ShadowMap; + #define SAMPLE_TEXTURE2D_SHADOW(textureName, coord3) textureLod(textureName, coord3 , 0.0) + #define TEXTURE2D_SHADOW_PARAM(shadowMap) mediump sampler2DShadow shadowMap + #else + sampler2D scene_ShadowMap; + #ifdef ENGINE_NO_DEPTH_TEXTURE + const vec4 bitShift = vec4(1.0, 1.0/256.0, 1.0/(256.0*256.0), 1.0/(256.0*256.0*256.0)); + /** + * Unpack depth value. + */ + float unpack(in vec4 rgbaDepth) { + return dot(rgbaDepth, bitShift); + } + #define SAMPLE_TEXTURE2D_SHADOW(textureName, coord3) (unpack(texture2D(textureName, coord3.xy)) < coord3.z ? 0.0 : 1.0) + #else + #define SAMPLE_TEXTURE2D_SHADOW(textureName, coord3) ((texture2D(textureName, coord3.xy)).r < coord3.z ? 0.0 : 1.0) + #endif + #define TEXTURE2D_SHADOW_PARAM(shadowMap) mediump sampler2D shadowMap + #endif + + #if SCENE_SHADOW_TYPE == 2 + float sampleShadowMapFiltered4(TEXTURE2D_SHADOW_PARAM(shadowMap), vec3 shadowCoord, vec4 shadowMapSize) { + float attenuation; + vec4 attenuation4; + vec2 offset=shadowMapSize.xy/2.0; + vec3 shadowCoord0=shadowCoord + vec3(-offset,0.0); + vec3 shadowCoord1=shadowCoord + vec3(offset.x,-offset.y,0.0); + vec3 shadowCoord2=shadowCoord + vec3(-offset.x,offset.y,0.0); + vec3 shadowCoord3=shadowCoord + vec3(offset,0.0); + attenuation4.x = SAMPLE_TEXTURE2D_SHADOW(shadowMap, shadowCoord0); + attenuation4.y = SAMPLE_TEXTURE2D_SHADOW(shadowMap, shadowCoord1); + attenuation4.z = SAMPLE_TEXTURE2D_SHADOW(shadowMap, shadowCoord2); + attenuation4.w = SAMPLE_TEXTURE2D_SHADOW(shadowMap, shadowCoord3); + attenuation = dot(attenuation4, vec4(0.25)); + return attenuation; + } + #endif + + #if SCENE_SHADOW_TYPE == 3 + #include "ShadowSampleTent.glsl" + + float sampleShadowMapFiltered9(TEXTURE2D_SHADOW_PARAM(shadowMap), vec3 shadowCoord, vec4 shadowmapSize) { + float attenuation; + float fetchesWeights[9]; + vec2 fetchesUV[9]; + sampleShadowComputeSamplesTent5x5(shadowmapSize, shadowCoord.xy, fetchesWeights, fetchesUV); + attenuation = fetchesWeights[0] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3(fetchesUV[0].xy, shadowCoord.z)); + attenuation += fetchesWeights[1] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3(fetchesUV[1].xy, shadowCoord.z)); + attenuation += fetchesWeights[2] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3(fetchesUV[2].xy, shadowCoord.z)); + attenuation += fetchesWeights[3] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3(fetchesUV[3].xy, shadowCoord.z)); + attenuation += fetchesWeights[4] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3(fetchesUV[4].xy, shadowCoord.z)); + attenuation += fetchesWeights[5] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3(fetchesUV[5].xy, shadowCoord.z)); + attenuation += fetchesWeights[6] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3(fetchesUV[6].xy, shadowCoord.z)); + attenuation += fetchesWeights[7] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3(fetchesUV[7].xy, shadowCoord.z)); + attenuation += fetchesWeights[8] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3(fetchesUV[8].xy, shadowCoord.z)); + return attenuation; + } + #endif + + + float getShadowFade(vec3 positionWS){ + vec3 camToPixel = positionWS - camera_Position; + float distanceCamToPixel2 = dot(camToPixel, camToPixel); + return saturate( distanceCamToPixel2 * scene_ShadowInfo.z + scene_ShadowInfo.w ); + } + + + float sampleShadowMap(vec3 positionWS, vec3 shadowCoord) { + float attenuation = 1.0; + if(shadowCoord.z > 0.0 && shadowCoord.z < 1.0) { + #if SCENE_SHADOW_TYPE == 1 + attenuation = SAMPLE_TEXTURE2D_SHADOW(scene_ShadowMap, shadowCoord); + #endif + + #if SCENE_SHADOW_TYPE == 2 + attenuation = sampleShadowMapFiltered4(scene_ShadowMap, shadowCoord, scene_ShadowMapSize); + #endif + + #if SCENE_SHADOW_TYPE == 3 + attenuation = sampleShadowMapFiltered9(scene_ShadowMap, shadowCoord, scene_ShadowMapSize); + #endif + attenuation = mix(1.0, attenuation, scene_ShadowInfo.x); + } + + float shadowFade = getShadowFade(positionWS); + attenuation = mix(1.0, mix(attenuation, 1.0, shadowFade), scene_ShadowInfo.x); + + return attenuation; + } +#endif + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/ShadowSampleTent.glsl b/packages/shader-shaderlab/src/shaders/ShadowSampleTent.glsl new file mode 100644 index 0000000000..7fc570c72b --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/ShadowSampleTent.glsl @@ -0,0 +1,120 @@ +#ifndef SHADOW_SAMPLE_TENT_INCLUDED +#define SHADOW_SAMPLE_TENT_INCLUDED + +// ------------------------------------------------------------------ +// PCF Filtering Tent Functions +// ------------------------------------------------------------------ + +// Assuming a isoceles right angled triangle of height "triangleHeight" (as drawn below). +// This function return the area of the triangle above the first texel(in Y the first texel). +// +// |\ <-- 45 degree slop isosceles right angled triangle +// | \ +// ---- <-- length of this side is "triangleHeight" +// _ _ _ _ <-- texels +float sampleShadowGetIRTriangleTexelArea(float triangleHeight) { + return triangleHeight - 0.5; +} + +// Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels. +// This function return the area of the triangle above each of those texels. +// | <-- offset from -0.5 to 0.5, 0 meaning triangle is exactly in the center +// / \ <-- 45 degree slop isosceles triangle (ie tent projected in 2D) +// / \ +// _ _ _ _ <-- texels +// X Y Z W <-- result indices (in computedArea.xyzw and computedAreaUncut.xyzw) +// Top point at (right,top) in a texel,left bottom point at (middle,middle) in a texel,right bottom point at (middle,middle) in a texel. +void sampleShadowGetTexelAreasTent3x3(float offset, out vec4 computedArea, out vec4 computedAreaUncut) { + // Compute the exterior areas,a and h is same. + float a = offset + 0.5; + float offsetSquaredHalved = a * a * 0.5; + computedAreaUncut.x = computedArea.x = offsetSquaredHalved - offset; + computedAreaUncut.w = computedArea.w = offsetSquaredHalved; + + // Compute the middle areas + // For Y : We find the area in Y of as if the left section of the isoceles triangle would + // intersect the axis between Y and Z (ie where offset = 0). + computedAreaUncut.y = sampleShadowGetIRTriangleTexelArea(1.5 - offset); + // This area is superior to the one we are looking for if (offset < 0) thus we need to + // subtract the area of the triangle defined by (0,1.5-offset), (0,1.5+offset), (-offset,1.5). + float clampedOffsetLeft = min(offset,0.0); + float areaOfSmallLeftTriangle = clampedOffsetLeft * clampedOffsetLeft; + computedArea.y = computedAreaUncut.y - areaOfSmallLeftTriangle; + + // We do the same for the Z but with the right part of the isoceles triangle + computedAreaUncut.z = sampleShadowGetIRTriangleTexelArea(1.5 + offset); + float clampedOffsetRight = max(offset,0.0); + float areaOfSmallRightTriangle = clampedOffsetRight * clampedOffsetRight; + computedArea.z = computedAreaUncut.z - areaOfSmallRightTriangle; +} + +// Assuming a isoceles triangle of 2.5 texel height and 5 texels wide lying on 6 texels. +// This function return the weight of each texels area relative to the full triangle area. +// / \ +// _ _ _ _ _ _ <-- texels +// 0 1 2 3 4 5 <-- computed area indices (in texelsWeights[]) +// Top point at (right,top) in a texel,left bottom point at (middle,middle) in a texel,right bottom point at (middle,middle) in a texel. +void sampleShadowGetTexelWeightsTent5x5(float offset, out vec3 texelsWeightsA, out vec3 texelsWeightsB) { + vec4 areaFrom3texelTriangle; + vec4 areaUncutFrom3texelTriangle; + sampleShadowGetTexelAreasTent3x3(offset, areaFrom3texelTriangle, areaUncutFrom3texelTriangle); + + // Triangle slope is 45 degree thus we can almost reuse the result of the 3 texel wide computation. + // the 5 texel wide triangle can be seen as the 3 texel wide one but shifted up by one unit/texel. + // 0.16 is 1/(the triangle area) + texelsWeightsA.x = 0.16 * (areaFrom3texelTriangle.x); + texelsWeightsA.y = 0.16 * (areaUncutFrom3texelTriangle.y); + texelsWeightsA.z = 0.16 * (areaFrom3texelTriangle.y + 1.0); + texelsWeightsB.x = 0.16 * (areaFrom3texelTriangle.z + 1.0); + texelsWeightsB.y = 0.16 * (areaUncutFrom3texelTriangle.z); + texelsWeightsB.z = 0.16 * (areaFrom3texelTriangle.w); +} + +// 5x5 Tent filter (45 degree sloped triangles in U and V) +void sampleShadowComputeSamplesTent5x5(vec4 shadowMapTextureTexelSize, vec2 coord, out float fetchesWeights[9], out vec2 fetchesUV[9]) +{ + // tent base is 5x5 base thus covering from 25 to 36 texels, thus we need 9 bilinear PCF fetches + vec2 tentCenterInTexelSpace = coord.xy * shadowMapTextureTexelSize.zw; + vec2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5); + vec2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace; + + // find the weight of each texel based on the area of a 45 degree slop tent above each of them. + vec3 texelsWeightsUA, texelsWeightsUB; + vec3 texelsWeightsVA, texelsWeightsVB; + sampleShadowGetTexelWeightsTent5x5(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsUA, texelsWeightsUB); + sampleShadowGetTexelWeightsTent5x5(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsVA, texelsWeightsVB); + + // each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels + vec3 fetchesWeightsU = vec3(texelsWeightsUA.xz, texelsWeightsUB.y) + vec3(texelsWeightsUA.y, texelsWeightsUB.xz); + vec3 fetchesWeightsV = vec3(texelsWeightsVA.xz, texelsWeightsVB.y) + vec3(texelsWeightsVA.y, texelsWeightsVB.xz); + + // move the PCF bilinear fetches to respect texels weights + vec3 fetchesOffsetsU = vec3(texelsWeightsUA.y, texelsWeightsUB.xz) / fetchesWeightsU.xyz + vec3(-2.5,-0.5,1.5); + vec3 fetchesOffsetsV = vec3(texelsWeightsVA.y, texelsWeightsVB.xz) / fetchesWeightsV.xyz + vec3(-2.5,-0.5,1.5); + fetchesOffsetsU *= shadowMapTextureTexelSize.xxx; + fetchesOffsetsV *= shadowMapTextureTexelSize.yyy; + + vec2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTextureTexelSize.xy; + fetchesUV[0] = bilinearFetchOrigin + vec2(fetchesOffsetsU.x, fetchesOffsetsV.x); + fetchesUV[1] = bilinearFetchOrigin + vec2(fetchesOffsetsU.y, fetchesOffsetsV.x); + fetchesUV[2] = bilinearFetchOrigin + vec2(fetchesOffsetsU.z, fetchesOffsetsV.x); + fetchesUV[3] = bilinearFetchOrigin + vec2(fetchesOffsetsU.x, fetchesOffsetsV.y); + fetchesUV[4] = bilinearFetchOrigin + vec2(fetchesOffsetsU.y, fetchesOffsetsV.y); + fetchesUV[5] = bilinearFetchOrigin + vec2(fetchesOffsetsU.z, fetchesOffsetsV.y); + fetchesUV[6] = bilinearFetchOrigin + vec2(fetchesOffsetsU.x, fetchesOffsetsV.z); + fetchesUV[7] = bilinearFetchOrigin + vec2(fetchesOffsetsU.y, fetchesOffsetsV.z); + fetchesUV[8] = bilinearFetchOrigin + vec2(fetchesOffsetsU.z, fetchesOffsetsV.z); + + fetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x; + fetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x; + fetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x; + fetchesWeights[3] = fetchesWeightsU.x * fetchesWeightsV.y; + fetchesWeights[4] = fetchesWeightsU.y * fetchesWeightsV.y; + fetchesWeights[5] = fetchesWeightsU.z * fetchesWeightsV.y; + fetchesWeights[6] = fetchesWeightsU.x * fetchesWeightsV.z; + fetchesWeights[7] = fetchesWeightsU.y * fetchesWeightsV.z; + fetchesWeights[8] = fetchesWeightsU.z * fetchesWeightsV.z; +} + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/Skin.glsl b/packages/shader-shaderlab/src/shaders/Skin.glsl new file mode 100644 index 0000000000..3f8e1cb1ab --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/Skin.glsl @@ -0,0 +1,47 @@ +#ifndef SKIN_INCLUDED +#define SKIN_INCLUDED + + +#ifdef RENDERER_HAS_SKIN + #ifdef RENDERER_USE_JOINT_TEXTURE + sampler2D renderer_JointSampler; + float renderer_JointCount; + + mat4 getJointMatrix(sampler2D smp, float index){ + float base = index / renderer_JointCount; + float hf = 0.5 / renderer_JointCount; + float v = base + hf; + + vec4 m0 = texture2D(smp, vec2(0.125, v )); + vec4 m1 = texture2D(smp, vec2(0.375, v )); + vec4 m2 = texture2D(smp, vec2(0.625, v )); + vec4 m3 = texture2D(smp, vec2(0.875, v )); + + return mat4(m0, m1, m2, m3); + } + #else + mat4 renderer_JointMatrix[ RENDERER_JOINTS_NUM ]; + #endif + + mat4 getSkinMatrix(Attributes attributes){ + #ifdef RENDERER_USE_JOINT_TEXTURE + mat4 skinMatrix = + attributes.WEIGHTS_0.x * getJointMatrix(renderer_JointSampler, attributes.JOINTS_0.x ) + + attributes.WEIGHTS_0.y * getJointMatrix(renderer_JointSampler, attributes.JOINTS_0.y ) + + attributes.WEIGHTS_0.z * getJointMatrix(renderer_JointSampler, attributes.JOINTS_0.z ) + + attributes.WEIGHTS_0.w * getJointMatrix(renderer_JointSampler, attributes.JOINTS_0.w ); + #else + mat4 skinMatrix = + attributes.WEIGHTS_0.x * renderer_JointMatrix[ int( attributes.JOINTS_0.x ) ] + + attributes.WEIGHTS_0.y * renderer_JointMatrix[ int( attributes.JOINTS_0.y ) ] + + attributes.WEIGHTS_0.z * renderer_JointMatrix[ int( attributes.JOINTS_0.z ) ] + + attributes.WEIGHTS_0.w * renderer_JointMatrix[ int( attributes.JOINTS_0.w ) ]; + #endif + + return skinMatrix; + } + +#endif + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/Transform.glsl b/packages/shader-shaderlab/src/shaders/Transform.glsl new file mode 100644 index 0000000000..b5d1a52a68 --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/Transform.glsl @@ -0,0 +1,16 @@ +#ifndef TRANSFORM_INCLUDED +#define TRANSFORM_INCLUDED + +mat4 renderer_LocalMat; +mat4 renderer_ModelMat; +mat4 camera_ViewMat; +mat4 camera_ProjMat; +mat4 renderer_MVMat; +mat4 renderer_MVPMat; +mat4 renderer_NormalMat; + +vec3 camera_Position; +vec3 camera_Forward; +vec4 camera_ProjectionParams; + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/index.ts b/packages/shader-shaderlab/src/shaders/index.ts new file mode 100644 index 0000000000..de23d2e392 --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/index.ts @@ -0,0 +1,31 @@ +import BlendShape from "./BlendShape.glsl"; +import Common from "./Common.glsl"; +import Fog from "./Fog.glsl"; +import Light from "./Light.glsl"; +import Normal from "./Normal.glsl"; +import PBRSource from "./PBR.gs"; +import Shadow from "./Shadow.glsl"; +import ShadowSampleTent from "./ShadowSampleTent.glsl"; +import Skin from "./Skin.glsl"; +import Transform from "./Transform.glsl"; +import shadingPBR from "./shadingPBR"; + +interface IShaderFragment { + includeKey: string; + source: string; +} + +const fragmentList: IShaderFragment[] = [ + { source: BlendShape, includeKey: "BlendShape.glsl" }, + { source: Common, includeKey: "Common.glsl" }, + { source: Fog, includeKey: "Fog.glsl" }, + { source: Light, includeKey: "Light.glsl" }, + { source: Normal, includeKey: "Normal.glsl" }, + { source: ShadowSampleTent, includeKey: "ShadowSampleTent.glsl" }, + { source: Shadow, includeKey: "Shadow.glsl" }, + { source: Transform, includeKey: "Transform.glsl" }, + { source: Skin, includeKey: "Skin.glsl" }, + + ...shadingPBR +]; +export { PBRSource, fragmentList }; diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/AttributesPBR.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/AttributesPBR.glsl new file mode 100644 index 0000000000..df8b010b90 --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/AttributesPBR.glsl @@ -0,0 +1,76 @@ +#ifndef ATTRIBUTES_PBR_INCLUDED +#define ATTRIBUTES_PBR_INCLUDED + + +struct Attributes{ + vec3 POSITION; + + #ifdef RENDERER_HAS_BLENDSHAPE + #ifndef RENDERER_BLENDSHAPE_USE_TEXTURE + vec3 POSITION_BS0; + vec3 POSITION_BS1; + #if defined( RENDERER_BLENDSHAPE_HAS_NORMAL ) && defined( RENDERER_BLENDSHAPE_HAS_TANGENT ) + vec3 NORMAL_BS0; + vec3 NORMAL_BS1; + vec3 TANGENT_BS0; + vec3 TANGENT_BS1; + #else + #if defined( RENDERER_BLENDSHAPE_HAS_NORMAL ) || defined( RENDERER_BLENDSHAPE_HAS_TANGENT ) + vec3 POSITION_BS2; + vec3 POSITION_BS3; + + #ifdef RENDERER_BLENDSHAPE_HAS_NORMAL + vec3 NORMAL_BS0; + vec3 NORMAL_BS1; + vec3 NORMAL_BS2; + vec3 NORMAL_BS3; + #endif + + #ifdef RENDERER_BLENDSHAPE_HAS_TANGENT + vec3 TANGENT_BS0; + vec3 TANGENT_BS1; + vec3 TANGENT_BS2; + vec3 TANGENT_BS3; + #endif + + #else + vec3 POSITION_BS2; + vec3 POSITION_BS3; + vec3 POSITION_BS4; + vec3 POSITION_BS5; + vec3 POSITION_BS6; + vec3 POSITION_BS7; + #endif + #endif + #endif + #endif + + + #ifdef RENDERER_HAS_UV + vec2 TEXCOORD_0; + #endif + + #ifdef RENDERER_HAS_UV1 + vec2 TEXCOORD_1; + #endif + + #ifdef RENDERER_HAS_SKIN + vec4 JOINTS_0; + vec4 WEIGHTS_0; + #endif + + #ifdef RENDERER_ENABLE_VERTEXCOLOR + vec4 COLOR_0; + #endif + + #ifdef RENDERER_HAS_NORMAL + vec3 NORMAL; + #endif + + #ifdef RENDERER_HAS_TANGENT + vec4 TANGENT; + #endif +}; + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/BRDF.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/BRDF.glsl new file mode 100644 index 0000000000..c8eb64615c --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/BRDF.glsl @@ -0,0 +1,410 @@ + +#ifndef BRDF_INCLUDED +#define BRDF_INCLUDED + +#define MIN_PERCEPTUAL_ROUGHNESS 0.045 +#define MIN_ROUGHNESS 0.002025 + +#if defined(RENDERER_HAS_TANGENT) || defined(MATERIAL_ENABLE_ANISOTROPY) || defined(MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE) || defined(MATERIAL_HAS_NORMALTEXTURE) + #define NEED_TANGENT +#endif + +#ifdef MATERIAL_ENABLE_SHEEN + sampler2D scene_prefilteredLUT; +#endif + +struct SurfaceData{ + // common + vec3 albedoColor; + vec3 specularColor; + vec3 emissiveColor; + float metallic; + float roughness; + float diffuseAO; + float specularAO; + float f0; + float opacity; + + // geometry + vec3 position; + vec3 normal; + + #ifdef NEED_TANGENT + vec3 tangent; + vec3 bitangent; + #endif + + vec3 viewDir; + float dotNV; + + // Anisotropy + #ifdef MATERIAL_ENABLE_ANISOTROPY + float anisotropy; + vec3 anisotropicT; + vec3 anisotropicB; + vec3 anisotropicN; + #endif + + // Clear coat + #ifdef MATERIAL_ENABLE_CLEAR_COAT + float clearCoat; + float clearCoatRoughness; + vec3 clearCoatNormal; + float clearCoatDotNV; + #endif + + #ifdef MATERIAL_ENABLE_IRIDESCENCE + float iridesceceIOR; + float iridesceceFactor; + float iridescenceThickness; + #endif + + #ifdef MATERIAL_ENABLE_SHEEN + float sheenRoughness; + vec3 sheenColor; + #endif + +}; + + +struct BRDFData{ + vec3 diffuseColor; + vec3 specularColor; + float roughness; + + #ifdef MATERIAL_ENABLE_CLEAR_COAT + vec3 clearCoatSpecularColor; + float clearCoatRoughness; + #endif + + #ifdef MATERIAL_ENABLE_IRIDESCENCE + vec3 iridescenceSpecularColor; + #endif + + #ifdef MATERIAL_ENABLE_SHEEN + float sheenRoughness; + float sheenScaling; + float approxIBLSheenDG; + #endif + +}; + + +float getAARoughnessFactor(vec3 normal) { + // Kaplanyan 2016, "Stable specular highlights" + // Tokuyoshi 2017, "Error Reduction and Simplification for Shading Anti-Aliasing" + // Tokuyoshi and Kaplanyan 2019, "Improved Geometric Specular Antialiasing" + #ifdef HAS_DERIVATIVES + vec3 dxy = max( abs(dFdx(normal)), abs(dFdy(normal)) ); + return max( max(dxy.x, dxy.y), dxy.z ); + #else + return 0.0; + #endif +} + + +float F_Schlick(float f0, float dotLH) { + return f0 + 0.96 * (pow(1.0 - dotLH, 5.0)); +} + +vec3 F_Schlick(vec3 specularColor, float dotLH ) { + + // Original approximation by Christophe Schlick '94 + // float fresnel = pow( 1.0 - dotLH, 5.0 ); + + // Optimized variant (presented by Epic at SIGGRAPH '13) + // https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf + float fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH ); + + return ( 1.0 - specularColor ) * fresnel + specularColor; + +} + +// Moving Frostbite to Physically Based Rendering 3.0 - page 12, listing 2 +// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf +float G_GGX_SmithCorrelated(float alpha, float dotNL, float dotNV ) { + + float a2 = pow2( alpha ); + + // dotNL and dotNV are explicitly swapped. This is not a mistake. + float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) ); + float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) ); + + return 0.5 / max( gv + gl, EPSILON ); + +} + +#ifdef MATERIAL_ENABLE_ANISOTROPY + // Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs" + // Heitz http://jcgt.org/published/0003/02/03/paper.pdf + float G_GGX_SmithCorrelated_Anisotropic(float at, float ab, float ToV, float BoV, float ToL, float BoL, float NoV, float NoL) { + float lambdaV = NoL * length(vec3(at * ToV, ab * BoV, NoV)); + float lambdaL = NoV * length(vec3(at * ToL, ab * BoL, NoL)); + return 0.5 / max(lambdaV + lambdaL, EPSILON); + } +#endif + +// Microfacet Models for Refraction through Rough Surfaces - equation (33) +// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html +// alpha is "roughness squared" in Disney’s reparameterization +float D_GGX(float alpha, float dotNH ) { + + float a2 = pow2( alpha ); + + float denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0; // avoid alpha = 0 with dotNH = 1 + + return RECIPROCAL_PI * a2 / pow2( denom ); + +} + +#ifdef MATERIAL_ENABLE_ANISOTROPY + // GGX Distribution Anisotropic + // https://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf Addenda + float D_GGX_Anisotropic(float at, float ab, float ToH, float BoH, float NoH) { + float a2 = at * ab; + highp vec3 d = vec3(ab * ToH, at * BoH, a2 * NoH); + highp float d2 = dot(d, d); + float b2 = a2 / d2; + return a2 * b2 * b2 * RECIPROCAL_PI; + } +#endif + +float DG_GGX(float alpha, float dotNV, float dotNL, float dotNH) { + float D = D_GGX( alpha, dotNH ); + float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV ); + return G * D; +} + +#ifdef MATERIAL_ENABLE_ANISOTROPY + float DG_GGX_anisotropic(vec3 h, vec3 l, SurfaceData surfaceData, float alpha, float dotNV, float dotNL, float dotNH) { + vec3 t = surfaceData.anisotropicT; + vec3 b = surfaceData.anisotropicB; + vec3 v = surfaceData.viewDir; + + float dotTV = dot(t, v); + float dotBV = dot(b, v); + float dotTL = dot(t, l); + float dotBL = dot(b, l); + float dotTH = dot(t, h); + float dotBH = dot(b, h); + + // Aniso parameter remapping + // https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf page 24 + float at = max(alpha * (1.0 + surfaceData.anisotropy), MIN_ROUGHNESS); + float ab = max(alpha * (1.0 - surfaceData.anisotropy), MIN_ROUGHNESS); + + // specular anisotropic BRDF + float D = D_GGX_Anisotropic(at, ab, dotTH, dotBH, dotNH); + float G = G_GGX_SmithCorrelated_Anisotropic(at, ab, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL); + + return G * D; + } +#endif + +// GGX Distribution, Schlick Fresnel, GGX-Smith Visibility +vec3 BRDF_Specular_GGX(vec3 incidentDirection, SurfaceData surfaceData, BRDFData brdfData, vec3 normal, vec3 specularColor, float roughness ) { + + float alpha = pow2( roughness ); // UE4's roughness + + vec3 halfDir = normalize( incidentDirection + surfaceData.viewDir ); + + float dotNL = saturate( dot( normal, incidentDirection ) ); + float dotNV = saturate( dot( normal, surfaceData.viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float dotLH = saturate( dot( incidentDirection, halfDir ) ); + + vec3 F = F_Schlick( specularColor, dotLH ); + #ifdef MATERIAL_ENABLE_IRIDESCENCE + F = mix(F, brdfData.iridescenceSpecularColor, surfaceData.iridesceceFactor); + #endif + + + #ifdef MATERIAL_ENABLE_ANISOTROPY + float GD = DG_GGX_anisotropic(halfDir, incidentDirection, surfaceData, alpha, dotNV, dotNL, dotNH); + #else + float GD = DG_GGX(alpha, dotNV, dotNL, dotNH); + #endif + return F * GD; +} + +vec3 BRDF_Diffuse_Lambert(vec3 diffuseColor) { + return RECIPROCAL_PI * diffuseColor; +} + +#ifdef MATERIAL_ENABLE_IRIDESCENCE + vec3 iorToFresnel0(vec3 transmittedIOR, float incidentIOR) { + return pow((transmittedIOR - incidentIOR) / (transmittedIOR + incidentIOR),vec3(2.0)); + } + + float iorToFresnel0(float transmittedIOR, float incidentIOR) { + return pow((transmittedIOR - incidentIOR) / (transmittedIOR + incidentIOR),2.0); + } + + // Assume air interface for top + // Note: We don't handle the case fresnel0 == 1 + vec3 fresnelToIOR(vec3 f0){ + vec3 sqrtF0 = sqrt(f0); + return (vec3(1.0) + sqrtF0) / (vec3(1.0) - sqrtF0); + } + + // Fresnel equations for dielectric/dielectric interfaces. + // Ref: https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html + // Evaluation XYZ sensitivity curves in Fourier space + vec3 evalSensitivity(float opd, vec3 shift){ + // Use Gaussian fits, given by 3 parameters: val, pos and var + float phase = 2.0 * PI * opd * 1.0e-9; + const vec3 val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13); + const vec3 pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06); + const vec3 var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09); + vec3 xyz = val * sqrt(2.0 * PI * var) * cos(pos * phase + shift) * exp(-var * pow2(phase)); + xyz.x += 9.7470e-14 * sqrt(2.0 * PI * 4.5282e+09) * cos(2.2399e+06 * phase + shift[0]) * exp(-4.5282e+09 * pow2(phase)); + xyz /= 1.0685e-7; + // XYZ to RGB color space + const mat3 XYZ_TO_RGB = mat3( 3.2404542, -0.9692660, 0.0556434, + -1.5371385, 1.8760108, -0.2040259, + -0.4985314, 0.0415560, 1.0572252); + vec3 rgb = XYZ_TO_RGB * xyz; + return rgb; + } + + vec3 evalIridescenceSpecular(float outsideIOR, float dotNV, float thinIOR, vec3 baseF0,float iridescenceThickness){ + vec3 iridescence = vec3(1.0); + // Force iridescenceIOR -> outsideIOR when thinFilmThickness -> 0.0 + float iridescenceIOR = mix( outsideIOR, thinIOR, smoothstep( 0.0, 0.03, iridescenceThickness ) ); + // Evaluate the cosTheta on the base layer (Snell law) + float sinTheta2Sq = pow( outsideIOR / iridescenceIOR, 2.0) * (1.0 - pow( dotNV, 2.0)); + float cosTheta2Sq = 1.0 - sinTheta2Sq; + // Handle total internal reflection + if (cosTheta2Sq < 0.0) { + return iridescence; + } + float cosTheta2 = sqrt(cosTheta2Sq); + + // First interface + float f0 = iorToFresnel0(iridescenceIOR, outsideIOR); + float reflectance = F_Schlick(f0, dotNV); + float t121 = 1.0 - reflectance; + float phi12 = 0.0; + // iridescenceIOR has limited greater than 1.0 + // if (iridescenceIOR < outsideIOR) {phi12 = PI;} + float phi21 = PI - phi12; + + // Second interface + vec3 baseIOR = fresnelToIOR(clamp(baseF0, 0.0, 0.9999)); // guard against 1.0 + vec3 r1 = iorToFresnel0(baseIOR, iridescenceIOR); + vec3 r23 = F_Schlick(r1, cosTheta2); + vec3 phi23 =vec3(0.0); + if (baseIOR[0] < iridescenceIOR) {phi23[0] = PI;} + if (baseIOR[1] < iridescenceIOR) {phi23[1] = PI;} + if (baseIOR[2] < iridescenceIOR) {phi23[2] = PI;} + + // Phase shift + float opd = 2.0 * iridescenceIOR * iridescenceThickness * cosTheta2; + vec3 phi = vec3(phi21) + phi23; + + // Compound terms + vec3 r123 = clamp(reflectance * r23, 1e-5, 0.9999); + vec3 sr123 = sqrt(r123); + vec3 rs = pow2(t121) * r23 / (vec3(1.0) - r123); + // Reflectance term for m = 0 (DC term amplitude) + vec3 c0 = reflectance + rs; + iridescence = c0; + // Reflectance term for m > 0 (pairs of diracs) + vec3 cm = rs - t121; + for (int m = 1; m <= 2; ++m) { + cm *= sr123; + vec3 sm = 2.0 * evalSensitivity(float(m) * opd, float(m) * phi); + iridescence += cm * sm; + } + return iridescence = max(iridescence, vec3(0.0)); + } +#endif + +#ifdef MATERIAL_ENABLE_SHEEN + // http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf + float D_Charlie(float roughness, float dotNH) { + float invAlpha = 1.0 / roughness; + float cos2h = dotNH * dotNH; + float sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16 + return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI); + } + + // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886". + float V_Neubelt(float NoV, float NoL) { + return saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV))); + } + + vec3 sheenBRDF(vec3 incidentDirection, SurfaceData surfaceData, vec3 sheenColor, float sheenRoughness) { + vec3 halfDir = normalize(incidentDirection + surfaceData.viewDir); + float dotNL = saturate(dot(surfaceData.normal, incidentDirection)); + float dotNH = saturate(dot(surfaceData.normal, halfDir)); + float D = D_Charlie(sheenRoughness, dotNH); + float V = V_Neubelt(surfaceData.dotNV, dotNL); + vec3 F = sheenColor; + return D * V * F; + } + + float prefilteredSheenDFG(float dotNV, float sheenRoughness) { + #ifdef HAS_TEX_LOD + return texture2DLodEXT(scene_prefilteredLUT, vec2(dotNV, sheenRoughness), 0.0).b; + #else + return texture2D(scene_prefilteredLUT, vec2(dotNV, sheenRoughness),0.0).b; + #endif + } +#endif + +// ------------------------Indirect Specular------------------------ +// ref: https://www.unrealengine.com/blog/physically-based-shading-on-mobile - environmentBRDF for GGX on mobile +vec3 envBRDFApprox(vec3 specularColor, float roughness, float dotNV ) { + + const vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 ); + + const vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 ); + + vec4 r = roughness * c0 + c1; + + float a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y; + + vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw; + + return specularColor * AB.x + AB.y; + +} + + +void initBRDFData(SurfaceData surfaceData, out BRDFData brdfData){ + vec3 albedoColor = surfaceData.albedoColor; + vec3 specularColor = surfaceData.specularColor; + float metallic = surfaceData.metallic; + float roughness = surfaceData.roughness; + float f0 = surfaceData.f0; + + #ifdef IS_METALLIC_WORKFLOW + brdfData.diffuseColor = albedoColor * ( 1.0 - metallic ); + brdfData.specularColor = mix( vec3(f0), albedoColor, metallic ); + #else + float specularStrength = max( max( specularColor.r, specularColor.g ), specularColor.b ); + brdfData.diffuseColor = albedoColor * ( 1.0 - specularStrength ); + brdfData.specularColor = specularColor; + #endif + + brdfData.roughness = max(MIN_PERCEPTUAL_ROUGHNESS, min(roughness + getAARoughnessFactor(surfaceData.normal), 1.0)); + + #ifdef MATERIAL_ENABLE_CLEAR_COAT + brdfData.clearCoatRoughness = max(MIN_PERCEPTUAL_ROUGHNESS, min(surfaceData.clearCoatRoughness + getAARoughnessFactor(surfaceData.clearCoatNormal), 1.0)); + brdfData.clearCoatSpecularColor = vec3(0.04); + #endif + + #ifdef MATERIAL_ENABLE_IRIDESCENCE + float topIOR = 1.0; + brdfData.iridescenceSpecularColor = evalIridescenceSpecular(topIOR, surfaceData.dotNV, surfaceData.iridesceceIOR, brdfData.specularColor, surfaceData.iridescenceThickness); + #endif + + #ifdef MATERIAL_ENABLE_SHEEN + brdfData.sheenRoughness = max(MIN_PERCEPTUAL_ROUGHNESS, min(surfaceData.sheenRoughness + getAARoughnessFactor(surfaceData.normal), 1.0)); + brdfData.approxIBLSheenDG = prefilteredSheenDFG(surfaceData.dotNV, brdfData.sheenRoughness); + brdfData.sheenScaling = 1.0 - brdfData.approxIBLSheenDG * max(max(surfaceData.sheenColor.r, surfaceData.sheenColor.g), surfaceData.sheenColor.b); + #endif +} + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/ForwardPassPBR.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/ForwardPassPBR.glsl new file mode 100644 index 0000000000..8717574808 --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/ForwardPassPBR.glsl @@ -0,0 +1,110 @@ +#ifndef FORWARD_PASS_PBR_INCLUDED +#define FORWARD_PASS_PBR_INCLUDED + +#include "Common.glsl" +#include "Fog.glsl" + +#include "AttributesPBR.glsl" +#include "VaryingsPBR.glsl" +#include "LightDirectPBR.glsl" +#include "LightIndirectPBR.glsl" + +#include "VertexPBR.glsl" +#include "FragmentPBR.glsl" + + +Varyings PBRVertex(Attributes attributes) { + Varyings varyings; + + varyings.uv = getUV0(attributes); + #ifdef RENDERER_HAS_UV1 + varyings.uv1 = attributes.TEXCOORD_1; + #endif + + #ifdef RENDERER_ENABLE_VERTEXCOLOR + varyings.vertexColor = attributes.COLOR_0; + #endif + + + VertexInputs vertexInputs = getVertexInputs(attributes); + + // positionWS + varyings.positionWS = vertexInputs.positionWS; + + // positionVS + #if SCENE_FOG_MODE != 0 + varyings.positionVS = vertexInputs.positionVS; + #endif + + // normalWS、tangentWS、bitangentWS + #ifdef RENDERER_HAS_NORMAL + varyings.normalWS = vertexInputs.normalWS; + #ifdef RENDERER_HAS_TANGENT + varyings.tangentWS = vertexInputs.tangentWS; + varyings.bitangentWS = vertexInputs.bitangentWS; + #endif + #endif + + // ShadowCoord + #if defined(NEED_CALCULATE_SHADOWS) && (SCENE_SHADOW_CASCADED_COUNT == 1) + varyings.shadowCoord = getShadowCoord(vertexInputs.positionWS); + #endif + + gl_Position = renderer_MVPMat * vertexInputs.positionOS; + + return varyings; +} + + +void PBRFragment(Varyings varyings) { + BRDFData brdfData; + + // Get aoUV + vec2 aoUV = varyings.uv; + #if defined(MATERIAL_HAS_OCCLUSION_TEXTURE) && defined(RENDERER_HAS_UV1) + if(material_OcclusionTextureCoord == 1.0){ + aoUV = varyings.uv1; + } + #endif + + SurfaceData surfaceData = getSurfaceData(varyings, aoUV, gl_FrontFacing); + + // Can modify surfaceData here + initBRDFData(surfaceData, brdfData); + + vec4 color = vec4(0, 0, 0, surfaceData.opacity); + + // Get shadow attenuation + float shadowAttenuation = 1.0; + #if defined(SCENE_DIRECT_LIGHT_COUNT) && defined(NEED_CALCULATE_SHADOWS) + #if SCENE_SHADOW_CASCADED_COUNT == 1 + vec3 shadowCoord = varyings.shadowCoord; + #else + vec3 shadowCoord = getShadowCoord(varyings.positionWS); + #endif + shadowAttenuation *= sampleShadowMap(varyings.positionWS, shadowCoord); + #endif + + // Evaluate direct lighting + evaluateDirectRadiance(varyings, surfaceData, brdfData, shadowAttenuation, color.rgb); + + // IBL + evaluateIBL(varyings, surfaceData, brdfData, color.rgb); + + // Emissive + color.rgb += surfaceData.emissiveColor; + + + #if SCENE_FOG_MODE != 0 + color = fog(color, varyings.positionVS); + #endif + + #ifndef ENGINE_IS_COLORSPACE_GAMMA + color = linearToGamma(color); + #endif + + gl_FragColor = color; +} + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/FragmentPBR.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/FragmentPBR.glsl new file mode 100644 index 0000000000..0ec9afe48c --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/FragmentPBR.glsl @@ -0,0 +1,315 @@ +#ifndef MATERIAL_INPUT_PBR_INCLUDED +#define MATERIAL_INPUT_PBR_INCLUDED + +#include "Normal.glsl" + +float material_AlphaCutoff; +vec4 material_BaseColor; +float material_Metal; +float material_Roughness; +float material_IOR; +vec3 material_PBRSpecularColor; +float material_Glossiness; +vec3 material_EmissiveColor; +float material_NormalIntensity; +float material_OcclusionIntensity; +float material_OcclusionTextureCoord; + +#ifdef MATERIAL_ENABLE_CLEAR_COAT + float material_ClearCoat; + float material_ClearCoatRoughness; + + #ifdef MATERIAL_HAS_CLEAR_COAT_TEXTURE + sampler2D material_ClearCoatTexture; + #endif + + #ifdef MATERIAL_HAS_CLEAR_COAT_ROUGHNESS_TEXTURE + sampler2D material_ClearCoatRoughnessTexture; + #endif + + #ifdef MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE + sampler2D material_ClearCoatNormalTexture; + #endif +#endif + +#ifdef MATERIAL_ENABLE_ANISOTROPY + vec3 material_AnisotropyInfo; + #ifdef MATERIAL_HAS_ANISOTROPY_TEXTURE + sampler2D material_AnisotropyTexture; + #endif +#endif + +#ifdef MATERIAL_ENABLE_IRIDESCENCE + vec4 material_IridescenceInfo; + #ifdef MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE + sampler2D material_IridescenceThicknessTexture; + #endif + + #ifdef MATERIAL_HAS_IRIDESCENCE_TEXTURE + sampler2D material_IridescenceTexture; + #endif +#endif + +#ifdef MATERIAL_ENABLE_SHEEN + float material_SheenRoughness; + vec3 material_SheenColor; + #ifdef MATERIAL_HAS_SHEEN_TEXTURE + sampler2D material_SheenTexture; + #endif + + #ifdef MATERIAL_HAS_SHEEN_ROUGHNESS_TEXTURE + sampler2D material_SheenRoughnessTexture; + #endif +#endif + +// Texture +#ifdef MATERIAL_HAS_BASETEXTURE + sampler2D material_BaseTexture; +#endif + +#ifdef MATERIAL_HAS_NORMALTEXTURE + sampler2D material_NormalTexture; +#endif + +#ifdef MATERIAL_HAS_EMISSIVETEXTURE + sampler2D material_EmissiveTexture; +#endif + +#ifdef MATERIAL_HAS_ROUGHNESS_METALLIC_TEXTURE + sampler2D material_RoughnessMetallicTexture; +#endif + + +#ifdef MATERIAL_HAS_SPECULAR_GLOSSINESS_TEXTURE + sampler2D material_SpecularGlossinessTexture; +#endif + +#ifdef MATERIAL_HAS_OCCLUSION_TEXTURE + sampler2D material_OcclusionTexture; +#endif + + +#ifdef MATERIAL_ENABLE_ANISOTROPY + // Aniso Bent Normals + // Mc Alley https://www.gdcvault.com/play/1022235/Rendering-the-World-of-Far + vec3 getAnisotropicBentNormal(SurfaceData surfaceData) { + vec3 anisotropyDirection = (surfaceData.anisotropy >= 0.0) ? surfaceData.anisotropicB : surfaceData.anisotropicT; + vec3 anisotropicTangent = cross(anisotropyDirection, surfaceData.viewDir); + vec3 anisotropicNormal = cross(anisotropicTangent, anisotropyDirection); + // reduce stretching for (roughness < 0.2), refer to https://advances.realtimerendering.com/s2018/Siggraph%202018%20HDRP%20talk_with%20notes.pdf 80 + vec3 bentNormal = normalize( mix(surfaceData.normal, anisotropicNormal, abs(surfaceData.anisotropy) * saturate( 5.0 * surfaceData.roughness)) ); + + return bentNormal; + } +#endif + + +SurfaceData getSurfaceData(Varyings v, vec2 aoUV, bool isFrontFacing){ + SurfaceData surfaceData; + + vec2 uv = v.uv; + + // common + vec4 baseColor = material_BaseColor; + float metallic = material_Metal; + float roughness = material_Roughness; + vec3 specularColor = material_PBRSpecularColor; + float glossiness = material_Glossiness; + float f0 = pow2( (material_IOR - 1.0) / (material_IOR + 1.0) ); + vec3 emissiveRadiance = material_EmissiveColor; + + #ifdef MATERIAL_HAS_BASETEXTURE + vec4 baseTextureColor = texture2D(material_BaseTexture, uv); + #ifndef ENGINE_IS_COLORSPACE_GAMMA + baseTextureColor = gammaToLinear(baseTextureColor); + #endif + baseColor *= baseTextureColor; + #endif + + #ifdef RENDERER_ENABLE_VERTEXCOLOR + baseColor *= v.vertexColor; + #endif + + + #ifdef MATERIAL_IS_ALPHA_CUTOFF + if( baseColor.a < material_AlphaCutoff ) { + discard; + } + #endif + + #ifdef MATERIAL_HAS_ROUGHNESS_METALLIC_TEXTURE + vec4 metalRoughMapColor = texture2D( material_RoughnessMetallicTexture, uv ); + roughness *= metalRoughMapColor.g; + metallic *= metalRoughMapColor.b; + #endif + + #ifdef MATERIAL_HAS_SPECULAR_GLOSSINESS_TEXTURE + vec4 specularGlossinessColor = texture2D(material_SpecularGlossinessTexture, uv ); + #ifndef ENGINE_IS_COLORSPACE_GAMMA + specularGlossinessColor = gammaToLinear(specularGlossinessColor); + #endif + specularColor *= specularGlossinessColor.rgb; + glossiness *= specularGlossinessColor.a; + roughness = 1.0 - glossiness; + #endif + + #ifdef MATERIAL_HAS_EMISSIVETEXTURE + vec4 emissiveColor = texture2D(material_EmissiveTexture, uv); + #ifndef ENGINE_IS_COLORSPACE_GAMMA + emissiveColor = gammaToLinear(emissiveColor); + #endif + emissiveRadiance *= emissiveColor.rgb; + #endif + + surfaceData.albedoColor = baseColor.rgb; + surfaceData.specularColor = specularColor; + surfaceData.emissiveColor = emissiveRadiance; + surfaceData.metallic = metallic; + surfaceData.roughness = roughness; + surfaceData.f0 = f0; + + #ifdef MATERIAL_IS_TRANSPARENT + surfaceData.opacity = baseColor.a; + #else + surfaceData.opacity = 1.0; + #endif + + + // Geometry + surfaceData.position = v.positionWS; + + #ifdef CAMERA_ORTHOGRAPHIC + surfaceData.viewDir = -camera_Forward; + #else + surfaceData.viewDir = normalize(camera_Position - v.positionWS); + #endif + + // Normal + #ifdef RENDERER_HAS_NORMAL + vec3 normal = normalize(v.normalWS); + #elif defined(HAS_DERIVATIVES) + vec3 pos_dx = dFdx(v.positionWS); + vec3 pos_dy = dFdy(v.positionWS); + vec3 normal = normalize( cross(pos_dx, pos_dy) ); + normal *= camera_ProjectionParams.x; + #else + vec3 normal = vec3(0, 0, 1); + #endif + + normal *= float( isFrontFacing ) * 2.0 - 1.0; + surfaceData.normal = normal; + + // Tangent + #ifdef NEED_TANGENT + #if defined(RENDERER_HAS_NORMAL) && defined(RENDERER_HAS_TANGENT) + surfaceData.tangent = v.tangentWS; + surfaceData.bitangent = v.bitangentWS; + mat3 tbn = mat3(v.tangentWS, v.bitangentWS, v.normalWS); + #else + mat3 tbn = getTBNByDerivatives(uv, normal, v.positionWS, isFrontFacing); + surfaceData.tangent = tbn[0]; + surfaceData.bitangent = tbn[1]; + #endif + + #ifdef MATERIAL_HAS_NORMALTEXTURE + surfaceData.normal = getNormalByNormalTexture(tbn, material_NormalTexture, material_NormalIntensity, uv, isFrontFacing); + #endif + #endif + + surfaceData.dotNV = saturate( dot(surfaceData.normal, surfaceData.viewDir) ); + + // Clear Coat + #ifdef MATERIAL_ENABLE_CLEAR_COAT + #ifdef MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE + surfaceData.clearCoatNormal = getNormalByNormalTexture(mat3(surfaceData.tangent, surfaceData.bitangent, surfaceData.normal), material_ClearCoatNormalTexture, material_NormalIntensity, uv, isFrontFacing); + #else + surfaceData.clearCoatNormal = normal; + #endif + surfaceData.clearCoatDotNV = saturate( dot(surfaceData.clearCoatNormal, surfaceData.viewDir) ); + + surfaceData.clearCoat = material_ClearCoat; + surfaceData.clearCoatRoughness = material_ClearCoatRoughness; + + #ifdef MATERIAL_HAS_CLEAR_COAT_TEXTURE + surfaceData.clearCoat *= (texture2D( material_ClearCoatTexture, uv )).r; + #endif + + #ifdef MATERIAL_HAS_CLEAR_COAT_ROUGHNESS_TEXTURE + surfaceData.clearCoatRoughness *= (texture2D( material_ClearCoatRoughnessTexture, uv )).g; + #endif + + surfaceData.clearCoat = saturate( surfaceData.clearCoat ); + surfaceData.clearCoatRoughness = max(MIN_PERCEPTUAL_ROUGHNESS, min(surfaceData.clearCoatRoughness + getAARoughnessFactor(surfaceData.clearCoatNormal), 1.0)); + #endif + + // Anisotropy + #ifdef MATERIAL_ENABLE_ANISOTROPY + float anisotropy = material_AnisotropyInfo.z; + vec3 anisotropicDirection = vec3(material_AnisotropyInfo.xy, 0.0); + #ifdef MATERIAL_HAS_ANISOTROPY_TEXTURE + vec3 anisotropyTextureInfo = (texture2D( material_AnisotropyTexture, uv )).rgb; + anisotropy *= anisotropyTextureInfo.b; + anisotropicDirection.xy *= anisotropyTextureInfo.rg * 2.0 - 1.0; + #endif + + surfaceData.anisotropy = anisotropy; + surfaceData.anisotropicT = normalize(mat3(surfaceData.tangent, surfaceData.bitangent, surfaceData.normal) * anisotropicDirection); + surfaceData.anisotropicB = normalize(cross(surfaceData.normal, surfaceData.anisotropicT)); + surfaceData.anisotropicN = getAnisotropicBentNormal(surfaceData); + #endif + + //Iridescence + #ifdef MATERIAL_ENABLE_IRIDESCENCE + surfaceData.iridesceceFactor = material_IridescenceInfo.x; + surfaceData.iridesceceIOR = material_IridescenceInfo.y; + + #ifdef MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE + float iridescenceThicknessWeight = texture2D( material_IridescenceThicknessTexture, uv).g; + surfaceData.iridescenceThickness = mix(material_IridescenceInfo.z, material_IridescenceInfo.w, iridescenceThicknessWeight); + #else + surfaceData.iridescenceThickness = material_IridescenceInfo.w; + #endif + + #ifdef MATERIAL_HAS_IRIDESCENCE_TEXTURE + surfaceData.iridesceceFactor *= texture2D( material_IridescenceTexture, uv).r; + #endif + #endif + + #ifdef MATERIAL_ENABLE_SHEEN + vec3 sheenColor = material_SheenColor; + #ifdef MATERIAL_HAS_SHEEN_TEXTURE + vec4 sheenTextureColor = texture2D(material_SheenTexture, uv); + #ifndef ENGINE_IS_COLORSPACE_GAMMA + sheenTextureColor = gammaToLinear(sheenTextureColor); + #endif + sheenColor *= sheenTextureColor.rgb; + #endif + surfaceData.sheenColor = sheenColor; + + surfaceData.sheenRoughness = material_SheenRoughness; + #ifdef MATERIAL_HAS_SHEEN_ROUGHNESS_TEXTURE + surfaceData.sheenRoughness *= texture2D(material_SheenRoughnessTexture, uv).a; + #endif + #endif + + // AO + float diffuseAO = 1.0; + float specularAO = 1.0; + + #ifdef MATERIAL_HAS_OCCLUSION_TEXTURE + diffuseAO = ((texture2D(material_OcclusionTexture, aoUV)).r - 1.0) * material_OcclusionIntensity + 1.0; + #endif + + #if defined(MATERIAL_HAS_OCCLUSION_TEXTURE) && defined(SCENE_USE_SPECULAR_ENV) + specularAO = saturate( pow( surfaceData.dotNV + diffuseAO, exp2( - 16.0 * surfaceData.roughness - 1.0 ) ) - 1.0 + diffuseAO ); + #endif + + surfaceData.diffuseAO = diffuseAO; + surfaceData.specularAO = specularAO; + + return surfaceData; +} + + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/LightDirectPBR.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/LightDirectPBR.glsl new file mode 100644 index 0000000000..f8ad6e77a4 --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/LightDirectPBR.glsl @@ -0,0 +1,162 @@ + +#ifndef LIGHT_DIRECT_PBR_INCLUDED +#define LIGHT_DIRECT_PBR_INCLUDED + +#ifndef FUNCTION_SURFACE_SHADING + #define FUNCTION_SURFACE_SHADING surfaceShading +#endif +#ifndef FUNCTION_DIFFUSE_LOBE + #define FUNCTION_DIFFUSE_LOBE diffuseLobe +#endif +#ifndef FUNCTION_SPECULAR_LOBE + #define FUNCTION_SPECULAR_LOBE specularLobe +#endif +#ifndef FUNCTION_CLEAR_COAT_LOBE + #define FUNCTION_CLEAR_COAT_LOBE clearCoatLobe +#endif +#ifndef FUNCTION_SHEEN_LOBE + #define FUNCTION_SHEEN_LOBE sheenLobe +#endif + +#include "BRDF.glsl" +#include "Light.glsl" +#include "ReflectionLobe.glsl" + +void surfaceShading(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, vec3 incidentDirection, vec3 lightColor, inout vec3 color) { + + vec3 diffuseColor = vec3(0); + vec3 specularColor = vec3(0); + float dotNL = saturate( dot( surfaceData.normal, incidentDirection ) ); + vec3 irradiance = dotNL * lightColor * PI; + + // ClearCoat Lobe + float attenuation = FUNCTION_CLEAR_COAT_LOBE(varyings, surfaceData, brdfData, incidentDirection, lightColor, specularColor); + + vec3 attenuationIrradiance = attenuation * irradiance; + // Diffuse Lobe + FUNCTION_DIFFUSE_LOBE(varyings, surfaceData, brdfData, attenuationIrradiance, diffuseColor); + // Specular Lobe + FUNCTION_SPECULAR_LOBE(varyings, surfaceData, brdfData, incidentDirection, attenuationIrradiance, specularColor); + // Sheen Lobe + FUNCTION_SHEEN_LOBE(varyings, surfaceData, brdfData, incidentDirection, attenuationIrradiance, diffuseColor, specularColor); + + color += diffuseColor + specularColor; + +} + +#ifdef SCENE_DIRECT_LIGHT_COUNT + + void addDirectionalDirectLightRadiance(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, DirectLight directionalLight, inout vec3 color) { + vec3 lightColor = directionalLight.color; + vec3 direction = -directionalLight.direction; + + FUNCTION_SURFACE_SHADING(varyings, surfaceData, brdfData, direction, lightColor, color); + + } + +#endif + +#ifdef SCENE_POINT_LIGHT_COUNT + + void addPointDirectLightRadiance(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, PointLight pointLight, inout vec3 color) { + vec3 lVector = pointLight.position - surfaceData.position; + vec3 direction = normalize( lVector ); + float lightDistance = length( lVector ); + + vec3 lightColor = pointLight.color; + lightColor *= clamp(1.0 - pow(lightDistance/pointLight.distance, 4.0), 0.0, 1.0); + + FUNCTION_SURFACE_SHADING(varyings, surfaceData, brdfData, direction, lightColor, color); + } + +#endif + +#ifdef SCENE_SPOT_LIGHT_COUNT + + void addSpotDirectLightRadiance(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, SpotLight spotLight, inout vec3 color) { + + vec3 lVector = spotLight.position - surfaceData.position; + vec3 direction = normalize( lVector ); + float lightDistance = length( lVector ); + float angleCos = dot( direction, -spotLight.direction ); + + float spotEffect = smoothstep( spotLight.penumbraCos, spotLight.angleCos, angleCos ); + float decayEffect = clamp(1.0 - pow(lightDistance/spotLight.distance, 4.0), 0.0, 1.0); + + vec3 lightColor = spotLight.color; + lightColor *= spotEffect * decayEffect; + + FUNCTION_SURFACE_SHADING(varyings, surfaceData, brdfData, direction, lightColor, color); + + } + + +#endif + +void evaluateDirectRadiance(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, float shadowAttenuation, inout vec3 color){ + #ifdef SCENE_DIRECT_LIGHT_COUNT + + for ( int i = 0; i < SCENE_DIRECT_LIGHT_COUNT; i ++ ) { + // warning: use `continue` syntax may trigger flickering bug in safri 16.1. + if(!isRendererCulledByLight(renderer_Layer.xy, scene_DirectLightCullingMask[i])){ + #ifdef GRAPHICS_API_WEBGL2 + DirectLight directionalLight = getDirectLight(i); + #else + DirectLight directionalLight; + directionalLight.color = scene_DirectLightColor[i]; + directionalLight.direction = scene_DirectLightDirection[i]; + #endif + + #ifdef NEED_CALCULATE_SHADOWS + if (i == 0) { // Sun light index is always 0 + directionalLight.color *= shadowAttenuation; + } + #endif + addDirectionalDirectLightRadiance(varyings, surfaceData, brdfData, directionalLight, color ); + } + } + + #endif + + #ifdef SCENE_POINT_LIGHT_COUNT + + for ( int i = 0; i < SCENE_POINT_LIGHT_COUNT; i ++ ) { + if(!isRendererCulledByLight(renderer_Layer.xy, scene_PointLightCullingMask[i])){ + #ifdef GRAPHICS_API_WEBGL2 + PointLight pointLight = getPointLight(i); + #else + PointLight pointLight; + pointLight.color = scene_PointLightColor[i]; + pointLight.position = scene_PointLightPosition[i]; + pointLight.distance = scene_PointLightDistance[i]; + #endif + addPointDirectLightRadiance(varyings, surfaceData, brdfData, pointLight, color ); + } + } + + #endif + + #ifdef SCENE_SPOT_LIGHT_COUNT + + for ( int i = 0; i < SCENE_SPOT_LIGHT_COUNT; i ++ ) { + if(!isRendererCulledByLight(renderer_Layer.xy, scene_SpotLightCullingMask[i])){ + #ifdef GRAPHICS_API_WEBGL2 + SpotLight spotLight = getSpotLight(i); + #else + SpotLight spotLight; + spotLight.color = scene_SpotLightColor[i]; + spotLight.position = scene_SpotLightPosition[i]; + spotLight.direction = scene_SpotLightDirection[i]; + spotLight.distance = scene_SpotLightDistance[i]; + spotLight.angleCos = scene_SpotLightAngleCos[i]; + spotLight.penumbraCos = scene_SpotLightPenumbraCos[i]; + #endif + addSpotDirectLightRadiance( varyings, surfaceData, brdfData, spotLight, color ); + } + } + + #endif +} + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/LightIndirectFunctions.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/LightIndirectFunctions.glsl new file mode 100644 index 0000000000..a658834937 --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/LightIndirectFunctions.glsl @@ -0,0 +1,51 @@ +#ifndef LIGHT_INDIRECT_FUNCTIONS_INCLUDED +#define LIGHT_INDIRECT_FUNCTIONS_INCLUDED +#include "Light.glsl" + +vec3 getReflectedVector(SurfaceData surfaceData, vec3 n) { + #ifdef MATERIAL_ENABLE_ANISOTROPY + vec3 r = reflect(-surfaceData.viewDir, surfaceData.anisotropicN); + #else + vec3 r = reflect(-surfaceData.viewDir, n); + #endif + + return r; +} + +float getSpecularMIPLevel(float roughness, int maxMIPLevel ) { + return roughness * float(maxMIPLevel); +} + +// sh need be pre-scaled in CPU. +vec3 getLightProbeRadiance(SurfaceData surfaceData, vec3 normal, float roughness) { + + #ifndef SCENE_USE_SPECULAR_ENV + return vec3(0); + #else + vec3 reflectVec = getReflectedVector(surfaceData, normal); + reflectVec.x = -reflectVec.x; // TextureCube is left-hand,so x need inverse + + float specularMIPLevel = getSpecularMIPLevel(roughness, int(scene_EnvMapLight.mipMapLevel) ); + + #ifdef HAS_TEX_LOD + vec4 envMapColor = textureCubeLodEXT( scene_EnvSpecularSampler, reflectVec, specularMIPLevel ); + #else + vec4 envMapColor = textureCube( scene_EnvSpecularSampler, reflectVec, specularMIPLevel ); + #endif + + #ifdef SCENE_IS_DECODE_ENV_RGBM + envMapColor.rgb = (RGBMToLinear(envMapColor, 5.0)).rgb; + #ifdef ENGINE_IS_COLORSPACE_GAMMA + envMapColor = linearToGamma(envMapColor); + #endif + #else + #ifndef ENGINE_IS_COLORSPACE_GAMMA + envMapColor = gammaToLinear(envMapColor); + #endif + #endif + + return envMapColor.rgb * scene_EnvMapLight.specularIntensity; + + #endif +} +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/LightIndirectPBR.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/LightIndirectPBR.glsl new file mode 100644 index 0000000000..e0f5780b58 --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/LightIndirectPBR.glsl @@ -0,0 +1,113 @@ + +#ifndef LIGHT_INDIRECT_PBR_INCLUDED +#define LIGHT_INDIRECT_PBR_INCLUDED + +#ifndef FUNCTION_DIFFUSE_IBL + #define FUNCTION_DIFFUSE_IBL evaluateDiffuseIBL +#endif +#ifndef FUNCTION_SPECULAR_IBL + #define FUNCTION_SPECULAR_IBL evaluateSpecularIBL +#endif +#ifndef FUNCTION_CLEAR_COAT_IBL + #define FUNCTION_CLEAR_COAT_IBL evaluateClearCoatIBL +#endif +#ifndef FUNCTION_SHEEN_IBL + #define FUNCTION_SHEEN_IBL evaluateSheenIBL +#endif +#include "BRDF.glsl" +#include "Light.glsl" +#include "LightIndirectFunctions.glsl" + +// ------------------------Diffuse------------------------ + +// sh need be pre-scaled in CPU. +vec3 getLightProbeIrradiance(vec3 sh[9], vec3 normal){ + normal.x = -normal.x; + vec3 result = sh[0] + + + sh[1] * (normal.y) + + sh[2] * (normal.z) + + sh[3] * (normal.x) + + + sh[4] * (normal.y * normal.x) + + sh[5] * (normal.y * normal.z) + + sh[6] * (3.0 * normal.z * normal.z - 1.0) + + sh[7] * (normal.z * normal.x) + + sh[8] * (normal.x * normal.x - normal.y * normal.y); + + return max(result, vec3(0.0)); + +} + + +void evaluateDiffuseIBL(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, inout vec3 diffuseColor){ + #ifdef SCENE_USE_SH + vec3 irradiance = getLightProbeIrradiance(scene_EnvSH, surfaceData.normal); + #ifdef ENGINE_IS_COLORSPACE_GAMMA + irradiance = (linearToGamma(vec4(irradiance, 1.0))).rgb; + #endif + irradiance *= scene_EnvMapLight.diffuseIntensity; + #else + vec3 irradiance = scene_EnvMapLight.diffuse * scene_EnvMapLight.diffuseIntensity; + irradiance *= PI; + #endif + + diffuseColor += surfaceData.diffuseAO * irradiance * BRDF_Diffuse_Lambert( brdfData.diffuseColor ); +} + +float evaluateClearCoatIBL(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, inout vec3 specularColor){ + float radianceAttenuation = 1.0; + + #ifdef MATERIAL_ENABLE_CLEAR_COAT + vec3 clearCoatRadiance = getLightProbeRadiance(surfaceData, surfaceData.clearCoatNormal, brdfData.clearCoatRoughness); + specularColor += surfaceData.specularAO * clearCoatRadiance * surfaceData.clearCoat * envBRDFApprox(brdfData.clearCoatSpecularColor, brdfData.clearCoatRoughness, surfaceData.clearCoatDotNV); + radianceAttenuation -= surfaceData.clearCoat * F_Schlick(0.04, surfaceData.clearCoatDotNV); + #endif + + return radianceAttenuation; +} + +void evaluateSpecularIBL(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, float radianceAttenuation, inout vec3 outSpecularColor){ + vec3 radiance = getLightProbeRadiance(surfaceData, surfaceData.normal, brdfData.roughness); + + #ifdef MATERIAL_ENABLE_IRIDESCENCE + vec3 speculaColor = mix(brdfData.specularColor, brdfData.iridescenceSpecularColor, surfaceData.iridesceceFactor); + #else + vec3 speculaColor = brdfData.specularColor; + #endif + + outSpecularColor += surfaceData.specularAO * radianceAttenuation * radiance * envBRDFApprox(speculaColor, brdfData.roughness, surfaceData.dotNV); +} + +void evaluateSheenIBL(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, float radianceAttenuation, inout vec3 diffuseColor, inout vec3 specularColor){ + #ifdef MATERIAL_ENABLE_SHEEN + diffuseColor *= brdfData.sheenScaling; + specularColor *= brdfData.sheenScaling; + + vec3 reflectance = surfaceData.specularAO * radianceAttenuation * brdfData.approxIBLSheenDG * surfaceData.sheenColor; + specularColor += reflectance; + #endif +} + +void evaluateIBL(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, inout vec3 color){ + vec3 diffuseColor = vec3(0); + vec3 specularColor = vec3(0); + + // IBL diffuse + FUNCTION_DIFFUSE_IBL(varyings, surfaceData, brdfData, diffuseColor); + + // IBL ClearCoat + float radianceAttenuation = FUNCTION_CLEAR_COAT_IBL(varyings, surfaceData, brdfData, specularColor); + + // IBL specular + FUNCTION_SPECULAR_IBL(varyings, surfaceData, brdfData, radianceAttenuation, specularColor); + + // IBL sheen + FUNCTION_SHEEN_IBL(varyings, surfaceData, brdfData, radianceAttenuation, diffuseColor, specularColor); + + color += diffuseColor + specularColor; + +} + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/ReflectionLobe.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/ReflectionLobe.glsl new file mode 100644 index 0000000000..e13d6062bb --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/ReflectionLobe.glsl @@ -0,0 +1,35 @@ +#ifndef REFLECTION_LOBE_INCLUDED +#define REFLECTION_LOBE_INCLUDED + +void diffuseLobe(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, vec3 attenuationIrradiance, inout vec3 diffuseColor){ + diffuseColor += attenuationIrradiance * BRDF_Diffuse_Lambert( brdfData.diffuseColor ); +} + +void specularLobe(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, vec3 incidentDirection, vec3 attenuationIrradiance, inout vec3 specularColor){ + specularColor += attenuationIrradiance * BRDF_Specular_GGX( incidentDirection, surfaceData, brdfData, surfaceData.normal, brdfData.specularColor, brdfData.roughness); +} + +void sheenLobe(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, vec3 incidentDirection, vec3 attenuationIrradiance, inout vec3 diffuseColor, inout vec3 specularColor){ + #ifdef MATERIAL_ENABLE_SHEEN + diffuseColor *= brdfData.sheenScaling; + specularColor *= brdfData.sheenScaling; + + specularColor += attenuationIrradiance * sheenBRDF(incidentDirection, surfaceData, surfaceData.sheenColor, brdfData.sheenRoughness); + #endif +} + +float clearCoatLobe(Varyings varyings, SurfaceData surfaceData, BRDFData brdfData, vec3 incidentDirection, vec3 color, inout vec3 specularColor){ + float attenuation = 1.0; + + #ifdef MATERIAL_ENABLE_CLEAR_COAT + float clearCoatDotNL = saturate( dot( surfaceData.clearCoatNormal, incidentDirection ) ); + vec3 clearCoatIrradiance = clearCoatDotNL * color; + + specularColor += surfaceData.clearCoat * clearCoatIrradiance * BRDF_Specular_GGX( incidentDirection, surfaceData, brdfData, surfaceData.clearCoatNormal, brdfData.clearCoatSpecularColor, brdfData.clearCoatRoughness ); + attenuation -= surfaceData.clearCoat * F_Schlick(0.04, surfaceData.clearCoatDotNV); + #endif + + return attenuation; +} + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/VaryingsPBR.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/VaryingsPBR.glsl new file mode 100644 index 0000000000..6e11b24b4c --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/VaryingsPBR.glsl @@ -0,0 +1,37 @@ +#ifndef VARYINGS_PBR_INCLUDED +#define VARYINGS_PBR_INCLUDED + +#include "Shadow.glsl" + +struct Varyings{ + vec2 uv; + #ifdef RENDERER_HAS_UV1 + vec2 uv1; + #endif + + #ifdef RENDERER_ENABLE_VERTEXCOLOR + vec4 vertexColor; + #endif + + vec3 positionWS; + + #if SCENE_FOG_MODE != 0 + vec3 positionVS; + #endif + + #ifdef RENDERER_HAS_NORMAL + vec3 normalWS; + #ifdef RENDERER_HAS_TANGENT + vec3 tangentWS; + vec3 bitangentWS; + #endif + #endif + + + #if defined(NEED_CALCULATE_SHADOWS) && (SCENE_SHADOW_CASCADED_COUNT == 1) + vec3 shadowCoord; + #endif +}; + + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/VertexPBR.glsl b/packages/shader-shaderlab/src/shaders/shadingPBR/VertexPBR.glsl new file mode 100644 index 0000000000..b35eb0332a --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/VertexPBR.glsl @@ -0,0 +1,102 @@ +#ifndef VERTEX_INCLUDE +#define VERTEX_INCLUDE + +#include "Transform.glsl" +#include "Skin.glsl" +#include "BlendShape.glsl" +#include "Shadow.glsl" + + +struct VertexInputs{ + vec4 positionOS; + vec3 positionWS; + + #if SCENE_FOG_MODE != 0 + vec3 positionVS; + #endif + + #ifdef RENDERER_HAS_NORMAL + vec3 normalWS; + #ifdef RENDERER_HAS_TANGENT + vec3 tangentWS; + vec3 bitangentWS; + #endif + #endif +}; + +vec4 material_TilingOffset; +vec2 getUV0(Attributes attributes){ + vec2 uv0 = vec2(0); + + #ifdef RENDERER_HAS_UV + uv0 = attributes.TEXCOORD_0; + #endif + + return uv0 * material_TilingOffset.xy + material_TilingOffset.zw; +} + +VertexInputs getVertexInputs(Attributes attributes){ + VertexInputs inputs; + vec4 position = vec4(attributes.POSITION, 1.0); + + #ifdef RENDERER_HAS_NORMAL + vec3 normal = vec3( attributes.NORMAL ); + #ifdef RENDERER_HAS_TANGENT + vec4 tangent = vec4( attributes.TANGENT ); + #endif + #endif + + + // BlendShape + #ifdef RENDERER_HAS_BLENDSHAPE + calculateBlendShape(attributes, position + #ifdef RENDERER_HAS_NORMAL + ,normal + #ifdef RENDERER_HAS_TANGENT + ,tangent + #endif + #endif + ); + #endif + + // Skin + #ifdef RENDERER_HAS_SKIN + mat4 skinMatrix = getSkinMatrix(attributes); + position = skinMatrix * position; + + #if defined(RENDERER_HAS_NORMAL) + mat3 skinNormalMatrix = INVERSE_MAT(mat3(skinMatrix)); + normal = normal * skinNormalMatrix; + #ifdef RENDERER_HAS_TANGENT + tangent.xyz = tangent.xyz * skinNormalMatrix; + #endif + #endif + #endif + + // TBN world space + #ifdef RENDERER_HAS_NORMAL + inputs.normalWS = normalize( mat3(renderer_NormalMat) * normal ); + + #ifdef RENDERER_HAS_TANGENT + vec3 tangentWS = normalize( mat3(renderer_NormalMat) * tangent.xyz ); + vec3 bitangentWS = cross( inputs.normalWS, tangentWS ) * tangent.w; + + inputs.tangentWS = tangentWS; + inputs.bitangentWS = bitangentWS; + #endif + #endif + + + inputs.positionOS = position; + vec4 positionWS = renderer_ModelMat * position; + inputs.positionWS = positionWS.xyz / positionWS.w; + + #if SCENE_FOG_MODE != 0 + vec4 positionVS = renderer_MVMat * position; + inputs.positionVS = positionVS.xyz / positionVS.w; + #endif + + return inputs; +} + +#endif \ No newline at end of file diff --git a/packages/shader-shaderlab/src/shaders/shadingPBR/index.ts b/packages/shader-shaderlab/src/shaders/shadingPBR/index.ts new file mode 100644 index 0000000000..2f34850456 --- /dev/null +++ b/packages/shader-shaderlab/src/shaders/shadingPBR/index.ts @@ -0,0 +1,23 @@ +import AttributesPBR from "./AttributesPBR.glsl"; +import BRDF from "./BRDF.glsl"; +import ForwardPassPBR from "./ForwardPassPBR.glsl"; +import FragmentPBR from "./FragmentPBR.glsl"; +import LightDirectPBR from "./LightDirectPBR.glsl"; +import LightIndirectFunctions from "./LightIndirectFunctions.glsl"; +import LightIndirectPBR from "./LightIndirectPBR.glsl"; +import ReflectionLobe from "./ReflectionLobe.glsl"; +import VaryingsPBR from "./VaryingsPBR.glsl"; +import VertexPBR from "./VertexPBR.glsl"; + +export default [ + { source: ForwardPassPBR, includeKey: "ForwardPassPBR.glsl" }, + { source: AttributesPBR, includeKey: "AttributesPBR.glsl" }, + { source: VaryingsPBR, includeKey: "VaryingsPBR.glsl" }, + { source: FragmentPBR, includeKey: "FragmentPBR.glsl" }, + { source: LightDirectPBR, includeKey: "LightDirectPBR.glsl" }, + { source: LightIndirectPBR, includeKey: "LightIndirectPBR.glsl" }, + { source: VertexPBR, includeKey: "VertexPBR.glsl" }, + { source: BRDF, includeKey: "BRDF.glsl" }, + { source: LightIndirectFunctions, includeKey: "LightIndirectFunctions.glsl" }, + { source: ReflectionLobe, includeKey: "ReflectionLobe.glsl" } +]; diff --git a/packages/shader-shaderlab/tsconfig.json b/packages/shader-shaderlab/tsconfig.json new file mode 100644 index 0000000000..588b0055c3 --- /dev/null +++ b/packages/shader-shaderlab/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "module": "esnext", + "target": "esnext", + "declaration": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "declarationDir": "types", + "emitDeclarationOnly": true, + "noImplicitOverride": true, + "sourceMap": true, + "incremental": false, + "skipLibCheck": true, + "stripInternal": true + }, + "include": ["src/**/*"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e5f8db82b6..736f18b0ee 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,7 +46,7 @@ importers: version: 6.21.0(eslint@8.57.1)(typescript@5.6.3) '@vitest/coverage-v8': specifier: 2.1.3 - version: 2.1.3(@vitest/browser@2.1.3(@types/node@18.19.64)(@vitest/spy@2.1.3)(playwright@1.48.2)(typescript@5.6.3)(vite@5.4.11(@types/node@18.19.64)(sass@1.81.0))(vitest@2.1.3))(vitest@2.1.3(@types/node@18.19.64)(@vitest/browser@2.1.3)(msw@2.6.5(@types/node@18.19.64)(typescript@5.6.3))(sass@1.81.0)) + version: 2.1.3(@vitest/browser@2.1.3)(vitest@2.1.3) bumpp: specifier: ^9.5.2 version: 9.8.1(magicast@0.3.5) @@ -247,6 +247,12 @@ importers: specifier: workspace:* version: link:../design + packages/shader-shaderlab: + devDependencies: + '@galacean/engine': + specifier: workspace:* + version: link:../galacean + packages/xr: devDependencies: '@galacean/engine': @@ -5335,7 +5341,7 @@ snapshots: - utf-8-validate - vite - '@vitest/coverage-v8@2.1.3(@vitest/browser@2.1.3(@types/node@18.19.64)(@vitest/spy@2.1.3)(playwright@1.48.2)(typescript@5.6.3)(vite@5.4.11(@types/node@18.19.64)(sass@1.81.0))(vitest@2.1.3))(vitest@2.1.3(@types/node@18.19.64)(@vitest/browser@2.1.3)(msw@2.6.5(@types/node@18.19.64)(typescript@5.6.3))(sass@1.81.0))': + '@vitest/coverage-v8@2.1.3(@vitest/browser@2.1.3)(vitest@2.1.3)': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 diff --git a/rollup.config.js b/rollup.config.js index c253121a51..4ef87b8cc7 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -28,14 +28,13 @@ const shaderLabPkg = pkgs.find((item) => item.pkgJson.name === "@galacean/engine pkgs.push({ ...shaderLabPkg, verboseMode: true }); // toGlobalName - const extensions = [".js", ".jsx", ".ts", ".tsx"]; const mainFields = NODE_ENV === "development" ? ["debug", "module", "main"] : undefined; const commonPlugins = [ resolve({ extensions, preferBuiltins: true, mainFields }), glslify({ - include: [/\.glsl$/] + include: [/\.(glsl|gs)$/] }), swc( defineRollupSwcOption({