Browse Source

Continue working on Cube mapping

Godzil 4 years ago
parent
commit
3ebe403de0
4 changed files with 456 additions and 14 deletions
  1. 103 14
      source/pattern/texturemap.h
  2. 4 0
      tests/CMakeLists.txt
  3. 238 0
      tests/pattern_test.cpp
  4. 111 0
      tests/uvmap_checkeredcube.cpp

+ 103 - 14
source/pattern/texturemap.h

@@ -19,6 +19,7 @@ enum TextureMapType
     SPHERICAL_MAP,
     PLANAR_MAP,
     CYLINDRICAL_MAP,
+    CUBIC_MAP
 };
 
 class TextureMap : public Pattern
@@ -26,6 +27,7 @@ class TextureMap : public Pattern
 private:
     TextureMapType type;
     UVPattern *pattern;
+    UVPattern *frontPat, *leftPat, *rightPat, *backPat, *upPat, *downPat;
 public:
     TextureMap(TextureMapType type, UVPattern *pattern) : Pattern(Colour(0, 0, 0), Colour(0, 0, 0)),
                                                           type(type), pattern(pattern) { };
@@ -80,25 +82,112 @@ public:
         v = modulo(point.y, 1.0);
     }
 
+    enum CubeFaces {
+        CUBE_LEFT,
+        CUBE_RIGHT,
+        CUBE_FRONT,
+        CUBE_BACK,
+        CUBE_UP,
+        CUBE_DOWN,
+    };
+
+    static CubeFaces faceFromPoint(Tuple point) {
+        double abs_x = fabs(point.x);
+        double abs_y = fabs(point.y);
+        double abs_z = fabs(point.z);
+
+        double coord = max3(abs_x, abs_y, abs_z);
+
+        if (coord == point.x) { return CUBE_RIGHT; }
+        if (coord == -point.x) { return CUBE_LEFT; }
+        if (coord == point.y) { return CUBE_UP; }
+        if (coord == -point.y) { return CUBE_DOWN; }
+        if (coord == point.z) { return CUBE_FRONT; }
+
+        return CUBE_BACK;
+    }
+
+    static void cubeUBFront(Tuple point, double &u, double &v) {
+        u = modulo(point.x + 1, 2.0) / 2.0;
+        v = modulo(point.y + 1, 2.0) / 2.0;
+    }
+
+    static void cubeUBBack(Tuple point, double &u, double &v) {
+        u = modulo(1 - point.x, 2.0) / 2.0;
+        v = modulo(point.y + 1, 2.0) / 2.0;
+    }
+
+    static void cubeUBLeft(Tuple point, double &u, double &v) {
+        u = modulo(point.z + 1, 2.0) / 2.0;
+        v = modulo(point.y + 1, 2.0) / 2.0;
+    }
+
+    static void cubeUBRight(Tuple point, double &u, double &v) {
+        u = modulo(1 - point.z, 2.0) / 2.0;
+        v = modulo(point.y + 1, 2.0) / 2.0;
+    }
+
+    static void cubeUBUp(Tuple point, double &u, double &v) {
+        u = modulo(point.x + 1, 2.0) / 2.0;
+        v = modulo(1 - point.z, 2.0) / 2.0;
+    }
+
+    static void cubeUBDown(Tuple point, double &u, double &v) {
+        u = modulo(point.x + 1, 2.0) / 2.0;
+        v = modulo(point.z + 1, 2.0) / 2.0;
+    }
+
+    void setCubePattern(UVPattern *front, UVPattern *left, UVPattern *right,
+                        UVPattern *back, UVPattern *up, UVPattern *down)
+    {
+        this->frontPat = front;
+        this->leftPat = left;
+        this->rightPat = right;
+        this->backPat = back;
+        this->upPat = up;
+        this->downPat = down;
+    }
+
     Colour patternAt(Tuple point)
     {
         double u,v;
-        switch(this->type)
+        if (this->type == CUBIC_MAP)
         {
-        default:
-        case SPHERICAL_MAP:
-            this->sphericalMap(point, u, v);
-            break;
-        case PLANAR_MAP:
-            this->planarMap(point, u, v);
-            break;
-
-        case CYLINDRICAL_MAP:
-            this->cylindricalMap(point, u, v);
-            break;
+            CubeFaces face = this->faceFromPoint(point);
+            UVPattern *facePat;
+            double u, v;
+            switch(face)
+            {
+            default:
+            case CUBE_LEFT:  facePat = this->leftPat;  this->cubeUBLeft(point, u, v);  break;
+            case CUBE_RIGHT: facePat = this->rightPat; this->cubeUBRight(point, u, v); break;
+            case CUBE_FRONT: facePat = this->frontPat; this->cubeUBFront(point, u, v); break;
+            case CUBE_BACK:  facePat = this->backPat;  this->cubeUBBack(point, u, v);  break;
+            case CUBE_UP:    facePat = this->upPat;    this->cubeUBUp(point, u, v);    break;
+            case CUBE_DOWN:  facePat = this->downPat;  this->cubeUBDown(point, u, v);  break;
+            }
+
+            return facePat->uvPatternAt(u, v);
+        }
+        else
+        {
+            switch (this->type)
+            {
+            default:
+            case SPHERICAL_MAP:
+                this->sphericalMap(point, u, v);
+                break;
+            case PLANAR_MAP:
+                this->planarMap(point, u, v);
+                break;
+
+            case CYLINDRICAL_MAP:
+                this->cylindricalMap(point, u, v);
+                break;
+            }
+
+            return this->pattern->uvPatternAt(u, v);
         }
-
-        return this->pattern->uvPatternAt(u, v);
     }
 
     void dumpMe(FILE *fp) {

+ 4 - 0
tests/CMakeLists.txt

@@ -83,6 +83,9 @@ target_sources(uvmap_checkeredplane PRIVATE uvmap_checkeredplane.cpp)
 add_executable(uvmap_checkeredcylinder)
 target_sources(uvmap_checkeredcylinder PRIVATE uvmap_checkeredcylinder.cpp)
 
+add_executable(uvmap_checkeredcube)
+target_sources(uvmap_checkeredcube PRIVATE uvmap_checkeredcube.cpp)
+
 add_executable(uvmap_aligncheckplane)
 target_sources(uvmap_aligncheckplane PRIVATE uvmap_aligncheckplane.cpp)
 
@@ -103,6 +106,7 @@ add_test(NAME UVMap_CheckeredSphere COMMAND $<TARGET_FILE:uvmap_checkeredsphere>
 add_test(NAME UVMap_CheckeredPlane COMMAND $<TARGET_FILE:uvmap_checkeredplane>)
 add_test(NAME UVMap_CheckeredCylinder COMMAND $<TARGET_FILE:uvmap_checkeredcylinder>)
 add_test(NAME UVMap_AlignCheckPlane COMMAND $<TARGET_FILE:uvmap_aligncheckplane>)
+add_test(NAME UVMap_CheckeredCube COMMAND $<TARGET_FILE:uvmap_checkeredcube>)
 add_test(NAME Test_Rendering COMMAND $<TARGET_FILE:test_render>)
 add_test(NAME Triangle_RenderTest COMMAND $<TARGET_FILE:triangle_rendertest>)
 add_test(NAME ChristmasBall_Rendering COMMAND $<TARGET_FILE:christmasball_render>)

+ 238 - 0
tests/pattern_test.cpp

@@ -466,4 +466,242 @@ TEST(PatternTest, Layout_of_the_align_check_pattern)
         Colour ret = uvac.uvPatternAt(testList[i][0], testList[i][1]);
         ASSERT_EQ(ret, testResults[i]);
     }
+}
+
+TEST(PatternTest, Identifying_the_face_of_a_cube_from_a_point)
+{
+    Point testList[] = {
+            Point(-1, 0.5, -0.25),
+            Point(1.1, -0.75, 0.8),
+            Point(0.1, 0.6, 0.9),
+            Point(-0.7, 0, -2),
+            Point(0.5, 1, 0.9),
+            Point(-0.2, -1.3, 1.1),
+    };
+
+    TextureMap::CubeFaces testResults[] {
+            TextureMap::CUBE_LEFT,
+            TextureMap::CUBE_RIGHT,
+            TextureMap::CUBE_FRONT,
+            TextureMap::CUBE_BACK,
+            TextureMap::CUBE_UP,
+            TextureMap::CUBE_DOWN,
+    };
+
+    int testCount = sizeof(testList)/sizeof((testList)[0]);
+    int i;
+
+    TextureMap tm = TextureMap(CUBIC_MAP, nullptr);
+
+    for(i = 0; i < testCount; i++)
+    {
+        TextureMap::CubeFaces face = tm.faceFromPoint(testList[i]);
+        ASSERT_EQ(face, testResults[i]);
+    }
+}
+
+TEST(PatternTest, UV_mapping_the_front_face_of_a_cube)
+{
+    Point testList[] = {
+            Point(-0.5, 0.5, 1),
+            Point(0.5, -0.5, 1),
+    };
+
+    double testResults[][2] {
+            {0.25, 0.75},
+            {0.75, 0.25},
+    };
+
+    int testCount = sizeof(testList)/sizeof((testList)[0]);
+    int i;
+
+    TextureMap tm = TextureMap(CUBIC_MAP, nullptr);
+
+    for(i = 0; i < testCount; i++)
+    {
+        double u, v;
+        tm.cubeUBFront(testList[i], u, v);
+        ASSERT_TRUE(double_equal(u, testResults[i][0]));
+        ASSERT_TRUE(double_equal(v, testResults[i][1]));
+    }
+}
+
+TEST(PatternTest, UV_mapping_the_back_face_of_a_cube)
+{
+    Point testList[] = {
+            Point(0.5, 0.5, -1),
+            Point(-0.5, -0.5, -1),
+    };
+
+    double testResults[][2] {
+            {0.25, 0.75},
+            {0.75, 0.25},
+    };
+
+    int testCount = sizeof(testList)/sizeof((testList)[0]);
+    int i;
+
+    TextureMap tm = TextureMap(CUBIC_MAP, nullptr);
+
+    for(i = 0; i < testCount; i++)
+    {
+        double u, v;
+        tm.cubeUBBack(testList[i], u, v);
+        ASSERT_TRUE(double_equal(u, testResults[i][0]));
+        ASSERT_TRUE(double_equal(v, testResults[i][1]));
+    }
+}
+
+TEST(PatternTest, UV_mapping_the_left_face_of_a_cube)
+{
+    Point testList[] = {
+            Point(-1, 0.5, -0.5),
+            Point(-1, -0.5, 0.5),
+    };
+
+    double testResults[][2] {
+            {0.25, 0.75},
+            {0.75, 0.25},
+    };
+
+    int testCount = sizeof(testList)/sizeof((testList)[0]);
+    int i;
+
+    TextureMap tm = TextureMap(CUBIC_MAP, nullptr);
+
+    for(i = 0; i < testCount; i++)
+    {
+        double u, v;
+        tm.cubeUBLeft(testList[i], u, v);
+        ASSERT_TRUE(double_equal(u, testResults[i][0]));
+        ASSERT_TRUE(double_equal(v, testResults[i][1]));
+    }
+}
+
+TEST(PatternTest, UV_mapping_the_right_face_of_a_cube)
+{
+    Point testList[] = {
+            Point(1, 0.5, 0.5),
+            Point(1, -0.5, -0.5),
+    };
+
+    double testResults[][2] {
+            {0.25, 0.75},
+            {0.75, 0.25},
+    };
+
+    int testCount = sizeof(testList)/sizeof((testList)[0]);
+    int i;
+
+    TextureMap tm = TextureMap(CUBIC_MAP, nullptr);
+
+    for(i = 0; i < testCount; i++)
+    {
+        double u, v;
+        tm.cubeUBRight(testList[i], u, v);
+        ASSERT_TRUE(double_equal(u, testResults[i][0]));
+        ASSERT_TRUE(double_equal(v, testResults[i][1]));
+    }
+}
+
+TEST(PatternTest, UV_mapping_the_up_face_of_a_cube)
+{
+    Point testList[] = {
+            Point(-0.5, 1, -0.5),
+            Point(0.5, 1, 0.5),
+    };
+
+    double testResults[][2] {
+            {0.25, 0.75},
+            {0.75, 0.25},
+    };
+
+    int testCount = sizeof(testList)/sizeof((testList)[0]);
+    int i;
+
+    TextureMap tm = TextureMap(CUBIC_MAP, nullptr);
+
+    for(i = 0; i < testCount; i++)
+    {
+        double u, v;
+        tm.cubeUBUp(testList[i], u, v);
+        ASSERT_TRUE(double_equal(u, testResults[i][0]));
+        ASSERT_TRUE(double_equal(v, testResults[i][1]));
+    }
+}
+
+TEST(PatternTest, UV_mapping_the_down_face_of_a_cube)
+{
+    Point testList[] = {
+            Point(-0.5, -1, 0.5),
+            Point(0.5, -1, -0.5),
+    };
+
+    double testResults[][2] {
+            {0.25, 0.75},
+            {0.75, 0.25},
+    };
+
+    int testCount = sizeof(testList)/sizeof((testList)[0]);
+    int i;
+
+    TextureMap tm = TextureMap(CUBIC_MAP, nullptr);
+
+    for(i = 0; i < testCount; i++)
+    {
+        double u, v;
+        tm.cubeUBDown(testList[i], u, v);
+        ASSERT_TRUE(double_equal(u, testResults[i][0]));
+        ASSERT_TRUE(double_equal(v, testResults[i][1]));
+    }
+}
+
+TEST(PatternTest, Finding_the_colours_on_a_mapped_cube)
+{
+    Colour red = Colour(1, 0, 0);
+    Colour yellow = Colour(1, 1, 0);
+    Colour brown = Colour(1, 0.5, 0);
+    Colour green = Colour(0, 1, 0);
+    Colour cyan = Colour(0, 1, 1);
+    Colour blue = Colour(0, 0, 1);
+    Colour purple = Colour(1, 0, 1);
+    Colour white = Colour(1, 1, 1);
+
+    UVAlignCheck left = UVAlignCheck(yellow, cyan, red, blue, brown);
+    UVAlignCheck front = UVAlignCheck(cyan, red, yellow, brown, green);
+    UVAlignCheck right = UVAlignCheck(red, yellow, purple, green, white);
+    UVAlignCheck back = UVAlignCheck(green, purple, cyan, white, blue);
+    UVAlignCheck up = UVAlignCheck(brown, cyan, purple, red, yellow);
+    UVAlignCheck down = UVAlignCheck(purple, brown, green, blue, white);
+
+    TextureMap tm = TextureMap(CUBIC_MAP, nullptr);
+    tm.setCubePattern(&front, &left, &right, &back, &up, &down);
+
+    Point testList[] = {
+            Point(-1, 0, 0), Point(-1, 0.9, -0.9), Point(-1, 0.9, 0.9), Point(-1, -0.9, -0.9), Point(-1, -0.9, 0.9), /* left */
+            Point(0, 0, 1), Point(-0.9, 0.9, 1), Point(0.9, 0.9, 1), Point(-0.9, -0.9, 1), Point(0.9, -0.9, 1), /* front */
+            Point(1, 0, 0), Point(1, 0.9, 0.9), Point(1, 0.9, -0.9), Point(1, -0.9, 0.9), Point(1, -0.9, -0.9), /* right */
+            Point(0, 0, -1), Point(0.9, 0.9, -1), Point(-0.9, 0.9, -1), Point(0.9, -0.9, -1), Point(-0.9, -0.9, -1), /* back */
+            Point(0, 1, 0), Point(-0.9, 1, -0.9), Point(0.9, 1, -0.9), Point(-0.9, 1, 0.9), Point(0.9, 1, 0.9), /* up */
+            Point(0, -1, 0), Point(-0.9, -1, 0.9), Point(0.9, -1, 0.9), Point(-0.9, -1, -0.9), Point(0.9, -1, -0.9), /* down */
+    };
+
+    Colour testResults[] {
+            yellow, cyan, red, blue, brown,         /* left  */
+            cyan, red, yellow, brown, green,        /* front */
+            red, yellow, purple, green, white,      /* right */
+            green, purple, cyan, white, blue,       /* back  */
+            brown, cyan, purple, red, yellow,       /* up    */
+            purple, brown, green, blue, white,      /* down  */
+    };
+
+    int testCount = sizeof(testList)/sizeof((testList)[0]);
+    int i;
+
+    for(i = 0; i < testCount; i++)
+    {
+        Colour ret = tm.patternAt(testList[i]);
+        ASSERT_EQ(ret, testResults[i]);
+    }
+
 }

