aboutsummaryrefslogtreecommitdiff
path: root/src/texture/texture.cpp
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2023-12-07 16:23:20 -0500
committersotech117 <michael_foiani@brown.edu>2023-12-07 16:23:20 -0500
commitcaa765bff49d54217b75aaf0e7acf4e5392a11e4 (patch)
tree9b92914dfb88b99599e8e60e4512e9e9ea9a25db /src/texture/texture.cpp
parenta9274459443f1d560d7580a162deb581549980cb (diff)
upload base code
Diffstat (limited to 'src/texture/texture.cpp')
-rw-r--r--src/texture/texture.cpp180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/texture/texture.cpp b/src/texture/texture.cpp
new file mode 100644
index 0000000..1fa4353
--- /dev/null
+++ b/src/texture/texture.cpp
@@ -0,0 +1,180 @@
+//
+// Created by Michael Foiani on 11/4/23.
+//
+
+#include "raytracer/raytracer.h"
+
+glm::vec2 getUVCube(glm::vec4 pObject) {
+ float u = -1.f,v = -1.f;
+
+ if (RayTracer::floatEquals(pObject.y, -.5f)) // neg y, bottom face
+ {
+ u = pObject.x + 0.5f;
+ v = pObject.z + 0.5f;
+ }
+ else if (RayTracer::floatEquals(pObject.y, .5f)) // pos y, top face
+ {
+ u = pObject.x + 0.5f;
+ v = .5f - pObject.z; // flip z
+ }
+ else if (RayTracer::floatEquals(pObject.x, -.5f)) // neg x, left face
+ {
+ u = pObject.z + 0.5f;
+ v = pObject.y + 0.5f;
+ }
+ else if (RayTracer::floatEquals(pObject.x, .5f)) // pos x, right face
+ {
+ u = .5f - pObject.z; // flip z
+ v = pObject.y + 0.5f;
+ }
+ else if (RayTracer::floatEquals(pObject.z, -.5f)) // neg z, back face
+ {
+ u = .5f - pObject.x; // flip x
+ v = pObject.y + 0.5f;
+ }
+ else if (RayTracer::floatEquals(pObject.z, .5f)) // pos z, front face
+ {
+ u = pObject.x + 0.5f;
+ v = pObject.y + 0.5f;
+ }
+
+ return {u, v};
+}
+
+glm::vec2 getUVCone(glm::vec4 pObject) {
+ float u, v;
+
+ // three cases -> 1) top cap, 2) bottom cap, 3) conical side
+ if (RayTracer::floatEquals(pObject.y, -.5f)) // 1) bottom cap
+ {
+ u = pObject.x + 0.5f;
+ v = pObject.z + 0.5f;
+ }
+ else if (RayTracer::floatEquals(pObject.y, .5f)) // 2) top cap
+ {
+ u = pObject.x + 0.5f;
+ v = 0.5f - pObject.z; // flip z
+ }
+ else // case 3) conical face
+ {
+ // get u from theta zpos and xpos
+ float theta = glm::atan(pObject.x, pObject.z);
+ u = (theta + 1.5 * M_PI) / (2 * M_PI);
+
+ // get v from ypos, trivial
+ v = pObject.y + 0.5f;
+ }
+
+ return {u, v};
+}
+
+glm::vec2 getUVCylinder(glm::vec4 pObject) {
+ float u, v;
+
+ // three cases -> top cap, bottom cap, cylindrical side
+ if (RayTracer::floatEquals(pObject.y, -.5f)) // 1) bottom cap
+ {
+ u = pObject.x + 0.5f;
+ v = pObject.z + 0.5f;
+ }
+ else if (RayTracer::floatEquals(pObject.y, .5f)) // 2) top cap
+ {
+ u = pObject.x + 0.5f;
+ v = 0.5f - pObject.z; // flip z
+ }
+ else // case 3) cylindrical face
+ {
+ // get u from theta zpos and xpos
+ float theta = glm::atan(pObject.x, pObject.z);
+ u = (theta + 1.5 * M_PI) / (2 * M_PI);
+
+ // get v from ypos and origin
+ v = pObject.y + 0.5f;
+ }
+
+ return {u, v};
+}
+
+glm::vec2 getUVMesh(glm::vec4 pObject) {
+ return glm::vec2(-1.f);
+}
+
+glm::vec2 getUVSphere(glm::vec4 pObject) {
+ float u = -1.f,v = -1.f;
+
+ // get u from theta between xpos and zpos
+ // get u from theta zpos and xpos
+ float theta = glm::atan(pObject.x, pObject.z);
+ u = (theta + 1.5 * M_PI) / (2 * M_PI);
+
+ // get v from phi from ypos and origin
+ float height = pObject.y/.5f;
+ height = std::clamp(height, -1.f, 1.f);
+ float phi = glm::asin(height);
+ v = phi / M_PI + .5f;
+
+ return {u, v};
+}
+
+glm::vec4 RayTracer::interpolateTexture(
+ glm::vec4 pObject,
+ const RenderShapeData &shape,
+ glm::vec4 illuminationToInterpolate)
+{
+ auto material = shape.primitive.material;
+ if (!material.textureMap.isUsed)
+ {
+ // return if no texture
+ return illuminationToInterpolate;
+ }
+
+ // determine uv based on shape
+ glm::vec2 uv;
+ switch (shape.primitive.type)
+ {
+ case PrimitiveType::PRIMITIVE_CUBE:
+ uv = getUVCube(pObject);
+ break;
+ case PrimitiveType::PRIMITIVE_CONE:
+ uv = getUVCone(pObject);
+ break;
+ case PrimitiveType::PRIMITIVE_CYLINDER:
+ uv = getUVCylinder(pObject);
+ break;
+ case PrimitiveType::PRIMITIVE_SPHERE:
+ uv = getUVSphere(pObject);
+ break;
+ case PrimitiveType::PRIMITIVE_MESH:
+ uv = getUVMesh(pObject);
+ break;
+ }
+
+ float u = uv.x, v = uv.y;
+ if (u == -1.f) {
+ return illuminationToInterpolate;
+ }
+
+ // map u,v to texture image
+ TextureData textureData = material.textureData;
+ if (textureData.data == nullptr) {
+ return illuminationToInterpolate;
+ }
+
+ int m = material.textureMap.repeatU;
+ int c = (int) glm::floor(u * m * textureData.width) % textureData.width;
+ if (c >= textureData.width) {
+ c = textureData.width - 1;
+ }
+ int n = material.textureMap.repeatV;
+ int r = (int) glm::floor((1-v) * n * textureData.height) % textureData.height;
+ if (r >= textureData.height) {
+ r = textureData.height - 1;
+ }
+ RGBA texture = textureData.data[r * textureData.width + c];
+
+ // interpolate the texture color with the illumination
+ float blend = shape.primitive.material.blend;
+ glm::vec4 blended = blend * (glm::vec4(texture.r, texture.g, texture.b, texture.a) / 255.f)
+ + (1.f - blend) * illuminationToInterpolate;
+ return blended;
+} \ No newline at end of file