Luke
Luke

Reputation: 1

Implementing the Phong reflection model in a compute shader - unexpected response to change of spectral and diffuse coefficients

I am writing my first ray traced shader in Unity as a compute shader. I am following the very nice tutorial located here.

I've implemented the basic specular reflection logic as in the tutorial, where the ray's energy is simply multiplied by a material's specular reflection coefficient:

(in Shade):

float3 specular = float3(0.6f, 0.6f, 0.6f);
ray.origin = hit.position + hit.normal * 0.001f;
ray.direction = reflect(ray.direction, hit.normal);
ray.energy *= specular;
return float3(0.0f, 0.0f, 0.0f);

(in CSMain)

for (int i = 0; i < _maxBounce; i++){
    RayHit hit = Trace(ray);
    result += ray.energy*Shade(ray, hit);

    if (!any(ray.energy)){
        break;
    }
}

This works just fine. However, instead of following the tutorial's instructions to implement diffuse reflections, I'd like to just build in the Phong reflection model as defined in the Wikipedia page.
For simplicity, I'm just going to treat the specular and diffuse components of a light source's intensity as one. In addition, I'm choosing to ignore ambient lighting (for now):

(modified code in Shade)

float3 k_specular = float3(0.5f, 0.5f, 0.5f);
float3 k_diffuse = float3(0.9f, 0.9f, 0.9f);
float alpha = 30;

float3 intensity = float3(0.0f, 0.0f, 0.0f);
for (int i = 0; i < _nLights; i++){
    float3 diffuse = k_diffuse*((dot(-normalize(_Lights[i].xyz), hit.normal))*_Lights[i].w);
    float3 R = normalize(2*dot(-normalize(_Lights[i].xyz), hit.normal)*hit.normal + normalize(_Lights[i].xyz));
    float3 specular = k_specular*(pow(dot(R, -normalize(ray.direction)), alpha)*_Lights[i].w);
    intensity += specular + diffuse;
}

ray.energy *= intensity;

Notes:

  1. I'm using the negative of _Lights[i].xyz because the vector as provided by Unity points towards the surface and I need it to be pointing away in the model.
  2. Same as above for ray.direction in the specular component, for the same reason (the ray is cast from the camera/is pointing towards the surface after being reflected off another surface).

However, I'm having a few issues in getting this to work as expected:

  1. I'm finding that I need to wrap the first argument of the pow in max(argument, 0.0) to prevent a black "cliff" effect as pictured in the screenshot to get around HLSL's seeming inability to computed powers of negative numbers. Am I understanding this behavior correctly? Is this a reasonable approach for handling this? Screenshot with black "cliff" effect
  2. The coefficients don't seem to affect rendering as expected. The alpha parameter works fine; I can control the specular highlight as expected. However, setting the diffuse reflection coefficient very high (0.9f for all color channels) and the specular reflection coefficient very low (0.2f for all color channels) still produces a result which I would consider highly "shiny": Unexpectedly shiny result

I have checked and rechecked my code, adjusted signs here and there, etc. and am at a bit of a loss as to what might be going wrong. Can anyone provide insight? Much appreciated!

Upvotes: 0

Views: 89

Answers (0)

Related Questions