You are browsing as a guest. Sign up (or log in) to start making projects!

7h 16m 23s logged

pbr materials :yayayayayay:


pbr math

reflectance:

this is the main equation that a cook-torrance pbr system, all the other equations lead back to this one at some point

πΏπ‘œβ‘(𝑝,πœ”π‘œ) =𝐿𝑒⁑(𝑝,πœ”π‘œ) +βˆ«Ξ©π‘“π‘Ÿβ‘(𝑝,πœ”π‘–,πœ”π‘œ)⁒𝐿𝑖⁑(𝑝,πœ”π‘–)⁒(π§β‹…πœ”π‘–)β’π‘‘β’πœ”π‘–

this equation essentially just determines what light does after hitting a surface with specific parameters

we approximate the integral with two different light interactions:

  1. diffuse (β’π‘˜π·): any light that penetrates the surface, scatters internally, and re-emerges
  2. specular (π‘˜π‘†β’): light that reflects directly off the micro-surface

in the code itself, the total outgoing radiance ($L_o$) is calculated with:

vec3 Lo = (kD * albedo / PI + specular) * radiance * NdotL;

cook-torrance brdf:

the specular component is calculated using the cook-torrance microfacet brdf:
 
⁒## 𝑓cook-torrance =𝐷⋅𝐺⋅𝐹 / 4⁒(𝐍⋅𝐕)⁒(𝐍⋅𝐋)⁒
 
where 𝐷⁒, 𝐺, and ⁒𝐹 represent:

  1. normal distribution (𝐷):

    the NDF statistical distribution calculates how many microfacets are aligned with the halfway vector ($⁒𝐇=𝐕+𝐋 / abs(𝐕+𝐋⁒))

𝐷GGX⁑(𝐍,𝐇,𝛼) = 𝛼^2 / πœ‹β’((𝐍⋅𝐇)2⁒(𝛼2βˆ’1)+1)2⁒

```glsl
float DistributionGGX(vec3 N, vec3 H, float roughness) {
    float a = roughness * roughness;
    float a2 = a * a;
    float NdotH = max(dot(N, H), 0.0);
    float NdotH2 = NdotH * NdotH;

    float num = a2;
    float denom = (NdotH2 * (a2 - 1.0) + 1.0);
    denom = PI * denom * denom;

    return num / max(denom, 0.000001);
}
```
  1. geometry (𝐺): smiths schlick-ggx

    microfacets can cast shadows and obscure light from the camera too, so the geometry function calculates the self shading factor using smiths method:
        

𝐺⁑(𝐍,𝐕,𝐋,π‘˜) =𝐺1⁑(𝐍,𝐕,π‘˜) ⋅𝐺1⁑(𝐍,𝐋,π‘˜)

     
where π‘˜β’ maps roughness for direct lighting using β’π‘˜ = (roughness+1)^2 / 8:

```glsl
float GeometrySchlickGGX(float NdotV, float roughness) {
    float r = (roughness + 1.0);
    float k = (r * r) / 8.0;

    float num = NdotV;
    float denom = NdotV * (1.0 - k) + k;

    return num / denom;
}

float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
    float NdotV = max(dot(N, V), 0.0);
    float NdotL = max(dot(N, L), 0.0);
    float ggx2 = GeometrySchlickGGX(NdotV, roughness);
    float ggx1 = GeometrySchlickGGX(NdotL, roughness);

    return ggx1 * ggx2;
}
```
  1. fresnel equation (𝐹⁑): fresnel-schlick approximation

    the fresnel factor calculates the percentage of light reflected versus absorbed based on the viewing angle (β’πœƒ):
       

𝐹⁑(πœƒ,𝐹0) =𝐹0 +(1βˆ’πΉ0)⁒(1βˆ’cosβ‘πœƒ)^5

     
nonmetals reflect around 4% of light (𝐹0 =0.04), while metals (conductors) use their tinted base albedo color as 𝐹0:

```glsl
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
    return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}

// lower, inside main():
vec3 F0 = mix(vec3(0.04), albedo, metallic);
vec3 F  = fresnelSchlick(max(dot(H, V), 0.0), F0);
```

other stuff:

a surface cant reflect more light than it recieves, so a simple equation is used to make sure this doesnt happen:
       
⁒## 𝐀𝐃 =(1βˆ’π€π’) β‹…(1βˆ’metallic)
     
right now, all the material data is pulled from a .mtl file


i also added bindless ssbo storage so it doesnt explode when you have a lot of models


next, i might keep working on the custom persistent ui system

0
7

Comments 0

No comments yet. Be the first!