/**
 * Phong Shading
 */
void PointLight::shade( Ray3D& ray ) {
	Intersection intPoint = ray.intersection;

	// construct vectors
	Vector3D n = intPoint.normal;
	Vector3D de = -ray.dir;
	Vector3D s = get_position() - intPoint.point; // light source
	Vector3D m = ((2 * n.dot(s)) * n) - s; // perfect mirror directions

	// normalize
	n.normalize();
	s.normalize();
	m.normalize();
	de.normalize();

	// do the diffuse shading
	do_diffuse(s, n, ray);

	// do the specular shading
	Colour specular(0, 0, 0);

	double mdde = m.dot(de);
	if ( mdde >= 0 ) {
		specular =
			pow(mdde, intPoint.mat->specular_exp)
			* intPoint.mat->specular * _col_specular;
	}

	if ( ray.shadowed ) {
		ray.col = ray.col + (_shadow_opacity * specular);
	} else {
		ray.col = ray.col + specular;
	}
}
/**
 * Diffuse Shading
 */
void PointLight::shade_diffuse( Ray3D& ray ) {
	Intersection intPoint = ray.intersection;

	// construct vectors
	Vector3D n = intPoint.normal;
	Vector3D s = get_position() - intPoint.point;

	// normalize
	n.normalize();
	s.normalize();

	do_diffuse(s, n, ray);
}
Example #3
0
RGBColor Lambertian::sample_f(const ShadeRec& sr, const Vector3D& wo, Vector3D& wi, float& pdf) const
{
  Vector3D w = sr.normal;
  Vector3D v = Vector3D(0.0034, 1, 0.0071) ^ w;
  v.normalize();
  Vector3D u = v ^ w;

  Point3D sp = sampler_ptr->sampleHemisphere();
  wi = sp.x * u + sp.y * v + sp.z * w;
  wi.normalize();

  pdf = sr.normal * wi * invPI;

  return (kd * cd * invPI);
}
Example #4
0
AffineTrans3D initInvViewMatrix( Point3D const& eye, Vector3D view, Vector3D up) {
    AffineTrans3D mat; 
    Vector3D w;
    view.normalize();
    up = up - up.dot(view)*view;
    up.normalize();
    w = view.cross(up);

    mat.A.col(0) = w.v;
    mat.A.col(1) = up.v;
    mat.A.col(2) = -view.v;

    mat.t = eye.v;

    return mat; 
}
Example #5
0
void make_coord_space(Matrix3x3& o2w, const Vector3D& n) {

    Vector3D z = Vector3D(n.x, n.y, n.z);
    Vector3D h = z;
    if (fabs(h.x) <= fabs(h.y) && fabs(h.x) <= fabs(h.z)) h.x = 1.0;
    else if (fabs(h.y) <= fabs(h.x) && fabs(h.y) <= fabs(h.z)) h.y = 1.0;
    else h.z = 1.0;

    z.normalize();
    Vector3D y = cross(h, z);
    y.normalize();
    Vector3D x = cross(z, y);
    x.normalize();

    o2w[0] = x;
    o2w[1] = y;
    o2w[2] = z;
}
Example #6
0
//obtains the orientation matrix based on the unitary vector x, 
//the vector vv corrspondent to y. z is cw defined, and vv corrected
OrientationMatrix::OrientationMatrix(Vector3D vu, Vector3D vv)
{
	vu.normalize();
	Vector3D vw=vu.cross(vv);
	vw.normalize();
	vv=vw.cross(vu);
	mat[0][0]=vu[0];mat[1][0]=vu[1];mat[2][0]=vu[2];
	mat[0][1]=vv[0];mat[1][1]=vv[1];mat[2][1]=vv[2];
	mat[0][2]=vw[0];mat[1][2]=vw[1];mat[2][2]=vw[2];
}
void Matrix3DUtils::setOrientation(Matrix3D &m, const Vector3D &dir, const Vector3D &up, const float smooth) {
    getScale(m, _scale);
    
    Vector3D upp;
    Vector3D dirr;
    
    upp.copyFrom(up);
    dirr.copyFrom(dir);
    
    if (smooth != 1) {
        getDir(m, _dir);
        _dir.x += (dir.x - _dir.x) * smooth;
        _dir.y += (dir.y - _dir.y) * smooth;
        _dir.z += (dir.z - _dir.z) * smooth;
        dirr = _dir;
        
        getUp(m, _up);
        _up.x += (up.x - _up.x) * smooth;
        _up.y += (up.y - _up.y) * smooth;
        _up.z += (up.z - _up.z) * smooth;
        upp = _up;
    } else {
        dirr = dir;
    }
    dirr.normalize();
    
    Vector3D rVec;
    Vector3D::crossProduct(upp, dirr, &rVec);
    rVec.normalize();
    
    Vector3D uVec;
    Vector3D::crossProduct(dirr, rVec, &uVec);
    
    rVec.scaleBy(_scale.x);
    uVec.scaleBy(_scale.y);
    dirr.scaleBy(_scale.z);
    
    rVec.w = 0.0f;
    uVec.w = 0.0f;
    dirr.w = 0.0f;
    
    setVectors(m,rVec, uVec, dirr);
}
Example #8
0
void PointLight::shade( Ray3D& ray, Ray3D::intersection_func intersectCheck ) const {

    Material* mat = ray.intersection.mat;
    
    // compute direction towards light
    Vector3D lightDir = pos_ - ray.intersection.point;
    double distance = lightDir.normalize();
    ray.col += col_ambient_ * mat->ambient.at(ray.intersection.uv);

    // cos of angle from normal to lightDir
    double cosAngle = lightDir.dot(ray.intersection.normal);

    if (cosAngle < 0) {
        return;
    }
    // shadow check
    else {
        Ray3D lightRay(ray.intersection.point, lightDir);
        intersectCheck(lightRay);

        // if we intersect an object between the light and point
        // we are considering, then it is in shadow
        if (!lightRay.intersection.none && lightRay.intersection.t_value < distance ) {
            return;
        }
    }

    // diffuse
    ray.col += col_diffuse_ * mat->diffuse.at(ray.intersection.uv) * cosAngle;

    // direction of reflection of light ray
    Vector3D reflectDir = 2*cosAngle*ray.intersection.normal - lightDir;
    reflectDir.normalize();
    // cos of angle from reflection to ray back to viewer
    double rv = -reflectDir.dot(ray.dir);

    // specular
    if (rv > 0) {
        ray.col += col_specular_ * mat->specular.at(ray.intersection.uv)
                                 * pow(rv, mat->specular_exp);
    }
}
Example #9
0
Color Refractive::shade(ShadeRec& sr) {
	Color col = Phong::shade(sr);

	// get the texture
	if (refraction_ptr) {
		eta = 2.0f * refraction_ptr->get_color(sr).r;
	}

	Vector3D v = -sr.ray.d.normalized();
	Vector3D n = sr.nh;

	float cosTheta1 = sr.nh * v;
	float theeta = eta;
	if(cosTheta1 < 0)
	{
		n = -n;
		cosTheta1 = -cosTheta1;
		theeta = 1.0f / theeta;
	}

	float a = -1.0f / theeta;
	float term = ((cosTheta1 * cosTheta1 -1) / (theeta * theeta)) + 1;
	
	Vector3D transmitDir;
	if (term > 0.0) {
		float b = (cosTheta1 / theeta) - sqrt(term);
		transmitDir = a * v + b * n;
		transmitDir.normalize();
	}
	else {
		transmitDir = -v + 2.0f * cosTheta1 * n;
		transmitDir.normalize();
	}

	Ray transmittedRay = Ray(sr.ph+0.01f*transmitDir, transmitDir);

	col += sr.world.trace_ray(transmittedRay, sr.depth + 1);

	return col;
}
Example #10
0
	void Transformable::setTransformOrientationLH(Vector3D look,Vector3D up)
	{
		look.normalize();

		Vector3D side = crossProduct(look,up);
		side.normalize();

		up = crossProduct(side,look);

		local[0] = side.x;
		local[1] = side.y;
		local[2] = side.z;
		local[4] = up.x;
		local[5] = up.y;
		local[6] = up.z;
		local[8] = look.x;
		local[9] = look.y;
		local[10] = look.z;

		localIdentity = false;
		notifyForUpdate();
	}
