I want to write a custom light shader for water(so that light reflects off of the surface in little specks), but I haven't been able to find anything on light shaders. All I have is this:

DIFFUSE_LIGHT += dot(NORMAL, LIGHT) * ATTENUATION * ALBEDO;

The default light shader would be a good place to start. Does anyone know where to learn about light shaders, or where I can find the default light shader? Thanks.

I don't know if I've seen the second page, very useful. I do have some questions: LIGHT is a vector. Is it the direction of the light? ATTENUATION is also a vector, what does that mean? Is NORMAL just the normal, or normal + normal map? How might specular light be calculated?

In the shader code @SIsilicon28 linked, I found the part where specular light is calculated(blinn):

	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));
	float intensity = blinn;

	specular_light += light_color * intensity * specular_blob_intensity * attenuation;

Judging from a glance, I believe that's phong based specular.

Yes, Blinn adapted the Phong shading from a purely vertex shader into a pixel shader if I recall my CG history correctly.

15 days later

I did some research on specular shaders, and I got this:

void light() {
	DIFFUSE_LIGHT += dot(NORMAL, LIGHT) * ATTENUATION * ALBEDO;
	vec3 H = normalize(VIEW + LIGHT);
	float NdotH = max(0, dot(NORMAL, H));
	float specular = pow(NdotH, specular_power) * specular_strength * ATTENUATION.x;
	SPECULAR_LIGHT += specular * specular_color.rgb;
}

I don't know why ATTENUATION is a vec3, so I used ATTENUATION.x.

If I set specular_power to a high value(10,000) and specular color to a high value(5,5,5), then I get closer to the effect I want: I want it to look glittery, kind of the same way water glitters in the real world. Tell me if you have any suggestions.

Actually, I think it looks a little better with specular disabled entirely. I think it will look good enough if I make it a little glossier. I found

float fresnel = sqrt(1.0 - dot(NORMAL, VIEW));

can be used for a fresnel effect. Is there a way to adapt this to work with normal maps?

11 days later

Additive bloom gives the correct result:

I like additive bloom better anyway, it just needs to be way softer than softlight. Fire shaders can look really nice with additive bloom, too.

I learned two more things about light shaders:

void light() {
    DIFFUSE_LIGHT += max(dot(NORMAL, LIGHT),0.0) * ATTENUATION * ALBEDO * LIGHT_COLOR;
    vec3 H = normalize(VIEW + LIGHT);
    float NdotH = max(0, dot(NORMAL, H));
    float specular = pow(NdotH, specular_power) * specular_strength * ATTENUATION.x;
    SPECULAR_LIGHT += specular*LIGHT_COLOR;
}

First, I multiply both diffuse and specular light by LIGHT_COLOR. Also,

dot(NORMAL, LIGHT)

should be

max(dot(NORMAL, LIGHT),0.0)

otherwise, if a light is behind the surface, it will get darker.

2 years later

Hey @Dschoonmaker ! Thanks for all the updates you made here about what you learned. I was having trouble getting a handle on light shaders and this has helped me greatly.

Write a Reply...