diff --git a/README.md b/README.md index 6923803..d076a69 100644 --- a/README.md +++ b/README.md @@ -87,4 +87,7 @@ Spherical mapping: ![Spherical mapping](output/uvmap_checkeredsphere.png) Planar mapping: -![Planar mapping](output/uvmap_checkeredplane.png) \ No newline at end of file +![Planar mapping](output/uvmap_checkeredplane.png) + +Cylindrical mapping: +![Cylindrical mapping](output/uvmap_checkeredcylinder.png) \ No newline at end of file diff --git a/output/uvmap_checkeredcylinder.png b/output/uvmap_checkeredcylinder.png new file mode 100644 index 0000000..8bc0836 Binary files /dev/null and b/output/uvmap_checkeredcylinder.png differ diff --git a/source/pattern/texturemap.h b/source/pattern/texturemap.h index 0daf3ae..ba70855 100644 --- a/source/pattern/texturemap.h +++ b/source/pattern/texturemap.h @@ -67,8 +67,17 @@ public: } static void planarMap(Tuple point, double &u, double &v) { - u = fmod(point.x, 1); - v = fmod(point.z, 1); + u = modulo(point.x, 1.0); + v = modulo(point.z, 1.0); + } + + static void cylindricalMap(Tuple point, double &u, double &v) { + /* Let's get the azimuthal angle, same as with the spherical mapping */ + double theta = atan2(point.x , point.z); + double raw_u = theta / (2 * M_PI); + + u = 1 - (raw_u + 0.5); + v = modulo(point.y, 1.0); } Colour patternAt(Tuple point) @@ -83,6 +92,10 @@ public: case PLANAR_MAP: this->planarMap(point, u, v); break; + + case CYLINDRICAL_MAP: + this->cylindricalMap(point, u, v); + break; } return this->pattern->uvPatternAt(u, v); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e080d50..2e6222f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -80,6 +80,9 @@ target_sources(uvmap_checkeredsphere PRIVATE uvmap_checkeredsphere.cpp) add_executable(uvmap_checkeredplane) target_sources(uvmap_checkeredplane PRIVATE uvmap_checkeredplane.cpp) +add_executable(uvmap_checkeredcylinder) +target_sources(uvmap_checkeredcylinder PRIVATE uvmap_checkeredcylinder.cpp) + add_test(NAME Chapter05_Test COMMAND $) add_test(NAME Chapter06_Test COMMAND $) add_test(NAME Chapter07_Test COMMAND $) @@ -95,6 +98,7 @@ add_test(NAME Chapter14_Test COMMAND $) add_test(NAME AreaLight_Test COMMAND $) add_test(NAME UVMap_CheckeredSphere COMMAND $) add_test(NAME UVMap_CheckeredPlane COMMAND $) +add_test(NAME UVMap_CheckeredCylinder COMMAND $) add_test(NAME Test_Rendering COMMAND $) add_test(NAME Triangle_RenderTest COMMAND $) add_test(NAME ChristmasBall_Rendering COMMAND $) diff --git a/tests/pattern_test.cpp b/tests/pattern_test.cpp index 3878ca2..5044c5e 100644 --- a/tests/pattern_test.cpp +++ b/tests/pattern_test.cpp @@ -387,4 +387,46 @@ TEST(PatternTest, Using_a_planar_mapping_on_a_3d_point) ASSERT_TRUE(double_equal(u, testResults[i][0])); ASSERT_TRUE(double_equal(v, testResults[i][1])); } +} + +TEST(PatternTest, Using_a_cylindrical_mapping_on_a_3d_point) +{ + Point testList[] = { + Point( 0.00000, 0.00, -1.00000), + Point( 0.00000, 0.50, -1.00000), + Point( 0.00000, 1.00, -1.00000), + Point( 0.70711, 0.50, -0.70711), + Point( 1.00000, 0.50, -0.00000), + Point( 0.70711, 0.50, 0.70711), + Point( 0.00000, -0.25, 1.00000), + Point(-0.70711, 0.50, 0.70711), + Point(-1.00000, 1.25, 0.00000), + Point(-0.70711, 0.50, -0.70711), + }; + + double testResults[][2] { + {0.000, 0.00}, + {0.000, 0.50}, + {0.000, 0.00}, + {0.125, 0.50}, + {0.250, 0.50}, + {0.375, 0.50}, + {0.500, 0.75}, + {0.625, 0.50}, + {0.750, 0.25}, + {0.875, 0.50}, + }; + + int testCount = sizeof(testList)/sizeof((testList)[0]); + int i; + + TextureMap tm = TextureMap(CYLINDRICAL_MAP, nullptr); + + for(i = 0; i < testCount; i++) + { + double u, v; + tm.cylindricalMap(testList[i], u, v); + ASSERT_TRUE(double_equal(u, testResults[i][0])); + ASSERT_TRUE(double_equal(v, testResults[i][1])); + } } \ No newline at end of file diff --git a/tests/uvmap_checkeredcylinder.cpp b/tests/uvmap_checkeredcylinder.cpp new file mode 100644 index 0000000..c88d998 --- /dev/null +++ b/tests/uvmap_checkeredcylinder.cpp @@ -0,0 +1,58 @@ +/* + * DoRayMe - a quick and dirty Raytracer + * Render test for chapter 10 + * + * Created by Manoƫl Trapier + * Copyright (c) 2020 986-Studio. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +int main() +{ + World w = World(); + + Light light = Light(POINT_LIGHT, Point(-10, 10, -10), Colour(1, 1, 1)); + w.addLight(&light); + + Cylinder sp = Cylinder(); + sp.minCap = 0; + sp.maxCap = 1; + sp.setTransform(scaling(1, 3.1415, 1) * translation(0, -0.5, 0)); + UVCheckers checkers = UVCheckers(16, 8, Colour(0, 0.5, 0), Colour(1, 1, 1)); + TextureMap tm = TextureMap(CYLINDRICAL_MAP, &checkers); + sp.material.pattern = &tm; + sp.material.ambient = 0.1; + sp.material.specular = 0.6; + sp.material.shininess = 15; + sp.material.diffuse = 0.8; + + w.addObject(&sp); + + /* Set the camera */ + Camera camera = Camera(400, 400, 0.5); + camera.setTransform(viewTransform(Point(0, 0, -10), + Point(0, 0, 0), + Vector(0, 1, 0))); + + /* Now render it */ + Canvas image = camera.render(w); + + image.SaveAsPNG("uvmap_checkeredcylinder.png"); + + return 0; +} \ No newline at end of file