bool UnitSphere::intersect( Ray3D& ray, const Matrix4x4& worldToModel,
		const Matrix4x4& modelToWorld ) {
	// TODO: implement intersection code for UnitSphere, which is centred 
	// on the origin.  
	//
	// Your goal here is to fill ray.intersection with correct values
	// should an intersection occur.  This includes intersection.point, 
	// intersection.normal, intersection.none, intersection.t_value.   
	//
	// HINT: Remember to first transform the ray into object space  
	// to simplify the intersection test.
	
	Ray3D r;
	r.origin = worldToModel * ray.origin;
	r.dir = worldToModel * ray.dir;

	Point3D sphere(0,0,0);
	Vector3D s_dist = r.origin - sphere;
	double int0 = -1, int1;

	double a = r.dir.dot(r.dir);
	double b = s_dist.dot(r.dir);
	double c = s_dist.dot(s_dist) - 1;
	double d = b * b - a * c;

	if (d == 0) int0 = -b/a;
	else if (d > 0) {
		int0 = (-b + sqrt(d)) / a;
		int1 = (-b - sqrt(d)) / a;
		int0 = int0 < int1 ? int0 : int1;
	}


	if (int0 <= 0) return false;

	if (ray.intersection.none || int0 < ray.intersection.t_value) {

		Point3D ip = r.origin + int0 * r.dir;
		Vector3D n = 2 * (ip - sphere);
		n.normalize();

		ray.intersection.t_value = int0;
		ray.intersection.point = modelToWorld * ip;
		ray.intersection.normal = transNorm(worldToModel, n);
		ray.intersection.normal.normalize();
		ray.intersection.none = false;
		return true;
	}

	return false;
}
Example #12
0
void Renderer3DRasterization::render()
{
	setMaxDepth(1.0);

	TransformMatrix3D lookat = camera_->getLookatMatrix();
	TransformMatrix3D proj = camera_->getProjectionMatrix();
	TransformMatrix3D screen = camera_->getScreenMatrix();

	TransformMatrix3D transform = screen * proj * lookat;

	std::vector<Surface3D*> list = scene_->getTriangleList();

	std::cout << "Renderer3DRasterization: Found " << list.size() << " triangles" << std::endl;

	for (Surface3D* triangle : list)
	{
		Color color = triangle->getColor();

		// color shading according to Lambert
		// normally we need a light source, but we use camera this time

		Vector3D normal = triangle->getNormal();
		Vector3D center = triangle->getCenter();

		// get direction to camera

		Vector3D d = camera_->getCenter() - center;
		d.normalize();

		double lambert = Mathtools::dot(d, normal);

		color = color * (lambert < 0.0 ? 0.0 : lambert);

		Vector3D p0 = transform * *(triangle->getP0());
		Vector3D p1 = transform * *(triangle->getP1());
		Vector3D p2 = transform * *(triangle->getP2());

		// in case we used perspective projection: divide by homogeneous coordinate "w"
		p0.homogeneousDivide();
		p1.homogeneousDivide();
		p2.homogeneousDivide();

		
		Surface3D transformedTriangle(p0, p1, p2, &color, triangle->getTexture());
		transformedTriangle.setTextureAnchorPoints(triangle->getT0(), triangle->getT1(), triangle->getT2());

		rasterization(&transformedTriangle);
	}

}
Example #13
0
void Camera::compute_position() {
  double sinPhi = sin(phi);
  if (sinPhi == 0) {
    phi += EPS_F;
    sinPhi = sin(phi);
  }
  const Vector3D dirToCamera(r * sinPhi * sin(theta),
                             r * cos(phi),
                             r * sinPhi * cos(theta));
  pos = targetPos + dirToCamera;
  Vector3D upVec(0, sinPhi > 0 ? 1 : -1, 0);
  Vector3D screenXDir = cross(upVec, dirToCamera);
  screenXDir.normalize();
  Vector3D screenYDir = cross(dirToCamera, screenXDir);
  screenYDir.normalize();

  c2w[0] = screenXDir;
  c2w[1] = screenYDir;
  c2w[2] = dirToCamera.unit();   // camera's view direction is the
                                 // opposite of of dirToCamera, so
                                 // directly using dirToCamera as
                                 // column 2 of the matrix takes [0 0 -1]
                                 // to the world space view direction
}
Example #14
0
bool UnitSphere::intersect( Ray3D& ray, const Matrix4x4& worldToModel,
		const Matrix4x4& modelToWorld ) {
	// TODO: implement intersection code for UnitSphere, which is centred 
	// on the origin.  
	//
	// Your goal here is to fill ray.intersection with correct values
	// should an intersection occur.  This includes intersection.point, 
	// intersection.normal, intersection.none, intersection.t_value.   
	//
	// HINT: Remember to first transform the ray into object space  
	// to simplify the intersection test.
    
    Vector3D d = worldToModel*ray.dir;
    // d.normalize();
    Point3D e = worldToModel*ray.origin;
    Point3D c;
    float A = d.dot(d);
    float B = d.dot(e-c);
    float C = (e-c).dot(e-c)-1.0;
    if ((B*B - A*C) < 0)
    {
        ray.intersection.none = true;
        return false;
    }
    else
    {
        float t1 = (-B - sqrt(B*B - A*C)) / A;
        float t2 = (-B + sqrt(B*B - A*C)) / A;
        float t = fmin(t1, t2);
        if (t > 0)
        {
            if (!ray.intersection.none && ray.intersection.t_value < t)
            {
                return false;
            }
            Vector3D n = e + t*d - c;
            n.normalize();
            ray.intersection.point = modelToWorld * (e + t*d);
            ray.intersection.normal = transNorm(worldToModel, n);
            ray.intersection.none = false;
            ray.intersection.t_value = t;
            return true;
        }
        else
            return false;
    }
}
Example #15
0
Color PointLight::L(const ShadeRec& sr) {
	float d = (sr.ph - location).mag();
	
	if (casts_shadows()) {
		Vector3D r = (location - sr.ph);
		r.normalize();
		Ray shRay = Ray(sr.ph+0.01f*r, r);
		float t;
		float Li = 0.0;
		for (unsigned int i = 0; i < sr.world.get_num_objects(); i++) {
			if (sr.world.get_object(i)->shadow_hit(shRay, t, Li) && t < d) {
				float csh = 1 - (Li/d);
				if (csh < 0) csh = 0.0;
				return (ls * color) * csh / (2.5f * d);
			}
		}
	}
	return (ls * color) / (1.5f * d);
}
Example #16
0
void Physics::calcSlopeDirection(Ball *b, Tile *tile) {
	Vector3D xaxis = worldUp.cross(tile->normal);
	Vector3D slope = tile->normal.cross(xaxis);

	slope.normalize();

	//cout << slope.y << ":"; // DEBUG SLOPE

	if (slope.y != 0.0) {
		if (tile->normal.dot(b->dir) > 0.0) { // rolling down
			b->dir.y = slope.y * -1;
		} else if (tile->normal.dot(b->dir) < 0.0) { // rolling up
			b->dir.y = slope.y;
		} else {
		}
	} else {
		b->dir.y = 0.0; 
	}
}
Example #17
0
Colour PhongMaterial::calculateLighting(const Vector3D& incident, const Vector3D& normal, const Vector3D& reflected, const Vector3D& viewer, const Colour& intensity) const {
  double incidentDotNormal = std::max(0.0, incident.dot(normal));

  Colour diffuse = m_kd * incidentDotNormal * intensity;

#ifdef BLINN_PHONG
  // Blinn-Phong.
  Vector3D h = viewer + incident;
  h.normalize();
  Colour specular = m_ks * pow(std::max(0.0, h.dot(normal)), m_shininess) * intensity;
#else
  // Phong.
  Colour specular = m_ks * pow(reflected.dot(viewer), m_shininess) * intensity;
#endif

  //std::cout << "incident " << incident << ", normal " << normal << ", viewer " << viewer << ", intensity " << intensity << ", result=" << diffuse+specular << std::endl;

  return diffuse + specular;
}
Example #18
0
void Quaternion::GetAxisAngle(Vector3D &v, float &angle) const
{
	double	temp_angle;		// temp angle
	double	scale;			// temp vars

	temp_angle = acos(w);

	//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	// Another version where scale is sqrt (x2 + y2 + z2)
	//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	scale = (float)sqrt(SQR(x) + SQR(y) + SQR(z));
//	scale = (float)sin(temp_angle);

	assert(0 <= temp_angle);		// make sure angle is 0 - PI
	assert(PI >= temp_angle);

	if (FLOAT_EQ(0.0f, scale))		// angle is 0 or 360 so just simply set axis to 0,0,1 with angle 0
	{
		angle = 0.0f;

		//v.SetValues(0.0f, 0.0f, 1.0f);		// any axis will do
		v.x = 0.0f;
		v.y = 0.0f;
		v.z = 0.0f;
	}
	else
	{
		angle = (float)(temp_angle * 2.0);		// angle in radians

		//v.SetValues(float(x / scale), float(y / scale), float(z / scale));
		v.x = float(x / scale);
		v.y = float(y / scale);
		v.z = float(z / scale);
		v.normalize();

		assert(0.0f <= angle);			// make sure rotation around axis is 0 - 360
		assert(2*PI >= angle);
		assert(v.IsUnit());				// make sure a unit axis comes up
	}

	return;
}	// end void GetAxisAngle(..)
void PointLight::shade( Ray3D& ray ) {
	// TODO: implement this function to fill in values for ray.col 
	// using phong shading.  Make sure your vectors are normalized, and
	// clamp colour values to 1.0.
	//
	// It is assumed at this point that the intersection information in ray 
	// is available.  So be sure that traverseScene() is called on the ray 
	// before this function.

    //get the intersection  
    Intersection intersection = ray.intersection;
    //get the normal
    Vector3D normal = intersection.normal;
    normal.normalize();
    //get the ray direction
    Vector3D ray_dir = ray.dir;
    ray_dir.normalize();
    //get the light direction
    Vector3D light_dir = _pos - intersection.point;
    light_dir.normalize();
    //calculate the reflection diretion
    Vector3D reflect_dir = light_dir - 2.0 * (light_dir.dot(normal)) * normal;
    reflect_dir.normalize();
    //get Material data
    Material* mat = intersection.mat;
    //calculate ambient 
    Colour ambient_component = (mat->ambient) * _col_ambient;
    //calculate diffusion
    Colour diffuse_component = fmax(0 , light_dir.dot(normal)) * (mat->diffuse) * _col_diffuse;
    //calculate speculation
    Colour specular_component = pow(fmax(0 , ray_dir.dot(reflect_dir)),
            mat->specular_exp) * _col_specular * mat->specular;
    ambient_component.clamp();
    diffuse_component.clamp();
    specular_component.clamp();
    //add all component together
    Colour ray_col = ambient_component + diffuse_component + specular_component;
    ray_col.clamp();
    ray.col = ray.col + ray_col;    

}
Example #20
0
	void Transformable::setTransformOrientation(Vector3D axis,float angle)
	{
		axis.normalize();
		float c = std::cos(angle);
		float s = std::sin(angle);
		float a = 1 - c;
		Vector3D axis2(axis.x * axis.x,axis.y * axis.y,axis.z * axis.z);

		local[0] = axis2.x + (1 - axis2.x) * c;
		local[1] = axis.x * axis.y * a + axis.z * s;
		local[2] = axis.x * axis.z * a - axis.y * s;
		local[4] = axis.x * axis.y * a - axis.z * s;
		local[5] = axis2.y + (1 - axis2.y) * c;
		local[6] = axis.y * axis.z * a + axis.x * s;
		local[8] = axis.x * axis.z * a + axis.y * s;
		local[9] = axis.y * axis.z * a - axis.x * s;
		local[10] = axis2.z + (1 - axis2.z) * c;

		localIdentity = false;
		notifyForUpdate();
	}
