PlayCanvas PBR材质shader代码分析(pixel shader)
#version 300 es #define varying in out highp vec4 pc_fragColor; #define gl_FragColor pc_fragColor #define texture2D texture #define textureCube texture #define texture2DProj textureProj #define texture2DLodEXT textureLod #define texture2DProjLodEXT textureProjLod #define textureCubeLodEXT textureLod #define texture2DGradEXT textureGrad #define texture2DProjGradEXT textureProjGrad #define textureCubeGradEXT textureGrad #define GL2 precision highp float; #ifdef GL2 precision highp sampler2DShadow; #endif varying vec3 vPositionW; varying vec3 vNormalW; uniform vec3 view_position; uniform vec3 light_globalAmbient; float square(float x) { return x*x; } float saturate(float x) { return clamp(x, 0.0, 1.0); } vec3 saturate(vec3 x) { return clamp(x, vec3(0.0), vec3(1.0)); } vec4 dReflection; vec3 dAlbedo; vec3 dNormalW; vec3 dVertexNormalW; vec3 dViewDirW; vec3 dReflDirW; vec3 dDiffuseLight; vec3 dSpecularLight; vec3 dSpecularity; float dGlossiness; float dAlpha; void getNormal() { dNormalW = normalize(dVertexNormalW); } vec3 gammaCorrectInput(vec3 color) { return pow(color, vec3(2.2)); } float gammaCorrectInput(float color) { return pow(color, 2.2); } vec4 gammaCorrectInput(vec4 color) { return vec4(pow(color.rgb, vec3(2.2)), color.a); } vec4 texture2DSRGB(sampler2D tex, vec2 uv) { vec4 rgba = texture2D(tex, uv); rgba.rgb = gammaCorrectInput(rgba.rgb); return rgba; } vec4 texture2DSRGB(sampler2D tex, vec2 uv, float bias) { vec4 rgba = texture2D(tex, uv, bias); rgba.rgb = gammaCorrectInput(rgba.rgb); return rgba; } vec4 textureCubeSRGB(samplerCube tex, vec3 uvw) { vec4 rgba = textureCube(tex, uvw); rgba.rgb = gammaCorrectInput(rgba.rgb); return rgba; } vec3 gammaCorrectOutput(vec3 color) { #ifdef HDR return color; #else color += vec3(0.0000001); return pow(color, vec3(0.45)); #endif } uniform float exposure; // 线性toneMap整体颜色亮度调节 vec3 toneMap(vec3 color) { return color * exposure; } vec3 addFog(vec3 color) { return color; } // 这里RGBM解码是pc引擎专门修改过的 编码做了pow(0.5) 最大值调整为了8.0 vec3 decodeRGBM(vec4 rgbm) { vec3 color = (8.0 * rgbm.a) * rgbm.rgb; return color * color; } vec3 texture2DRGBM(sampler2D tex, vec2 uv) { return decodeRGBM(texture2D(tex, uv)); } vec3 textureCubeRGBM(samplerCube tex, vec3 uvw) { return decodeRGBM(textureCube(tex, uvw)); } vec3 fixSeams(vec3 vec, float mipmapIndex) { float scale = 1.0 - exp2(mipmapIndex) / 128.0; float M = max(max(abs(vec.x), abs(vec.y)), abs(vec.z)); if (abs(vec.x) != M) vec.x *= scale; if (abs(vec.y) != M) vec.y *= scale; if (abs(vec.z) != M) vec.z *= scale; return vec; } vec3 fixSeams(vec3 vec) { float scale = 1.0 - 1.0 / 128.0; float M = max(max(abs(vec.x), abs(vec.y)), abs(vec.z)); if (abs(vec.x) != M) vec.x *= scale; if (abs(vec.y) != M) vec.y *= scale; if (abs(vec.z) != M) vec.z *= scale; return vec; } vec3 fixSeamsStatic(vec3 vec, float invRecMipSize) { float scale = invRecMipSize; float M = max(max(abs(vec.x), abs(vec.y)), abs(vec.z)); if (abs(vec.x) != M) vec.x *= scale; if (abs(vec.y) != M) vec.y *= scale; if (abs(vec.z) != M) vec.z *= scale; return vec; } vec3 cubeMapProject(vec3 dir) { return dir; } vec3 processEnvironment(vec3 color) { return color; } #undef MAPFLOAT #undef MAPCOLOR #undef MAPVERTEX #undef MAPTEXTURE #ifdef MAPCOLOR uniform vec3 material_diffuse; #endif #ifdef MAPTEXTURE uniform sampler2D texture_diffuseMap; #endif // 获取基础色 void getAlbedo() { dAlbedo = vec3(1.0); #ifdef MAPCOLOR dAlbedo *= material_diffuse.rgb; #endif #ifdef MAPTEXTURE dAlbedo *= texture2DSRGB(texture_diffuseMap, UV).CH; #endif #ifdef MAPVERTEX dAlbedo *= gammaCorrectInput(saturate(vVertexColor.VC)); #endif } #undef MAPFLOAT #undef MAPCOLOR #define MAPCOLOR #undef MAPVERTEX #undef MAPTEXTURE #ifdef MAPCOLOR uniform vec3 material_emissive; #endif #ifdef MAPFLOAT uniform float material_emissiveIntensity; #endif #ifdef MAPTEXTURE uniform sampler2D texture_emissiveMap; #endif // 获取自发光颜色 vec3 getEmission() { vec3 emission = vec3(1.0); #ifdef MAPFLOAT emission *= material_emissiveIntensity; #endif #ifdef MAPCOLOR emission *= material_emissive; #endif #ifdef MAPTEXTURE emission *= texture2DSAMPLE(texture_emissiveMap, UV).CH; #endif #ifdef MAPVERTEX emission *= gammaCorrectInput(saturate(vVertexColor.VC)); #endif return emission; } float antiAliasGlossiness(float power) { return power; } #undef MAPFLOAT #define MAPFLOAT #undef MAPCOLOR #undef MAPVERTEX #undef MAPTEXTURE // 通过金属性计算各个颜色通道镜面反射强度系数,调整基础色颜色亮度 void processMetalness(float metalness) { const float dielectricF0 = 0.04; dSpecularity = mix(vec3(dielectricF0), dAlbedo, metalness); dAlbedo *= 1.0 - metalness; } #ifdef MAPFLOAT uniform float material_metalness; #endif #ifdef MAPTEXTURE uniform sampler2D texture_metalnessMap; #endif // 获取镜面反射强度系数 void getSpecularity() { float metalness = 1.0; #ifdef MAPFLOAT metalness *= material_metalness; #endif #ifdef MAPTEXTURE metalness *= texture2D(texture_metalnessMap, UV).CH; #endif #ifdef MAPVERTEX metalness *= saturate(vVertexColor.VC); #endif processMetalness(metalness); } #undef MAPFLOAT #define MAPFLOAT #undef MAPCOLOR #undef MAPVERTEX #undef MAPTEXTURE #ifdef MAPFLOAT uniform float material_shininess; #endif #ifdef MAPTEXTURE uniform sampler2D texture_glossMap; #endif // 计算光泽度 void getGlossiness() { dGlossiness = 1.0; #ifdef MAPFLOAT dGlossiness *= material_shininess; #endif #ifdef MAPTEXTURE dGlossiness *= texture2D(texture_glossMap, UV).CH; #endif #ifdef MAPVERTEX dGlossiness *= saturate(vVertexColor.VC); #endif dGlossiness += 0.0000001; } // Schlick's approximation uniform float material_fresnelFactor; // unused // 计算菲尼尔系数并且调整镜面反射系数 void getFresnel() { float fresnel = 1.0 - max(dot(dNormalW, dViewDirW), 0.0); float fresnel2 = fresnel * fresnel; fresnel *= fresnel2 * fresnel2; fresnel *= dGlossiness * dGlossiness; dSpecularity = dSpecularity + (1.0 - dSpecularity) * fresnel; } #ifndef PMREM4 #define PMREM4 uniform samplerCube texture_prefilteredCubeMap128; #endif uniform float material_reflectivity; // 添加ibl全局光镜面反射颜色 void addReflection() { float bias = saturate(1.0 - dGlossiness) * 5.0; // multiply by max mip level #ifdef ENABLE_ENVROT vec3 fixedReflDir = fixSeams(cubeMapProject(environmentRotate(dReflDirW)), bias); #else vec3 fixedReflDir = fixSeams(cubeMapProject(dReflDirW), bias); #endif fixedReflDir.x *= -1.0; vec3 refl = processEnvironment(decodeRGBM( textureCubeLodEXT(texture_prefilteredCubeMap128, fixedReflDir, bias) ).rgb); dReflection += vec4(refl, material_reflectivity); } // 漫反射 * 基础色 * (1.0 - 镜面反射强度) + (镜面反射 + 环境反射) * 镜面反射强度 // 这里漫反射包含了直接光+ibl全局光 vec3 combineColor() { return mix(dAlbedo * dDiffuseLight, dSpecularLight + dReflection.rgb * dReflection.a, dSpecularity); } #ifndef PMREM4 #define PMREM4 uniform samplerCube texture_prefilteredCubeMap128; #endif // 获取ibl全局光漫反射颜色 void addAmbient() { #ifdef ENABLE_ENVROT vec3 fixedReflDir = fixSeamsStatic(environmentRotate(dNormalW), 1.0 - 1.0 / 4.0); #else vec3 fixedReflDir = fixSeamsStatic(dNormalW, 1.0 - 1.0 / 4.0); #endif fixedReflDir.x *= -1.0; dDiffuseLight += processEnvironment(decodeRGBM( textureCubeLodEXT(texture_prefilteredCubeMap128, fixedReflDir, 5.0) ).rgb); } // 获取V向量 void getViewDir() { dViewDirW = normalize(view_position - vPositionW); } // 获取R向量 void getReflDir() { dReflDirW = normalize(-reflect(dViewDirW, dNormalW)); } void main(void) { // 漫反射颜色 dDiffuseLight = vec3(0); // 镜面反射颜色 dSpecularLight = vec3(0); // ibl全局环境反射 dReflection = vec4(0); // 镜面反射强度系数 dSpecularity = vec3(0); // 顶点世界空间法线 dVertexNormalW = vNormalW; dAlpha = 1.0; getViewDir();// 计算 view - pos getNormal();// 计算世界空间法线 getReflDir();// 计算反射方向 getAlbedo();// 计算基础色,一般走diffuseMap、顶点颜色、材质diffuse颜色直接取出 getSpecularity();// 计算镜面反射强度系数, 镜面反射强度通过金属性系数来计算,金属性越强反射强度越大漫反射越弱,金属性越弱反射强度越小漫反射颜色越强,从而漫反射和镜面反射遵循能量守恒 getGlossiness();// 计算光泽度(相当于粗糙度的相反叫法) 通过外部给材质设定系数或者走光泽度贴图获取 getFresnel(); // 计算菲尼尔效果 addAmbient(); // 计算环境光颜色(间接光漫反射颜色) addReflection(); // 计算环境光反射(间接光镜面高光颜色) gl_FragColor.rgb = combineColor(); // 组合漫反射、基础色、镜面反射输出颜色 gl_FragColor.rgb += getEmission(); // 累加自发光颜色 gl_FragColor.rgb = addFog(gl_FragColor.rgb); // 雾化效果计算 #ifndef HDR gl_FragColor.rgb = toneMap(gl_FragColor.rgb); // tonemap计算 gl_FragColor.rgb = gammaCorrectOutput(gl_FragColor.rgb);// gamma矫正回到gama颜色空间 #endif gl_FragColor.a = 1.0; }