+#include <vector>
+
#include "PhongShader.hxx"
#include "Primitive.hxx"
+#include "Scene.hxx"
PhongShader::PhongShader(Scene* scene,
const Vec3f& am_c,
Vec3f
PhongShader::Shade(Ray& ray)
{
- // surface normal at hit point of object
- Vec3f normal = ray.hit()->GetNormal(ray);
- // turn to front if angle > 90°
- if(normal.dot(ray.direction()) < 0) {
- normal = normal * -1;
- }
- // direction of reflection
- Vec3f refl_dir = ray.direction() - normal * 2 * normal.dot(ray.direction());
- refl_dir.normalize();
-
- // ambient color term
- Vec3f amb_color = m_ambient_color * m_ka;
+ // surface normal at hit point
+ Vec3f N = ray.hit()->GetNormal(ray);
+ // turn normal to front
+ if(N.dot(ray.direction()) > 0)
+ {
+ N *= -1;
+ }
+
+ // reflection vector
+ Vec3f R = ray.direction() - N*2*N.dot(ray.direction());
+ R.normalize();
- Vec3f intensity, light_dir;
+ // ambient term
+ Vec3f color = m_ambient_color * 1.0 * m_ka;
+
+ // construct shadow ray
+ Vec3f shadow_org = ray.origin()+ray.direction()*ray.t();
+ Ray shadow_ray;
+ shadow_ray.setOrigin(shadow_org);
+
- // diffuse and specular color for each light source
- Vec3f diff_sum;
- Vec3f spec_sum;
- for(std::vector<Light*>::iterator it = m_scene->m_lights.begin();
- it != m_scene->m_lights.end(); it++) {
- Ray light_ray;
- (*it)->Illuminate(light_ray, intensity);
- diff_sum += intensity * light_ray.direction().dot(normal);
- Vec3f view_dir = ray.direction()*-1; // direction from hitpoint to viewer
- spec_sum += intensity * pow(fmax(view_dir.dot(refl_dir),0), m_ke);
- }
- Vec3f diff_color = m_diffuse_color * m_kd * diff_sum;
- Vec3f spec_color = m_specular_color * m_ks * spec_sum;
+ int n_area_rays = 1000;
+ std::vector<Light*> lights = m_scene->lights();
+ for(unsigned int i = 0; i < lights.size(); ++i)
+ {
+ Vec3f intensity;
- return amb_color + diff_color + spec_color;
+ int max_s = (lights[i]->IsArea()) ? n_area_rays : 1;
+ Vec3f color_l(0.0f,0.0f,0.0f);
+ for(int s = 0; s < max_s; ++s)
+ {
+
+ if(lights[i]->Illuminate(shadow_ray, intensity))
+ {
+ // check for occluders
+ if(m_scene->Occluded(shadow_ray))
+ {
+ continue;
+ }
+
+ float IdotN = shadow_ray.direction().dot(N);
+ if(IdotN > 0)
+ {
+ // diffuse term
+ color_l += m_diffuse_color * intensity * IdotN * m_kd;
+ }
+
+ // specular term
+ float IdotR = shadow_ray.direction().dot(R);
+ if(IdotR > 0)
+ {
+ color_l += m_specular_color * intensity * pow(IdotR,m_ke) * m_ks;
+ }
+ }
+ }
+ color_l /= static_cast<float>(max_s);
+ color += color_l;
+ }
+ color.clamp();
+
+ return color;
}