- Making the original
- Let’s go straight to Shader
- It’s confusing to see something else
Vertex shader
- It’s basically computing normal vectors
#define USE_MATHS 1
#define USE_IBL 1
#define HAS_UV 1
#define HAS_NORMALS 1
#define HAS_TANGENTS 1
#define HAS_BASECOLORMAP 1
#define HAS_METALROUGHNESSMAP 1
#define HAS_NORMALMAP 1
#define HAS_OCCLUSIONMAP 1
#define USE_TEX_LOD 1
attribute vec4 a_Position; // Write vec4 with only three inputs. The last one defaults to 1.0?
#ifdef HAS_NORMALS
attribute vec4 a_Normal;
#endif
#ifdef HAS_TANGENTS
attribute vec4 a_Tangent;
#endif
#ifdef HAS_UV
attribute vec2 a_UV;
#endif
uniform mat4 u_mvpMatrix;
uniform mat4 u_NormalMatrix;
varying vec3 v_Position;
varying vec2 v_UV;
#ifdef HAS_NORMALS
#ifdef HAS_TANGENTS
varying mat3 v_TBN;
#else
varying vec3 v_Normal;
#endif
#endif
void main() {
//u_NormalMatrix is the model matrix
vec4 pos = u_NormalMatrix * a_Position;
v_Position = vec3(pos.xyz) / pos.w;
#ifdef HAS_NORMALS
#ifdef HAS_TANGENTS
vec3 normalW = normalize(vec3(u_NormalMatrix * vec4(a_Normal.xyz, 0.0)));
vec3 tangentW = normalize(vec3(u_NormalMatrix * vec4(a_Tangent.xyz, 0.0)));
vec3 bitangentW = cross(normalW, tangentW) * a_Tangent.w; //*w is not what I expected
v_TBN = mat3(tangentW, bitangentW, normalW); //TBN
#else // HAS_TANGENTS ! = 1
v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));
#endif
#endif
gl_Position = u_mvpMatrix * a_Position; // needs w for proper perspective correction
}
Copy the code
Chip shader
IBL map
#ifdef USE_IBL
uniform samplerCube u_DiffuseEnvSampler;
uniform samplerCube u_SpecularEnvSampler; // There are 60 cards in it
uniform sampler2D u_brdfLUT;
#endif
Copy the code
- U_DiffuseEnvSampler six
- U_SpecularEnvSampler has 60 specularenvroughness levels
- U_brdfLUT is a
Normal vector calculation
#ifndef HAS_TANGENTS
vec3 pos_dx = dFdx(v_Position);
vec3 pos_dy = dFdy(v_Position);
vec3 tex_dx = dFdx(vec3(v_UV, 0.0));
vec3 tex_dy = dFdy(vec3(v_UV, 0.0));
vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);
#ifdef HAS_NORMALS
vec3 ng = normalize(v_Normal);
#else
vec3 ng = cross(pos_dx, pos_dy);
#endif
t = normalize(t - ng * dot(ng, t));
vec3 b = normalize(cross(ng, t));
mat3 tbn = mat3(t, b, ng);
#else // HAS_TANGENTS && HAS_NORMALS
mat3 tbn = v_TBN;
#endif
Copy the code
#ifdef HAS_NORMALMAP
vec3 n = texture2D(u_NormalSampler, v_UV).rgb; / / [0 ~ 1]
n = normalize(tbn * (2.0 * n - 1.0)); / / [1 ~ 1]
#else
vec3 n = tbn[2].xyz;
#endif
Copy the code
You know the vectors and the angles between them
vec3 v = normalize(u_Camera - v_Position); //view
vec3 l = normalize(u_LightDirection); //light
vec3 h = normalize(l+v); //half
vec3 reflection = -normalize(reflect(v, n)); // reflection
float NdotL = clamp(dot(n, l), 0.0.1.0);
float NdotV = clamp(dot(n, v), 0.0.1.0);
float NdotH = clamp(dot(n, h), 0.0.1.0);
float LdotH = clamp(dot(l, h), 0.0.1.0);
float VdotH = clamp(dot(v, h), 0.0.1.0);
Copy the code
Metallicity/roughness
- Metal (only 0 and 1)
- roughness
#ifdef HAS_METALROUGHNESSMAP
vec4 mrSample = texture2D(u_MetallicRoughnessSampler, v_UV);
float roughness = clamp(mrSample.g, 0.04.1.0);
float metallic = clamp(mrSample.b, 0.0.1.0);
#else
float roughness = clamp(u_MetallicRoughnessValues.y, 0.04.1.0);
float metallic = u_MetallicRoughnessValues.x;
#endif
Copy the code
BaseColor
#ifdef HAS_BASECOLORMAP
vec3 baseColor = texture2D(u_BaseColorSampler, v_UV).rgb;
#else
vec3 baseColor = vec3(1.0.1.0.1.0);
#endif
Copy the code
F0 and I don’t know how these two colors work out, right
vec3 f0 = vec3(0.04);
vec3 diffuseColor = mix(baseColor.rgb * (1.0 - f0), vec3(0..0..0.), metallic); // Metallicity to calculate diffuse
vec3 specularColor = mix(f0, baseColor, metallic); //F0 is related to specular.
Copy the code
What is the purpose of calculating the reflection coefficient of 90
float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
float reflectance90 = clamp(reflectance * 25.0.0.0.1.0);
Copy the code
Plug in F0, what’s R90
vec3 specularEnvironmentR0 = specularColor.rgb; F0 = mix(F0, albedo, metallic);
vec3 specularEnvironmentR90 = vec3(1.0.1.0.1.0) * reflectance90;
Copy the code
PBRinfo
struct PBRInfo {
float NdotL;
float NdotV;
float NdotH;
float LdotH;
float VdotH;
float roughness;
float metalness;
vec3 baseColor;
vec3 reflectance0; / / specularEnvironmentR0 is F0
vec3 reflectance90; //specularEnvironmentR90
};
Copy the code
Calculate Fresnel F
vec3 fresnelSchlick2(PBRInfo pbrInputs) {
return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0.1.0), 5.0);
}
Copy the code
Calculate GGX
float SmithVisibilityGGX(PBRInfo pbrInputs) {
return SmithVisibilityG1_var2(pbrInputs.NdotL, pbrInputs.roughness) * SmithVisibilityG1_var2(pbrInputs.NdotV, pbrInputs.roughness);
}
float SmithVisibilityG1_var2(float NdotV, float r) {
float tanSquared = (1.0 - NdotV * NdotV) / max((NdotV * NdotV), 0.00001);
return 2.0 / (1.0 + sqrt(1.0 + r * r * tanSquared));
}
Copy the code
Calculate D
float GGX(PBRInfo pbrInputs) {
float roughnessSq = pbrInputs.roughness*pbrInputs.roughness;
float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0;
return roughnessSq / (M_PI * f * f);
}
Copy the code
Calculate the diffuse part of direct illumination
vec3 diffuseContrib = (1.0 - F) * lambertianDiffuse(pbrInputs) * NdotL * u_LightColor;
vec3 lambertianDiffuse(PBRInfo pbrInputs) {
return pbrInputs.baseColor / M_PI;
}
Copy the code
Calculate the specular reflection of direct illumination
vec3 specContrib = M_PI * u_LightColor * F * G * D / 4.0*NdotL*NdotV;
Copy the code
Direct illumination BRDF is calculated
vec3 color = (diffuseContrib + specContrib);
Copy the code
Calculate BRDF of indirect illumination and see the formula below
- finalColor = (diffuseLight + diffuseColor) + (specularLight * (specularColor * brdf.x + brdf.y))
#ifdef USE_IBL
float mipCount = 9.0; // Resolution of 512x512 //10 order roughness
float lod = (roughness * mipCount); // LoD range [0-9]
vec3 brdf = texture2D(u_brdfLUT, vec2(NdotV, 1.0 - roughness)).rgb; //brdf
vec3 diffuseLight = textureCube(u_DiffuseEnvSampler, n).rgb; / / the ambient light
#ifdef USE_TEX_LOD
vec3 specularLight = textureCubeLodEXT(u_SpecularEnvSampler, reflection, lod).rgb; Reflection is the roughness directed by reflection
#else
vec3 specularLight = textureCube(u_SpecularEnvSampler, reflection).rgb; ///
#endif
vec3 IBLcolor = (diffuseLight * diffuseColor * u_scaleIBLAmbient.x) + (specularLight * (specularColor * brdf.x + brdf.y) *u_scaleIBLAmbient.y);
color += IBLcolor; / / plus the IBL
#endif
Copy the code
The ao map
#ifdef HAS_OCCLUSIONMAP
float ao = texture2D(u_OcclusionSampler, v_UV).r; //r
color *= ao; / / multiplied
#endif
Copy the code
Self-illumination map
#ifdef HAS_EMISSIVEMAP
vec3 emissive = texture2D(u_EmissiveSampler, v_UV).rgb;
color += emissive; // Add it directly
#endif
Copy the code
#define USE_MATHS 1
#define USE_IBL 1
#define HAS_UV 1
#define HAS_NORMALS 1
#define HAS_TANGENTS 1
#define HAS_BASECOLORMAP 1
#define HAS_METALROUGHNESSMAP 1
#define HAS_NORMALMAP 1
#define HAS_EMISSIVEMAP 1
#define HAS_OCCLUSIONMAP 1
#define USE_TEX_LOD 1
#extension GL_EXT_shader_texture_lod: enable
#extension GL_OES_standard_derivatives : enable
precision highp float;
uniform vec3 u_LightDirection;
uniform vec3 u_LightColor;
#ifdef USE_IBL
uniform samplerCube u_DiffuseEnvSampler;
uniform samplerCube u_SpecularEnvSampler;
uniform sampler2D u_brdfLUT;
#endif
#ifdef HAS_BASECOLORMAP
uniform sampler2D u_BaseColorSampler;
#endif
#ifdef HAS_NORMALMAP
uniform sampler2D u_NormalSampler;
#endif
#ifdef HAS_EMISSIVEMAP
uniform sampler2D u_EmissiveSampler;
#endif
#ifdef HAS_METALROUGHNESSMAP
uniform sampler2D u_MetallicRoughnessSampler;
#else
uniform vec2 u_MetallicRoughnessValues;
#endif
#ifdef HAS_OCCLUSIONMAP
uniform sampler2D u_OcclusionSampler;
#endif
uniform vec3 u_Camera;
uniform vec4 u_scaleDiffBaseMR;
uniform vec4 u_scaleFGDSpec;
uniform vec4 u_scaleIBLAmbient;
varying vec3 v_Position;
varying vec2 v_UV;
#ifdef HAS_NORMALS
#ifdef HAS_TANGENTS
varying mat3 v_TBN;
#else
varying vec3 v_Normal;
#endif
#endif
struct PBRInfo {
float NdotL;
float NdotV;
float NdotH;
float LdotH;
float VdotH;
float roughness;
float metalness;
vec3 baseColor;
vec3 reflectance0;
vec3 reflectance90;
};
const float M_PI = 3.141592653589793;
// diffuse
vec3 disneyDiffuse(PBRInfo pbrInputs) {
float f90 = 2.*pbrInputs.LdotH*pbrInputs.LdotH*pbrInputs.roughness - 0.5;
return (pbrInputs.baseColor/M_PI)*(1.0+f90*pow((1.0-pbrInputs.NdotL), 5.0)) * (1.0+f90*pow((1.0-pbrInputs.NdotV), 5.0));
}
vec3 lambertianDiffuse(PBRInfo pbrInputs) {
return pbrInputs.baseColor / M_PI;
}
// F
// r
vec3 fresnelSchlick2(PBRInfo pbrInputs) {
return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0.1.0), 5.0);
}
vec3 fresnelSchlick(PBRInfo pbrInputs) {
return pbrInputs.metalness + (vec3(1.0) - pbrInputs.metalness) * pow(1.0 - pbrInputs.VdotH, 5.0);
}
// G
float microfacetCookTorrance(PBRInfo pbrInputs) {
return min(min(2.*pbrInputs.NdotV*pbrInputs.NdotH/pbrInputs.VdotH, 2.*pbrInputs.NdotL*pbrInputs.NdotH/pbrInputs.VdotH), 1.0);
}
float microfacetSchlick(PBRInfo pbrInputs) {
float k = pbrInputs.roughness * 0.79788; / / 0.79788 = SQRT (2.0/3.1415);
// alternately, k can be defined with
// float k = (pbrInputs.roughness + 1)*(pbrInputs.roughness + 1)/8;
float l = pbrInputs.LdotH / (pbrInputs.LdotH * (1.0 - k) + k);
float n = pbrInputs.NdotH / (pbrInputs.NdotH * (1.0 - k) + k);
return l * n;
}
float microfacetSmith_var1(PBRInfo pbrInputs) {
float NdotL2 = pbrInputs.NdotL * pbrInputs.NdotL;
float NdotV2 = pbrInputs.NdotV * pbrInputs.NdotV;
float v = ( 1. + sqrt ( pbrInputs.roughness * (1. - NdotL2 ) / NdotL2 + 1.)) * 0.5;
float l = ( 1. + sqrt ( pbrInputs.roughness * (1. - NdotV2 ) / NdotV2 + 1.)) * 0.5;
return (1. / max((1. + v + l ), 0.000001));
}
float SmithVisibilityG1_var2(float NdotV, float r) {
float tanSquared = (1.0 - NdotV * NdotV) / max((NdotV * NdotV), 0.00001);
return 2.0 / (1.0 + sqrt(1.0 + r * r * tanSquared));
}
float SmithG1(float NdotV, float r) {
return 2.0 * NdotV / (NdotV + sqrt(r*r+(1.0-r*r)*(NdotV*NdotV)));
}
float SmithVisibilityGGX(PBRInfo pbrInputs) {
return SmithVisibilityG1_var2(pbrInputs.NdotL, pbrInputs.roughness) * SmithVisibilityG1_var2(pbrInputs.NdotV, pbrInputs.roughness);
}
// D
float GGX(PBRInfo pbrInputs) {
float roughnessSq = pbrInputs.roughness*pbrInputs.roughness;
float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0;
return roughnessSq / (M_PI * f * f);
}
void main() {
// Normal Map
#ifndef HAS_TANGENTS
vec3 pos_dx = dFdx(v_Position);
vec3 pos_dy = dFdy(v_Position);
vec3 tex_dx = dFdx(vec3(v_UV, 0.0));
vec3 tex_dy = dFdy(vec3(v_UV, 0.0));
vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);
#ifdef HAS_NORMALS
vec3 ng = normalize(v_Normal);
#else
vec3 ng = cross(pos_dx, pos_dy);
#endif
t = normalize(t - ng * dot(ng, t));
vec3 b = normalize(cross(ng, t));
mat3 tbn = mat3(t, b, ng);
#else // HAS_TANGENTS && HAS_NORMALS
mat3 tbn = v_TBN;
#endif
#ifdef HAS_NORMALMAP
vec3 n = texture2D(u_NormalSampler, v_UV).rgb;
n = normalize(tbn * (2.0 * n - 1.0));
#else
vec3 n = tbn[2].xyz;
#endif
vec3 v = normalize(u_Camera - v_Position);
vec3 l = normalize(u_LightDirection);
vec3 h = normalize(l+v);
vec3 reflection = -normalize(reflect(v, n));
float NdotL = clamp(dot(n, l), 0.0.1.0);
float NdotV = clamp(dot(n, v), 0.0.1.0);
float NdotH = clamp(dot(n, h), 0.0.1.0);
float LdotH = clamp(dot(l, h), 0.0.1.0);
float VdotH = clamp(dot(v, h), 0.0.1.0);
#ifdef HAS_METALROUGHNESSMAP
vec4 mrSample = texture2D(u_MetallicRoughnessSampler, v_UV);
float roughness = clamp(mrSample.g, 0.04.1.0);
float metallic = clamp(mrSample.b, 0.0.1.0);
#else
float roughness = clamp(u_MetallicRoughnessValues.y, 0.04.1.0);
float metallic = u_MetallicRoughnessValues.x;
#endif
#ifdef HAS_BASECOLORMAP
vec3 baseColor = texture2D(u_BaseColorSampler, v_UV).rgb;
#else
vec3 baseColor = vec3(1.0.1.0.1.0);
#endif
vec3 f0 = vec3(0.04);
// is this the same? test!
vec3 diffuseColor = mix(baseColor.rgb * (1.0 - f0), vec3(0..0..0.), metallic);
// Vec3 diffuseColor = baseColor * (1.0-metallic);
vec3 specularColor = mix(f0, baseColor, metallic);
#ifdef USE_MATHS
// Compute reflectance.
float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
// For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
// For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
float reflectance90 = clamp(reflectance * 25.0.0.0.1.0);
vec3 specularEnvironmentR0 = specularColor.rgb;
vec3 specularEnvironmentR90 = vec3(1.0.1.0.1.0) * reflectance90;
PBRInfo pbrInputs = PBRInfo(
NdotL, NdotV, NdotH, LdotH, VdotH, roughness, metallic, diffuseColor, specularEnvironmentR0, specularEnvironmentR90
);
vec3 F = fresnelSchlick2(pbrInputs);
//vec3 F = fresnelSchlick(pbrInputs);
//float G = microfacetCookTorrance(pbrInputs);
//float G = microfacetSmith(pbrInputs);
//float G = microfacetSchlick(pbrInputs);
float G = SmithVisibilityGGX(pbrInputs);
float D = GGX(pbrInputs);
vec3 diffuseContrib = (1.0 - F) * lambertianDiffuse(pbrInputs) * NdotL * u_LightColor;
// Vec3 diffuseContrib = (1.0-f) * disneyDiffuse(pbrInputs) * NdotL * u_LightColor;
vec3 specContrib = M_PI * u_LightColor * F * G * D / 4.0*NdotL*NdotV;
vec3 color = (diffuseContrib + specContrib);
#endif
#ifdef USE_IBL
float mipCount = 9.0; // resolution of 512x512
float lod = (roughness * mipCount);
vec3 brdf = texture2D(u_brdfLUT, vec2(NdotV, 1.0 - roughness)).rgb;
vec3 diffuseLight = textureCube(u_DiffuseEnvSampler, n).rgb;
#ifdef USE_TEX_LOD
vec3 specularLight = textureCubeLodEXT(u_SpecularEnvSampler, reflection, lod).rgb; // This is correct
#else
vec3 specularLight = textureCube(u_SpecularEnvSampler, reflection).rgb;
#endif
vec3 IBLcolor = (diffuseLight * diffuseColor * u_scaleIBLAmbient.x) + (specularLight * (specularColor * brdf.x + brdf.y) *u_scaleIBLAmbient.y);
color += IBLcolor;
#endif
#ifdef HAS_OCCLUSIONMAP
float ao = texture2D(u_OcclusionSampler, v_UV).r;
color *= ao;
#endif
#ifdef HAS_EMISSIVEMAP
vec3 emissive = texture2D(u_EmissiveSampler, v_UV).rgb;
color += emissive;
#endif
#ifdef USE_MATHS
// mix in overrides
color = mix(color, F, u_scaleFGDSpec.x);
color = mix(color, vec3(G), u_scaleFGDSpec.y);
color = mix(color, vec3(D), u_scaleFGDSpec.z);
color = mix(color, specContrib, u_scaleFGDSpec.w);
color = mix(color, diffuseContrib, u_scaleDiffBaseMR.x);
color = mix(color, baseColor, u_scaleDiffBaseMR.y);
color = mix(color, vec3(metallic), u_scaleDiffBaseMR.z);
color = mix(color, vec3(roughness), u_scaleDiffBaseMR.w);
#endif
gl_FragColor = vec4(color, 1.0);
//gl_FragColor = vec4(n * 0.5 + 0.5, 1.0);
//gl_FragColor = vec4(NdotV, NdotV, NdotV, 1.0);
//gl_FragColor = vec4(v_uv. rg, 0.0, 1.0);
}
Copy the code