+ 111 - 0
tests/uvmap_checkeredcube.cpp

@@ -0,0 +1,111 @@
+/*
+ *  DoRayMe - a quick and dirty Raytracer
+ *  Render test for chapter 10
+ *
+ *  Created by Manoël Trapier
+ *  Copyright (c) 2020 986-Studio.
+ *
+ */
+#include <world.h>
+#include <light.h>
+#include <cube.h>
+#include <material.h>
+#include <colour.h>
+#include <canvas.h>
+#include <camera.h>
+
+#include <pattern.h>
+#include <texturemap.h>
+#include <uv_aligncheck.h>
+
+#include <transformation.h>
+
+Colour red = Colour(1, 0, 0);
+Colour yellow = Colour(1, 1, 0);
+Colour brown = Colour(1, 0.5, 0);
+Colour green = Colour(0, 1, 0);
+Colour cyan = Colour(0, 1, 1);
+Colour blue = Colour(0, 0, 1);
+Colour purple = Colour(1, 0, 1);
+Colour white = Colour(1, 1, 1);
+
+UVAlignCheck left = UVAlignCheck(yellow, cyan, red, blue, brown);
+UVAlignCheck front = UVAlignCheck(cyan, red, yellow, brown, green);
+UVAlignCheck right = UVAlignCheck(red, yellow, purple, green, white);
+UVAlignCheck back = UVAlignCheck(green, purple, cyan, white, blue);
+UVAlignCheck up = UVAlignCheck(brown, cyan, purple, red, yellow);
+UVAlignCheck down = UVAlignCheck(purple, brown, green, blue, white);
+
+Shape *MappedCube()
+{
+    Cube *ret = new Cube();
+    TextureMap *tm =  new TextureMap(CUBIC_MAP, nullptr);
+    tm->setCubePattern(&front, &left, &right, &back, &up, &down);
+    ret->material.pattern = tm;
+    ret->material.ambient = 0.2;
+    ret->material.specular = 0;
+    ret->material.diffuse = 0.8;
+
+    return ret;
+}
+
+int main()
+{
+    World w = World();
+
+    Light light1 = Light(POINT_LIGHT, Point(0, 100, -100), Colour(0.25, 0.25, 0.25));
+    w.addLight(&light1);
+    Light light2 = Light(POINT_LIGHT, Point(0, -100, -100), Colour(0.25, 0.25, 0.25));
+    w.addLight(&light2);
+    Light light3 = Light(POINT_LIGHT, Point(-100, 0, -100), Colour(0.25, 0.25, 0.25));
+    w.addLight(&light3);
+    Light light4 = Light(POINT_LIGHT, Point(100, 0, -100), Colour(0.25, 0.25, 0.25));
+    w.addLight(&light4);
+
+    Shape *s;
+
+    s = MappedCube();
+    s->setTransform(translation(-6, 2, 0) * rotationX(0.7854) * rotationY(0.7854));
+    w.addObject(s);
+
+    s = MappedCube();
+    s->setTransform(translation(-2, 2, 0) * rotationX(0.7854) * rotationY(2.3562));
+    w.addObject(s);
+
+    s = MappedCube();
+    s->setTransform(translation(2, 2, 0) * rotationX(0.7854) * rotationY(3.927));
+    w.addObject(s);
+
+    s = MappedCube();
+    s->setTransform(translation(6, 2, 0) * rotationX(0.7854) * rotationY(5.4978));
+    w.addObject(s);
+
+    s = MappedCube();
+    s->setTransform(translation(-6, -2, 0) * rotationX(-0.7854) * rotationY(0.7854));
+    w.addObject(s);
+
+    s = MappedCube();
+    s->setTransform(translation(-2, -2, 0) * rotationX(-0.7854) * rotationY(2.3562));
+    w.addObject(s);
+
+    s = MappedCube();
+    s->setTransform(translation(2, -2, 0) * rotationX(-0.7854) * rotationY(3.927));
+    w.addObject(s);
+
+    s = MappedCube();
+    s->setTransform(translation(6, -2, 0) * rotationX(-0.7854) * rotationY(5.4978));
+    w.addObject(s);
+
+    /* Set the camera */
+    Camera camera = Camera(800, 400, 0.8);
+    camera.setTransform(viewTransform(Point(0, 0, -20),
+                                      Point(0, 0, 0),
+                                      Vector(0, 1, 0)));
+
+    /* Now render it */
+    Canvas image = camera.render(w);
+
+    image.SaveAsPNG("uvmap_checkeredcube.png");
+
+    return 0;
+}