Shape is now an abstract class and can't be instanciated.
Change derived shape to only deal with local calculation they don't need anymore to deal with how they've been transformed.
This commit is contained in:
@@ -29,6 +29,10 @@ class Shape
|
|||||||
private:
|
private:
|
||||||
ShapeType type;
|
ShapeType type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual Intersect localIntersect(Ray r) = 0;
|
||||||
|
virtual Tuple localNormalAt(Tuple point) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Matrix transformMatrix;
|
Matrix transformMatrix;
|
||||||
Matrix inverseTransform;
|
Matrix inverseTransform;
|
||||||
@@ -37,8 +41,8 @@ public:
|
|||||||
public:
|
public:
|
||||||
Shape(ShapeType = SHAPE_NONE);
|
Shape(ShapeType = SHAPE_NONE);
|
||||||
|
|
||||||
virtual Intersect intersect(Ray r);
|
Intersect intersect(Ray r);
|
||||||
virtual Tuple normalAt(Tuple point);
|
Tuple normalAt(Tuple point);
|
||||||
|
|
||||||
void setTransform(Matrix transform);
|
void setTransform(Matrix transform);
|
||||||
void setMaterial(Material material) { this->material = material; };
|
void setMaterial(Material material) { this->material = material; };
|
||||||
|
|||||||
@@ -15,11 +15,13 @@
|
|||||||
|
|
||||||
class Sphere : public Shape
|
class Sphere : public Shape
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
Intersect localIntersect(Ray r);
|
||||||
|
Tuple localNormalAt(Tuple point);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Sphere() : Shape(SHAPE_SPHERE) { };
|
Sphere() : Shape(SHAPE_SPHERE) { };
|
||||||
/* All sphere are at (0, 0, 0) and radius 1 in the object space */
|
/* All sphere are at (0, 0, 0) and radius 1 in the object space */
|
||||||
virtual Intersect intersect(Ray r);
|
|
||||||
virtual Tuple normalAt(Tuple point);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* DORAYME_SPHERE_H */
|
#endif /* DORAYME_SPHERE_H */
|
||||||
|
|||||||
28
source/include/testshape.h
Normal file
28
source/include/testshape.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Test shape header
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef DORAYME_TESTSHAPE_H
|
||||||
|
#define DORAYME_TESTSHAPE_H
|
||||||
|
|
||||||
|
#include <shape.h>
|
||||||
|
#include <ray.h>
|
||||||
|
#include <tuple.h>
|
||||||
|
|
||||||
|
class TestShape : public Shape
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Intersect localIntersect(Ray r);
|
||||||
|
Tuple localNormalAt(Tuple point);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Ray localRay;
|
||||||
|
|
||||||
|
TestShape();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //DORAYME_TESTSHAPE_H
|
||||||
@@ -22,12 +22,21 @@ Shape::Shape(ShapeType type)
|
|||||||
|
|
||||||
Intersect Shape::intersect(Ray r)
|
Intersect Shape::intersect(Ray r)
|
||||||
{
|
{
|
||||||
return Intersect();
|
return this->localIntersect(this->invTransform(r));
|
||||||
};
|
};
|
||||||
|
|
||||||
Tuple Shape::normalAt(Tuple point)
|
Tuple Shape::normalAt(Tuple point)
|
||||||
{
|
{
|
||||||
return Vector(0, 0, 0);
|
Tuple local_point = this->inverseTransform * point;
|
||||||
|
|
||||||
|
Tuple local_normal = this->localNormalAt(local_point);
|
||||||
|
|
||||||
|
Tuple world_normal = this->inverseTransform.transpose() * local_normal;
|
||||||
|
|
||||||
|
/* W may get wrong, so hack it. This is perfectly normal as we are using a 4x4 matrix instead of a 3x3 */
|
||||||
|
world_normal.w = 0;
|
||||||
|
|
||||||
|
return world_normal.normalise();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shape::setTransform(Matrix transform)
|
void Shape::setTransform(Matrix transform)
|
||||||
|
|||||||
@@ -13,17 +13,15 @@
|
|||||||
#include <tuple.h>
|
#include <tuple.h>
|
||||||
#include <intersect.h>
|
#include <intersect.h>
|
||||||
|
|
||||||
Intersect Sphere::intersect(Ray r)
|
Intersect Sphere::localIntersect(Ray r)
|
||||||
{
|
{
|
||||||
Intersect ret;
|
Intersect ret;
|
||||||
double a, b, c, discriminant;
|
double a, b, c, discriminant;
|
||||||
|
|
||||||
Ray transRay = this->invTransform(r);
|
Tuple sphere_to_ray = r.origin - Point(0, 0, 0);
|
||||||
|
|
||||||
Tuple sphere_to_ray = transRay.origin - Point(0, 0, 0);
|
a = r.direction.dot(r.direction);
|
||||||
|
b = 2 * r.direction.dot(sphere_to_ray);
|
||||||
a = transRay.direction.dot(transRay.direction);
|
|
||||||
b = 2 * transRay.direction.dot(sphere_to_ray);
|
|
||||||
c = sphere_to_ray.dot(sphere_to_ray) - 1;
|
c = sphere_to_ray.dot(sphere_to_ray) - 1;
|
||||||
|
|
||||||
discriminant = b * b - 4 * a * c;
|
discriminant = b * b - 4 * a * c;
|
||||||
@@ -37,14 +35,7 @@ Intersect Sphere::intersect(Ray r)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple Sphere::normalAt(Tuple point)
|
Tuple Sphere::localNormalAt(Tuple point)
|
||||||
{
|
{
|
||||||
Tuple object_point = this->inverseTransform * point;
|
return (point - Point(0, 0, 0)).normalise();
|
||||||
Tuple object_normal = (object_point - Point(0, 0, 0)).normalise();
|
|
||||||
Tuple world_normal = this->inverseTransform.transpose() * object_normal;
|
|
||||||
|
|
||||||
/* W may get wrong, so hack it. This is perfectly normal as we are using a 4x4 matrix instead of a 3x3 */
|
|
||||||
world_normal.w = 0;
|
|
||||||
|
|
||||||
return world_normal.normalise();
|
|
||||||
}
|
}
|
||||||
25
source/shapes/testshape.cpp
Normal file
25
source/shapes/testshape.cpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* DoRayMe - a quick and dirty Raytracer
|
||||||
|
* Test shape implementation
|
||||||
|
*
|
||||||
|
* Created by Manoël Trapier
|
||||||
|
* Copyright (c) 2020 986-Studio.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <shape.h>
|
||||||
|
#include <testshape.h>
|
||||||
|
|
||||||
|
TestShape::TestShape() : localRay(Point(0, 0, 0), Vector(0, 0, 0))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Intersect TestShape::localIntersect(Ray r)
|
||||||
|
{
|
||||||
|
this->localRay = r;
|
||||||
|
return Intersect();
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple TestShape::localNormalAt(Tuple point)
|
||||||
|
{
|
||||||
|
return Vector(point.x, point.y, point.z);
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <ray.h>
|
#include <ray.h>
|
||||||
#include <transformation.h>
|
#include <transformation.h>
|
||||||
#include <shape.h>
|
#include <shape.h>
|
||||||
|
#include <testshape.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ TEST(RayTest, Translating_a_ray)
|
|||||||
Ray r = Ray(Point(1, 2, 3), Vector(0, 1, 0));
|
Ray r = Ray(Point(1, 2, 3), Vector(0, 1, 0));
|
||||||
|
|
||||||
Matrix m = translation(3, 4, 5);
|
Matrix m = translation(3, 4, 5);
|
||||||
Shape o = Shape();
|
TestShape o = TestShape();
|
||||||
|
|
||||||
o.setTransform(m);
|
o.setTransform(m);
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ TEST(RayTest, Scaling_a_ray)
|
|||||||
Ray r = Ray(Point(1, 2, 3), Vector(0, 1, 0));
|
Ray r = Ray(Point(1, 2, 3), Vector(0, 1, 0));
|
||||||
|
|
||||||
Matrix m = scaling(2, 3, 4);
|
Matrix m = scaling(2, 3, 4);
|
||||||
Shape o = Shape();
|
TestShape o = TestShape();
|
||||||
|
|
||||||
o.setTransform(m);
|
o.setTransform(m);
|
||||||
|
|
||||||
|
|||||||
@@ -7,19 +7,20 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <shape.h>
|
#include <shape.h>
|
||||||
|
#include <testshape.h>
|
||||||
#include <matrix.h>
|
#include <matrix.h>
|
||||||
#include <transformation.h>
|
#include <transformation.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
TEST(ShapeTest, The_default_transformation)
|
TEST(ShapeTest, The_default_transformation)
|
||||||
{
|
{
|
||||||
Shape s = Shape();
|
TestShape s = TestShape();
|
||||||
ASSERT_EQ(s.transformMatrix, Matrix4().identity());
|
ASSERT_EQ(s.transformMatrix, Matrix4().identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ShapeTest, Assigning_a_transformation)
|
TEST(ShapeTest, Assigning_a_transformation)
|
||||||
{
|
{
|
||||||
Shape s = Shape();
|
TestShape s = TestShape();
|
||||||
|
|
||||||
s.setTransform(translation(2, 3, 4));
|
s.setTransform(translation(2, 3, 4));
|
||||||
|
|
||||||
@@ -28,14 +29,14 @@ TEST(ShapeTest, Assigning_a_transformation)
|
|||||||
|
|
||||||
TEST(ShapeTest, The_default_material)
|
TEST(ShapeTest, The_default_material)
|
||||||
{
|
{
|
||||||
Shape s = Shape();
|
TestShape s = TestShape();
|
||||||
|
|
||||||
ASSERT_EQ(s.material, Material());
|
ASSERT_EQ(s.material, Material());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ShapeTest, Assigning_a_material)
|
TEST(ShapeTest, Assigning_a_material)
|
||||||
{
|
{
|
||||||
Shape s = Shape();
|
TestShape s = TestShape();
|
||||||
Material m = Material();
|
Material m = Material();
|
||||||
m.ambient = 1;
|
m.ambient = 1;
|
||||||
|
|
||||||
@@ -43,3 +44,55 @@ TEST(ShapeTest, Assigning_a_material)
|
|||||||
|
|
||||||
ASSERT_EQ(s.material, m);
|
ASSERT_EQ(s.material, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ShapeTest, Intersecting_a_scaled_shape_with_a_ray)
|
||||||
|
{
|
||||||
|
Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
|
||||||
|
TestShape s = TestShape();
|
||||||
|
|
||||||
|
s.setTransform(scaling(2, 2, 2));
|
||||||
|
Intersect xs = s.intersect(r);
|
||||||
|
|
||||||
|
ASSERT_EQ(s.localRay.origin, Point(0, 0, -2.5));
|
||||||
|
ASSERT_EQ(s.localRay.direction, Vector(0, 0, 0.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ShapeTest, Intersecting_a_translated_shape_with_a_ray)
|
||||||
|
{
|
||||||
|
Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
|
||||||
|
TestShape s = TestShape();
|
||||||
|
|
||||||
|
s.setTransform(translation(5, 0, 0));
|
||||||
|
Intersect xs = s.intersect(r);
|
||||||
|
|
||||||
|
ASSERT_EQ(s.localRay.origin, Point(-5, 0, -5));
|
||||||
|
ASSERT_EQ(s.localRay.direction, Vector(0, 0, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ShapeTest, Computing_the_normal_on_a_translated_shape)
|
||||||
|
{
|
||||||
|
TestShape s = TestShape();
|
||||||
|
s.setTransform(translation(0, 1, 0));
|
||||||
|
Tuple n = s.normalAt(Point(0, 1.70711, -0.70711));
|
||||||
|
|
||||||
|
/* Temporary lower the precision */
|
||||||
|
set_equal_precision(0.00001);
|
||||||
|
|
||||||
|
ASSERT_EQ(n, Vector(0, 0.70711, -0.70711));
|
||||||
|
|
||||||
|
set_equal_precision(FLT_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ShapeTest, Computing_the_normal_on_a_tranformed_shape)
|
||||||
|
{
|
||||||
|
TestShape s = TestShape();
|
||||||
|
s.setTransform(scaling(1, 0.5, 1) * rotationZ(M_PI / 5));
|
||||||
|
Tuple n = s.normalAt(Point(0, sqrt(2)/2, -sqrt(2)/2));
|
||||||
|
|
||||||
|
/* Temporary lower the precision */
|
||||||
|
set_equal_precision(0.00001);
|
||||||
|
|
||||||
|
ASSERT_EQ(n, Vector(0, 0.97014, -0.24254));
|
||||||
|
|
||||||
|
set_equal_precision(FLT_EPSILON);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user