Hi! I'm trying to write a shader that replicates the lighting of the StandardMaterial, because I want to make some small modifications, but I'm a little stumped. My diffuse lighting looks exactly like in the standard material (see this post), but I can't get the specular lights right.

I've tried to use the following code from the Godot github repo (lines 214-222):
vec3 H = normalize(V + L);
float cNdotH = max(dot(N, H), 0.0);
float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25;
float blinn = pow(cNdotH, shininess) * cNdotL;
blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
specular_brdf_NL = blinn;
specular += specular_brdf_NL * light_color * (1.0 / M_PI);

But it makes the specular lighting a lot brighter than in the standard material.

Anyone here that could point me in the right direction?

There's actually a built-in way to get Godot to write the StandardMaterial3D code you want to copy for you. First, start with using a StandardMaterial3D assigned to a GeometryInstance3D. Set it up with the features you want, including specular. Then, go to where you initially assigned the material, right click, and there will be a new option: Convert to Shader Material

Click that and it will turn into a ShaderMaterial as well as generate and attach a shader doing everything you had the StandardMaterial3D doing. The shader is embedded in the material, but you can save it out into your resource folder.

Unfortunately, shaders generated in this way don't include a light() function.

Since that's the part I'm interested in, this feature doesn't help much in this case. 😕

    xyz Ah, well that explains that.

    I took a look at the Schlick-GGX implementation found here (starting at line 1147), and porting it resulted in something that much more resembles the default material (though it's not completely identical yet).

    For anyone else who's interested, here's my current (very quick & messy) port job.

    `float D_GGX(float cos_theta_m, float alpha)
    {
    float alpha2 = alpha * alpha;
    float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m;
    return alpha2 / (PI * d * d);
    }

    float G_GGX_2cos(float cos_theta_m, float alpha)
    {
    float k = 0.5 * alpha;
    return 0.5 / (cos_theta_m * (1.0 - k) + k);
    }

    vec3 F0(float metallic, float specular, vec3 albedo)
    {
    float dielectric = 0.16 * specular * specular;
    return mix(vec3(dielectric), albedo, vec3(metallic));
    }


    float SchlickFresnel(float u)
    {
    float m = 1.0 - u;
    float m2 = m * m;
    return m2 * m2 * m;
    }

    void light()
    {
    vec3 lightColor = LIGHT_COLOR / PI;


    // Diffuse light.
    float NdotL = max(dot(NORMAL, LIGHT), 0.0);
    DIFFUSE_LIGHT += clamp(dot(NORMAL, LIGHT), 0.0, 1.0) * ATTENUATION * lightColor;
    
    // Specular light.
    vec3 halfway = normalize(VIEW + LIGHT);
    float NdotH = max(dot(NORMAL, halfway), 0.0);
    float LdotH = max(dot(LIGHT, halfway), 0.0);
    float NdotV = max(dot(NORMAL, VIEW), 0.0);
    
    float alpha_ggx = ROUGHNESS * ROUGHNESS;
    float D = D_GGX(NdotH, alpha_ggx);
    float G = G_GGX_2cos(NdotL, alpha_ggx) * G_GGX_2cos(NdotV, alpha_ggx);    
    
    vec3 f0 = F0(METALLIC, SPECULAR_AMOUNT, ALBEDO);
    float cLdotH5 = SchlickFresnel(LdotH);
    vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0);
    
    vec3 specular_brdf_NL = NdotL * D * F * G;
    
    float specular_blob_intensity = 0.25;
    SPECULAR_LIGHT += specular_brdf_NL * LIGHT_COLOR * specular_blob_intensity * ATTENUATION;

    }`

    Thanks for the help!

    Alright, I did some more tinkering, and I seem to have hammered out out a light function that looks identical to the 4.1.1 standard material shader (with the diffuse mode set to Lambert and the specular mode set to SchlickGGX).

    For anyone who's interested, here is the full shader code (the forum doesn't seem to like it when I post large blocks of code here), to use as a starting point for shaders with a custom light function.

    • xyz replied to this.

      David_J the forum doesn't seem to like it when I post large blocks of code here

      It will like it if you enclose the code in ~~~ tags