#ifndef MOUNTPHONGSHADER_HXX #define MOUNTPHONGSHADER_HXX #include "Shader.hxx" #include "Noise.hxx" /* This class determines the dye of the mountains. ** The base is colored with a mix of two colors and ** the peak is covered with snow. */ class MountPhongShader : public Shader { private: // base colors Vec3f first_color; // 1. base color Vec3f second_color; // 2. base color // Phong parameters float ka; // ambient coefficient float kd; // diffuse reflection coefficients float ks; // specular refelection coefficients float ke; // shininess exponent //snow lines float low_level; // lower level float high_level; // higher level public: MountPhongShader(Scene *scene, Vec3f first, Vec3f second, float ka,float kd, float ks, float ke, float low, float high) : Shader(scene),first_color(first),second_color(second),ka(ka),kd(kd),ks(ks),ke(ke),low_level(low),high_level(high) {}; virtual Vec3f Shade(Ray &ray) { /* determine color */ Vec3f color; Vec3f point = ray.org + ray.t * ray.dir; float height = point.y() + (PerlinNoise3D_new(point.x(), point.y(), point.z()) / 4.0f); float noise = fabs(PerlinNoise3D_new(point.x(), point.y(), point.z())); //peak is white and rest is random mix between two base colors if(height >= high_level) color = Vec3f(0.9f); else color = noise * first_color + (1.0f-noise) * second_color; /* Phong shading */ // get shading normal Vec3f normal = ray.hit->GetNormal(ray); // turn normal to front if (Dot(normal,ray.dir) > 0) normal = -normal; // calculate reflection vector Vec3f reflect = ray.dir - 2*Dot(normal,ray.dir)*normal; // ambient term Vec3f ambientIntensity(1,1,1); Vec3f ambientColor = ka * color; Vec3f result = Product(ambientColor, ambientIntensity); // shadow ray (up to now only for the light direction) Ray shadow; shadow.org = ray.org + ray.t * ray.dir; // iterate over all light sources for (unsigned int l=0; l < scene->mLights.size(); l++) { // get direction to light, and intensity Vec3f lightIntensity; Vec3f result_local = Vec3f(0.0); // check whenever the shader is computing area light source for(unsigned int s = 0; s < scene->mLights[l]->GetNumberOfRays(); s++) { // illuminate the ray by the light source if (scene->mLights[l]->Illuminate(shadow, lightIntensity, s)) { // compute distance to the light source float distance = shadow.t; // diffuse term, also used as a check if illuminating the front-side float cosLightNormal = Dot(shadow.dir,normal); if (cosLightNormal > 0) { // if the ray is occluded, hence there is a shadow // we put this here to optimize all things, since we work only for in-front surfaces if (scene->castShadows && scene->Intersect(shadow) && shadow.hit->castShadows()) { // if the shadow ray intersects a surface which is near then the light source, then we // are in shadow if (shadow.t < distance) continue; } // compute diffuse term Vec3f diffuseColor = kd * color; result_local = result_local + Product(diffuseColor * cosLightNormal, lightIntensity); // specular term is computed only if shading the front-side float cosLightReflect = Dot(shadow.dir,reflect); if (cosLightReflect > 0) { Vec3f specularColor = ks * Vec3f(1,1,1); // white highlight; result_local = result_local + Product(specularColor * powf(cosLightReflect,ke), lightIntensity); } } } } result += result_local / float(scene->mLights[l]->GetNumberOfRays()); } return result; }; }; #endif