Example #21
0
void shade(const Scene * scene, const int level, const C_FLT weight,
           const Ray &ray, Intercept * intercepts, Color * color) {
  Material * entryMat = intercepts[0].material,
           * hitMat = intercepts[0].enter?
                      intercepts[0].primitive->material: ray.medium;

  C_FLT specWeight = hitMat->specular.magnitude() * weight,
        transWeight = hitMat->transmission.magnitude() * weight;

  Vector3D specDir, transDir, normal;
  std::vector<P_FLT> mapping;

  Point3D interceptPoint = ray.rayPoint(intercepts[0].t);

  intercepts[0].primitive->getIntersect(interceptPoint, &normal, &mapping);
  if (dotProduct(ray.dir, normal) > 0.0f) {
    normal.negate();
  }
  specularDirection(ray.dir, normal, &specDir);
  bool transmission = transmissionDirection(entryMat, hitMat, ray.dir, normal,
                                            &transDir);

  *color += scene->ambience * hitMat->ambience;

  for (std::vector<Light *>::const_iterator itr = scene->lights.begin();
       itr != scene->lights.end(); itr++) {
    Vector3D pointToLight = (*itr)->orig - interceptPoint;
    P_FLT distanceToLight = pointToLight.normalize();
    Ray rayToLight(interceptPoint, pointToLight, NULL);

    P_FLT lightDotNormal = dotProduct(pointToLight, normal);
    if (fGreaterZero(lightDotNormal) &&
        fGreaterZero(shadow(scene, rayToLight, distanceToLight))) {
      // Light source diffuse reflection
      *color += (*itr)->color * hitMat->diffuse * lightDotNormal;

      // Light source specular reflection
      Vector3D h = pointToLight - ray.dir;
      h.normalize();
      P_FLT specDot = dotProduct(normal, h);
      if (specDot > 0.0f) {
        *color += (*itr)->color * hitMat->specular *
                  pow(specDot, hitMat->shine);
      }
    } else if (transmission && fLessZero(lightDotNormal) &&
               fLessZero(shadow(scene, rayToLight, distanceToLight))) {
      // Light source specular transmission
      C_FLT refrRatio = hitMat->refraction / entryMat->refraction;
      if (!fEqual(refrRatio, 1.0f)) {
        Vector3D h_j = (-ray.dir - pointToLight * refrRatio) /
                       (refrRatio - 1);
        h_j.normalize();

        // TODO(kent): Define transmission highlight coefficient
        *color += (*itr)->color * hitMat->transmission *
                  pow(dotProduct(-normal, h_j), hitMat->shine);
      }
    }
  }

  if (level < MAX_LEVEL) {
    // Other body specular reflection
    if (specWeight > MIN_WEIGHT) {
      Ray specRay(interceptPoint, specDir, entryMat);
      Color specColor;

      trace(scene, level + 1, specWeight, specRay, &specColor);
      *color += specColor * hitMat->specular;
    }

    // Other body specular transmission
    if (transWeight > MIN_WEIGHT) {
      if (transmission) {
        Ray transRay(interceptPoint, transDir, hitMat);
        Color transColor;

        trace(scene, level + 1, transWeight, transRay, &transColor);
        *color += transColor * hitMat->transmission;
      } else {
        // TODO(kent): Handle total internal reflection
      }
    }
  }

  if (intercepts[0].enter && intercepts[0].primitive->texture != NULL) {
    *color *= intercepts[0].primitive->getTexColor(mapping);
  }
}
Example #22
0
void a4_render(// What to render
               SceneNode* root,
               // Where to output the image
               const std::string& filename,
               // Image size
               int width, int height,
               // Viewing parameters
               const Point3D& eye, const Vector3D& view,
               const Vector3D& up, double fov,
               // Lighting parameters
               const Colour& ambient,
               const std::list<Light*>& lights
               )
{
    // Fill in raytracing code here.
    Image img(width, height, 3);
    Matrix4x4 inv_transf;
    //pinhole camera
    Vector3D m_cx = (view.cross(up));
    m_cx.normalize();
    Vector3D m_cy = (-up);

    double m_fovrad = (fov*M_PI)/360.0;
    double m_cw = tan(m_fovrad);
    double a =(double(width)/double(height));
    double m_ch = m_cw;

    //for percent display
    float done = 0;
#pragma omp parallel for default(shared) reduction(+:done) schedule(guided)
    for (int y = 0; y < height; y++) {
        done = done + 1.0f;
        display_percentage( done, (float)height);
        for (int x = 0; x < width; x++) {
            //background color
            // Red: increasing from top to bottom
            double red = (double)y / height;
            // Green: increasing from top and bottom to middle
            double green = ((red <= 0.5) ? 2.0*red : (2.0 - 2.0*red));
            // Blue: decreasing from top to bottom
            double blue = 1.0 - red;
            Colour back(red,green,blue);
            //antialiasing  http://www.codermind.com/articles/Raytracer-in-C++-Part-II-Specularity-post-processing.html
            double sampleRatio= 0.25;
            Colour aux(0.0, 0.0, 0.0);
            for (double fragmentx = double(x) ; fragmentx < x + 1.0; fragmentx += 0.5 )
                for (double fragmenty = double(y) ; fragmenty < y + 1.0; fragmenty += 0.5 )
                {
                    Vector3D m_raydir;
                    //get primary ray direction
                    m_raydir = view + (fragmentx / (double(width))*2.0 -1.0 )*m_cw*a*m_cx + ((fragmenty) / (double(height))*2.0 - 1.0) * m_ch*m_cy;
                    m_raydir.normalize();
                    //m_raydir = Vector3D(0.0,0.0,-1.0);
                    Ray r(eye,m_raydir);
                    //Ray r(Point3D(x,y,800),m_raydir);
                    double coef = 1.0;
                    int level = 0;
                    bool hit = false;
                    Colour tmp(0.0, 0.0, 0.0);
                    do{
                        // find the closest intersection
                        Intersection closest_isect;
                        hit = root->closest_intersect(r,closest_isect,inv_transf);
                        //if(!hit) cout<< "fail hit"<< endl;
                        if(hit){
                            //cout<< "success hit"<< endl;
                            // put color to pixel
                            Colour diffuse(0.0, 0.0, 0.0);
                            Colour specular(0.0, 0.0, 0.0);
                            Ray reflected_ray;//reflected ray
                            reflected_ray.origin()= closest_isect.position();

                            for (std::list<Light*>::const_iterator cl = lights.begin(); cl != lights.end(); ++cl){

                                Vector3D L = (*cl)->position - closest_isect.position();
                                double light_dist = L.length();
                                if((L.dot(closest_isect.normal())) <= 0.0 || light_dist < 0.0)// test if the point if lighted
                                    continue;
                                L.normalize();
                                reflected_ray.direction()=L;

                                // attenuation factor
                                double fatt = 1.0/((*cl)->falloff[0]+ (*cl)->falloff[1]*light_dist
                                                   + (*cl)->falloff[2]*light_dist*light_dist);
                                coef = fatt;
                                if(coef < double(1e-6)) break;

                                // test if point is in shadow
                                bool in_shadow = false;
                                Intersection aux_isect;
                                if(root->closest_intersect(reflected_ray,aux_isect,inv_transf,light_dist))
                                    in_shadow = true;

                                //ilumination
                                if(!in_shadow){
                                    double lambert = reflected_ray.direction().dot(closest_isect.normal())*fatt;
                                    diffuse = diffuse + (lambert*(*cl)->colour)*closest_isect.mtrl()->get_diffuse();
                                    // reflection by blinn-phong model reference:http://www.codermind.com/
                                    Vector3D blinnDir = reflected_ray.direction() - r.direction();
                                    double temp = blinnDir.length2();
                                    if (temp != 0.0 )
                                    {
                                        blinnDir.normalize();
                                        double blinnTerm = max(blinnDir.dot(closest_isect.normal()), 0.0);
                                        blinnTerm = pow(blinnTerm ,closest_isect.mtrl()->get_shininess())*fatt;

                                        specular =specular + blinnTerm*closest_isect.mtrl()->get_specular()*(*cl)->colour;
                                    }
                                }
                            }
                            tmp = tmp + ambient*closest_isect.mtrl()->get_diffuse() + diffuse + specular;
                            if(closest_isect.mtrl()->get_shininess() < eps)
                                break;
                            double reflet = 2.0*(r.direction().dot(closest_isect.normal()));
                            r.origin() = closest_isect.position() + eps*closest_isect.normal();
                            r.direction() = (r.direction() - reflet * closest_isect.normal());
                            r.direction().normalize();
                            level++;
                        }
                    }while((coef > double(1e-6)) && level < 5 && hit);

                    aux =aux + sampleRatio*tmp;
                }
            if(aux.R()!=0.0 || aux.G()!= 0.0 || aux.B()!= 0.0)
                back = aux;

            img(x, y, 0) = back.R();
            img(x, y, 1) =back.G();
            img(x, y, 2) = back.B();
        }
    }

    std::cerr << "Stub: a4_render(" << root << ",\n     "
              << filename << ", " << width << ", " << height << ",\n     "
              << eye << ", " << view << ", " << up << ", " << fov << ",\n     "
              << ambient << ",\n     {";

    for (std::list<Light*>::const_iterator I = lights.begin(); I != lights.end(); ++I) {
        if (I != lights.begin()) std::cerr << ", ";
        std::cerr << **I;
    }
    std::cerr << "});" << std::endl;
    img.savePng(filename);
}
// Assume disk is flat on the x,y plane with radius 1 
bool UnitDisk::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) 
{
	// Get the ray in the object coordinates
	Ray3D ObjectRay = Ray3D(worldToModel * ray.origin, worldToModel * ray.dir);
	// A reference to the origin point in object/model coordinates
	Point3D centerofDisk(0,0,0); // Center of cylinder 
	// T Values 
	// One to check for intersection with disks, one to check for intersection with sides 
	double t_value; double t_valueTwo; 
	double tempOne, tempTwo;
	double radius = 1.0; // the radius of the disk of the cylinder

	Vector3D normal; // The normal of the cylinder Disk as well as wall of cylinder
			// Gets reused
	Point3D intersectionPoint; // intersection point with the cylinder 

//---------------------------------------------------------------------------------
// Checking Intersection with Cylinder Disks 
//---------------------------------------------------------------------------------

	// Note: Will only intersect the disks of the cylinder
	// if the direction value for z is not 0
	// Getting the tValue for the closer base
	if (ObjectRay.dir[2] != 0)
	{
		// To know if intersect from top or bottom of disk, and set normal accordingly 
		tempOne = (-0.0000001-ObjectRay.origin[2])/ObjectRay.dir[2];
		// Tvalue  
		tempTwo = (0.00000001-ObjectRay.origin[2])/ObjectRay.dir[2];
		
		// Update the normal depending on which disk is closer 
		if (tempOne < tempTwo)
		{
			t_value = tempOne;
			// Construct the normal for the closer disk, which points on the negative z axis
			Point3D normal_temp(0,0,-1);
			normal = normal_temp - centerofDisk;
			normal.normalize();

		}
		else
		{
			t_value = tempTwo;
			Point3D normal_temp(0,0,1);
			normal = normal_temp - centerofDisk;
			normal.normalize();
		}
	}



//---------------------------------------------------------------------------------
//  Calculate the intersection point for the disk  
//---------------------------------------------------------------------------------
	intersectionPoint = ObjectRay.origin + t_value * ObjectRay.dir;
	
	// Prevent self intersection
	if (t_value < 0.001)
	{
		return false;
	}

	// Base or top of cylinder 
	// need make sure within the radius of the disk 
	if (intersectionPoint[0]*intersectionPoint[0] + intersectionPoint[1] * intersectionPoint[1] <= (radius*radius))
	{
		// If it intersection before and it's tvalue is lower then this, 
		// means there is no intersection, return false. 
		if (!ray.intersection.none && (t_value > ray.intersection.t_value))
		{
			return false;
		}
		// Else, there is intersection, update and return true 
		ray.intersection.point = intersectionPoint;
		
		ray.intersection.normal = normal;
		ray.intersection.t_value = t_value;
		ray.intersection.none = false;
		// Every model thinks it is in the center
		ray.intersection.CenterPoint = modelToWorld * Point3D(0,0,0); 
		return true;
	}
	return false; // no intersection with disk 
}
// Basically, this is an intersection with 3 different connected surfaces 
// The top disk, the bottom disk and the cylinder body. 
// Test the intersection of all 3 bodies and figure out which has the lowest t value
bool UnitCylinder::intersect( Ray3D& ray, const Matrix4x4& worldToModel, const Matrix4x4& modelToWorld ) 
{
	// Get the ray in the object coordinates
	Ray3D ObjectRay = Ray3D(worldToModel * ray.origin, worldToModel * ray.dir);
	// A reference to the origin point in object/model coordinates
	Point3D centerOfCylinder(0,0,0); // Center of cylinder 
	// T Values 
	// One to check for intersection with disks, one to check for intersection with sides 
	double t_value; double t_valueTwo; 
	double tempOne, tempTwo;
	double radius = 1.0; // the radius of the disk of the cylinder

	Vector3D normal; // The normal of the cylinder Disk as well as wall of cylinder
			// Gets reused
	Point3D intersectionPoint; // intersection point with the cylinder 

//---------------------------------------------------------------------------------
// Checking Intersection with Cylinder Disks 
//---------------------------------------------------------------------------------

	// Note: Will only intersect the disks of the cylinder
	// if the direction value for z is not 0
	// Getting the tValue for the closer base
	if (ObjectRay.dir[2] != 0)
	{
		// Tvalue to intersect bottom disk of cylinder (negative z axis)
		tempOne = (-0.5-ObjectRay.origin[2])/ObjectRay.dir[2];
		// Tvalue to intersect top disk of cylinder (positive z axis)
		tempTwo = (0.5-ObjectRay.origin[2])/ObjectRay.dir[2];
		
		// Update the normal depending on which disk is closer 
		if (tempOne < tempTwo)
		{
			t_value = tempOne;
			// Construct the normal for the closer disk, which points on the negative z axis
			Point3D normal_temp(0,0,-1);
			normal = normal_temp - centerOfCylinder;
			normal.normalize();

		}
		else
		{
			t_value = tempTwo;
			Point3D normal_temp(0,0,1);
			normal = normal_temp - centerOfCylinder;
			normal.normalize();
		}
	}



//---------------------------------------------------------------------------------
//  Calculate the intersection point for the disk  
//---------------------------------------------------------------------------------
	intersectionPoint = ObjectRay.origin + t_value * ObjectRay.dir;
	
	// Prevent self intersection
	if (t_value < 0.001)
	{
		return false;
	}

	// Base or top of cylinder 
	// need make sure within the radius of the disk 
	if (intersectionPoint[0]*intersectionPoint[0] + intersectionPoint[1] * intersectionPoint[1] <= (radius*radius))
	{
		// If it intersection before and it's tvalue is lower then this, 
		// means there is no intersection, return false. 
		if (!ray.intersection.none && (t_value > ray.intersection.t_value))
		{
			return false;
		}
		// Else, there is intersection, update and return true 
		ray.intersection.point = intersectionPoint;
		
		ray.intersection.normal = normal;
		ray.intersection.t_value = t_value;
		ray.intersection.none = false;
		// Every model thinks it is in the center
		ray.intersection.CenterPoint = modelToWorld * Point3D(0,0,0); 
		return true;
	}

	// No intersection with cylinder disk
	// Check for intersection with cylinder body 
//---------------------------------------------------------------------------------
// Checking Intersection with Cylinder Body 
//---------------------------------------------------------------------------------

// Source: http://www.csie.ntu.edu.tw/~cyy/courses/rendering/pbrt-2.00/html/cylinder_8cpp_source.html

	// Compute Quadratic Cylinder Coefficients 
	double a = ObjectRay.dir[0]*ObjectRay.dir[0] + ObjectRay.dir[1]*ObjectRay.dir[1];
	double b = (ObjectRay.origin[0]*ObjectRay.dir[0] + ObjectRay.origin[1]* ObjectRay.dir[1]);
					
	double c = ObjectRay.origin[0]*ObjectRay.origin[0] + ObjectRay.origin[1]*ObjectRay.origin[1] - radius*radius;
													
	double discriminant = b*b-a*c;


	// If ray is aligned with body of the cylinder, there is no intersection 
	if (a == 0.0)
	{
		// return false
	}

	//If discrimant is < 0 => No real roots to the cylinder quadratic equation. 
	if (discriminant<0)
	{
		// It means no intersection 
		return false;
	}
	else
	{
		double rootOne = -b/a + sqrt(discriminant) / a;
		double rootTwo = -b/a - sqrt(discriminant) / a;
		if (rootOne< 0 && rootTwo < 0)
		{
			return false;
		}
		else if (rootOne> 0 && rootTwo < 0)
		{
			t_valueTwo = rootOne;
		}
		else
		{
			t_valueTwo = rootTwo;
		}
	}
//---------------------------------------------------------------------------------
//  Calculate the intersection point for the walls of the cylinder   
//---------------------------------------------------------------------------------
	// There is no intersection with the base of the cylinder on x,y plane
	// Check if there is intersection with sides. 

		// Get the intersection point for the sides 
		intersectionPoint = ObjectRay.origin+ t_valueTwo * ObjectRay.dir;
		// Check for no self intersection 
		if (t_valueTwo < 0.001)
		{
			return false;
		}
		// Get the coordinate of the normals for the sides of the cylinder 
		normal[0] = intersectionPoint[0];
		normal[1] = intersectionPoint[1];
		normal[2] = 0;
		normal.normalize();

		// If the intersection point is within the height of the cylinder
		if (intersectionPoint[2] < 0.5 && intersectionPoint[2] > -0.5)
		{
			// Ensure no previous intersection with lower t value 
			if (!ray.intersection.none && t_value > ray.intersection.t_value)
			{
				return false;
			}
			// Update the intersection to the ray 
			ray.intersection.point = modelToWorld * intersectionPoint;
			Point3D normalTemp;
			normalTemp[0] = intersectionPoint[0];
			normalTemp[1] = intersectionPoint[1];
			normalTemp[2] = 0;
			ray.intersection.normal = modelToWorld * (normalTemp - centerOfCylinder);
			ray.intersection.t_value = t_valueTwo;
			ray.intersection.none = false;
			// Every model thinks it is in the center
			ray.intersection.CenterPoint = modelToWorld * Point3D(0,0,0); 
			return true;
		}
		// If the intersection is not within the height of the cylinder,
		// It means there wasn't really a cylinder intersection to begin with  
		else
		{
			return false;
		}
}
Example #25
0
Vector3D Shape::calculateSurfaceNormal(Vector3D point0, Vector3D point1, Vector3D point2)
{
    Vector3D normal = (point1 - point0).cross(point2 - point0);
    normal.normalize();
    return normal;
}