diff options
author | David Doan <daviddoan@Davids-MacBook-Pro-100.local> | 2023-12-08 15:04:43 -0500 |
---|---|---|
committer | David Doan <daviddoan@Davids-MacBook-Pro-100.local> | 2023-12-08 15:04:43 -0500 |
commit | 87be193a27a4d6ab583982e6d22eaccf154fff34 (patch) | |
tree | 4db10fc80f9077db4aab78ebd288b36ef4ca9368 /src | |
parent | a44bcf18656062785c89e8fde25c232431b0d585 (diff) | |
parent | 480c22ce9b50caad259e254d0127e99294b4c6ab (diff) |
merge
Diffstat (limited to 'src')
-rw-r--r-- | src/4dvecops/transform4d.cpp | 12 | ||||
-rw-r--r-- | src/raytracer/raytracer.cpp | 48 | ||||
-rw-r--r-- | src/utils/scenefilereader.cpp | 94 | ||||
-rw-r--r-- | src/utils/sceneparser.cpp | 24 | ||||
-rw-r--r-- | src/utils/sceneparser.h | 2 | ||||
-rw-r--r-- | src/vec4ops/rotations4d.cpp (renamed from src/4dvecops/rotations4d.cpp) | 0 | ||||
-rw-r--r-- | src/vec4ops/transform4d.cpp | 18 | ||||
-rw-r--r-- | src/vec4ops/vec4ops.cpp (renamed from src/4dvecops/vec4operations.cpp) | 9 | ||||
-rw-r--r-- | src/vec4ops/vec4ops.h (renamed from src/4dvecops/vec4ops.h) | 11 |
9 files changed, 136 insertions, 82 deletions
diff --git a/src/4dvecops/transform4d.cpp b/src/4dvecops/transform4d.cpp deleted file mode 100644 index 91f0d8c..0000000 --- a/src/4dvecops/transform4d.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "raytracer/raytracer.h" - -// this is used to transform a 4d point by a 4d matrix and its associated translation -// this is motivated by the fact that glm does not support 5d matrices, so we cannot define a mat5 to encapsulate both the rotation and translation in one matrix -// therefore, we break the 5d transformation into a 4d rotation and a 4d translation -glm::vec4 transformPoint4(glm::vec4 point4, glm::mat4 transformDirectionMatrix, glm::vec4 translationPointVector) { - // do the translation first - point4 -= translationPointVector; - // do the rotation and scaling - point4 = transformDirectionMatrix * point4; - return point4; -}
\ No newline at end of file diff --git a/src/raytracer/raytracer.cpp b/src/raytracer/raytracer.cpp index be31b8a..6b33150 100644 --- a/src/raytracer/raytracer.cpp +++ b/src/raytracer/raytracer.cpp @@ -7,7 +7,7 @@ #include "mainwindow.h" #include <QKeyEvent> #include <QTimerEvent> - +#include "vec4ops/vec4ops.h" // RayTracer::RayTracer(const Config &config) : m_config(config) {} RayTracer::RayTracer(QWidget *parent) : QWidget(parent) { @@ -23,13 +23,8 @@ RayTracer::RayTracer(QWidget *parent) : QWidget(parent) { } +// updated to use 4D void RayTracer::render(RGBA *imageData, const RayTraceScene &scene) { - if(m_enableParallelism) - { - renderParallel(imageData, scene); - return; - } - // naive rendering Camera camera = scene.getCamera(); float cameraDepth = 1.f; @@ -39,21 +34,30 @@ void RayTracer::render(RGBA *imageData, const RayTraceScene &scene) { for (int imageRow = 0; imageRow < scene.height(); imageRow++) { for (int imageCol = 0; imageCol < scene.width(); imageCol++) { - float xCameraSpace = viewplaneWidth * - (-.5f + (imageCol + .5f) / scene.width()); - float yCameraSpace = viewplaneHeight * - (-.5f + (imageRow + .5f) / scene.height()); - - glm::vec4 pixelDirCamera{xCameraSpace, -yCameraSpace, -cameraDepth, 0.f}; //w=0 for dir - glm::vec4 eyeCamera{0.f, 0.f, 0.f, 1.f}; // w=1.f for point - - // convert to world space - glm::vec4 pWorld = camera.getInverseViewMatrix() * eyeCamera; - glm::vec4 dWorld = glm::normalize(camera.getInverseViewMatrix() * pixelDirCamera); - - // cast ray! - glm::vec4 pixel = getPixelFromRay(pWorld, dWorld, scene); - imageData[imageRow * scene.width() + imageCol] = toRGBA(pixel); + // FIXME: for now, use height as depth + for (int imageDepth = 0; imageDepth < scene.height(); imageDepth++) { + // compute the ray + float x = (imageCol - scene.width()/2.f) * viewplaneWidth / scene.width(); + float y = (imageRow - scene.height()/2.f) * viewplaneHeight / scene.height(); + float z = (imageDepth - scene.height()/2.f) * viewplaneHeight / scene.height(); + float camera4dDepth = 1; + + glm::vec4 pCamera = + glm::vec4 pWorld = Vec4Ops::transformPoint4(camera.getvec4(x, y, z, camera4dDepth); + glm::vec4 dWorld = glm::vec4(0.f, 0.f, -1.f, 0.f); + + // get the pixel color + glm::vec4 pixelColor = getPixelFromRay(pWorld, dWorld, scene, 0); + + // set the pixel color + int index = imageRow * scene.width() + imageCol; + imageData[index] = RGBA{ + (std::uint8_t) (pixelColor.r * 255.f), + (std::uint8_t) (pixelColor.g * 255.f), + (std::uint8_t) (pixelColor.b * 255.f), + (std::uint8_t) (pixelColor.a * 255.f) + }; + } } } } diff --git a/src/utils/scenefilereader.cpp b/src/utils/scenefilereader.cpp index de5dce4..ad744a5 100644 --- a/src/utils/scenefilereader.cpp +++ b/src/utils/scenefilereader.cpp @@ -447,17 +447,23 @@ bool ScenefileReader::parseCameraData(const QJsonObject &cameradata) { // Parse the camera data if (cameradata["position"].isArray()) { QJsonArray position = cameradata["position"].toArray(); - if (position.size() != 3) { - std::cout << "cameraData position must have 3 elements" << std::endl; + if (position.size() != 3 && position.size() != 4) { + std::cout << "cameraData position must have 3-4 elements" << std::endl; return false; } - if (!position[0].isDouble() || !position[1].isDouble() || !position[2].isDouble()) { + if (!position[0].isDouble() || !position[1].isDouble() || !position[2].isDouble() || (position.size() == 4 && !position[3].isDouble())) { std::cout << "cameraData position must be a floating-point value" << std::endl; return false; } m_cameraData.pos.x = position[0].toDouble(); m_cameraData.pos.y = position[1].toDouble(); m_cameraData.pos.z = position[2].toDouble(); + if (position.size() == 4) { + m_cameraData.pos.w = position[3].toDouble(); + } + else { + m_cameraData.pos.w = 1.f; + } } else { std::cout << "cameraData position must be an array" << std::endl; @@ -466,17 +472,23 @@ bool ScenefileReader::parseCameraData(const QJsonObject &cameradata) { if (cameradata["up"].isArray()) { QJsonArray up = cameradata["up"].toArray(); - if (up.size() != 3) { - std::cout << "cameraData up must have 3 elements" << std::endl; + if (up.size() != 3 && up.size() != 4) { + std::cout << "cameraData up must have 3-4 elements" << std::endl; return false; } - if (!up[0].isDouble() || !up[1].isDouble() || !up[2].isDouble()) { + if (!up[0].isDouble() || !up[1].isDouble() || !up[2].isDouble() || (up.size() == 4 && !up[3].isDouble())) { std::cout << "cameraData up must be a floating-point value" << std::endl; return false; } m_cameraData.up.x = up[0].toDouble(); m_cameraData.up.y = up[1].toDouble(); m_cameraData.up.z = up[2].toDouble(); + if (up.size() == 4) { + m_cameraData.up.w = up[3].toDouble(); + } + else { + m_cameraData.up.w = 1.f; + } } else { std::cout << "cameraData up must be an array" << std::endl; @@ -516,17 +528,23 @@ bool ScenefileReader::parseCameraData(const QJsonObject &cameradata) { if (cameradata.contains("look")) { if (cameradata["look"].isArray()) { QJsonArray look = cameradata["look"].toArray(); - if (look.size() != 3) { - std::cout << "cameraData look must have 3 elements" << std::endl; + if (look.size() != 3 && look.size() != 4) { + std::cout << "cameraData look must have 3-4 elements" << std::endl; return false; } - if (!look[0].isDouble() || !look[1].isDouble() || !look[2].isDouble()) { + if (!look[0].isDouble() || !look[1].isDouble() || !look[2].isDouble() || (look.size() == 4 && !look[3].isDouble())) { std::cout << "cameraData look must be a floating-point value" << std::endl; return false; } m_cameraData.look.x = look[0].toDouble(); m_cameraData.look.y = look[1].toDouble(); m_cameraData.look.z = look[2].toDouble(); + if (look.size() == 4) { + m_cameraData.look.w = look[3].toDouble(); + } + else { + m_cameraData.look.w = 1.f; + } } else { std::cout << "cameraData look must be an array" << std::endl; @@ -536,17 +554,23 @@ bool ScenefileReader::parseCameraData(const QJsonObject &cameradata) { else if (cameradata.contains("focus")) { if (cameradata["focus"].isArray()) { QJsonArray focus = cameradata["focus"].toArray(); - if (focus.size() != 3) { - std::cout << "cameraData focus must have 3 elements" << std::endl; + if (focus.size() != 3 && focus.size() != 4) { + std::cout << "cameraData focus must have 3-4 elements" << std::endl; return false; } - if (!focus[0].isDouble() || !focus[1].isDouble() || !focus[2].isDouble()) { + if (!focus[0].isDouble() || !focus[1].isDouble() || !focus[2].isDouble() || (focus.size() == 4 && !focus[3].isDouble())) { std::cout << "cameraData focus must be a floating-point value" << std::endl; return false; } m_cameraData.look.x = focus[0].toDouble(); m_cameraData.look.y = focus[1].toDouble(); m_cameraData.look.z = focus[2].toDouble(); + if (focus.size() == 4) { + m_cameraData.look.w = focus[3].toDouble(); + } + else { + m_cameraData.look.w = 1.f; + } } else { std::cout << "cameraData focus must be an array" << std::endl; @@ -638,11 +662,11 @@ bool ScenefileReader::parseGroupData(const QJsonObject &object, SceneNode *node) } QJsonArray translateArray = object["translate"].toArray(); - if (translateArray.size() != 4) { - std::cout << "group translate must have 4 elements" << std::endl; + if (translateArray.size() != 4 && translateArray.size() != 3) { + std::cout << "group translate must have 3-4 elements" << std::endl; return false; } - if (!translateArray[0].isDouble() || !translateArray[1].isDouble() || !translateArray[2].isDouble() || !translateArray[3].isDouble()) { + if (!translateArray[0].isDouble() || !translateArray[1].isDouble() || !translateArray[2].isDouble() || (translateArray.size() == 4 && !translateArray[3].isDouble())) { std::cout << "group translate must contain floating-point values" << std::endl; return false; } @@ -652,7 +676,8 @@ bool ScenefileReader::parseGroupData(const QJsonObject &object, SceneNode *node) translation->translate.x = translateArray[0].toDouble(); translation->translate.y = translateArray[1].toDouble(); translation->translate.z = translateArray[2].toDouble(); - translation->translate.w = translateArray[3].toDouble(); + if (translateArray.size() == 4) + translation->translate.w = translateArray[3].toDouble(); node->transformations.push_back(translation); } @@ -665,11 +690,11 @@ bool ScenefileReader::parseGroupData(const QJsonObject &object, SceneNode *node) } QJsonArray rotateArray = object["rotate"].toArray(); - if (rotateArray.size() != 7) { - std::cout << "group rotate must have 7 elements" << std::endl; + if (rotateArray.size() != 7 && rotateArray.size() != 4) { + std::cout << "group rotate must have 4 or 7 elements" << std::endl; return false; } - if (!rotateArray[0].isDouble() || !rotateArray[1].isDouble() || !rotateArray[2].isDouble() || !rotateArray[3].isDouble() || !rotateArray[4].isDouble() || !rotateArray[5].isDouble() || !rotateArray[6].isDouble()) { + if (!rotateArray[0].isDouble() || !rotateArray[1].isDouble() || !rotateArray[2].isDouble() || !rotateArray[3].isDouble() || (rotateArray.size() == 7 && (!rotateArray[4].isDouble() || !rotateArray[5].isDouble() || !rotateArray[6].isDouble()))) { std::cout << "group rotate must contain floating-point values" << std::endl; return false; } @@ -679,10 +704,16 @@ bool ScenefileReader::parseGroupData(const QJsonObject &object, SceneNode *node) rotation->rotate3.x = rotateArray[0].toDouble(); rotation->rotate3.y = rotateArray[1].toDouble(); rotation->rotate3.z = rotateArray[2].toDouble(); - rotation->rotateW.x = rotateArray[3].toDouble(); - rotation->rotateW.y = rotateArray[4].toDouble(); - rotation->rotateW.z = rotateArray[5].toDouble(); - rotation->angle = rotateArray[6].toDouble() * M_PI / 180.f; + if (rotateArray.size() == 7) { + rotation->rotateW.x = rotateArray[4].toDouble(); + rotation->rotateW.y = rotateArray[5].toDouble(); + rotation->rotateW.z = rotateArray[6].toDouble(); + } else { + rotation->rotateW.x = 0; + rotation->rotateW.y = 0; + rotation->rotateW.z = 0; + } + rotation->angle = rotateArray[(rotateArray.size() == 7) ? 3 : 6].toDouble() * M_PI / 180.f; node->transformations.push_back(rotation); } @@ -695,11 +726,11 @@ bool ScenefileReader::parseGroupData(const QJsonObject &object, SceneNode *node) } QJsonArray scaleArray = object["scale"].toArray(); - if (scaleArray.size() != 4) { - std::cout << "group scale must have 4 elements" << std::endl; + if (scaleArray.size() != 4 && scaleArray.size() != 3) { + std::cout << "group scale must have 3-4 elements" << std::endl; return false; } - if (!scaleArray[0].isDouble() || !scaleArray[1].isDouble() || !scaleArray[2].isDouble() || !scaleArray[3].isDouble()) { + if (!scaleArray[0].isDouble() || !scaleArray[1].isDouble() || !scaleArray[2].isDouble() || (scaleArray.size() == 4 && !scaleArray[3].isDouble())) { std::cout << "group scale must contain floating-point values" << std::endl; return false; } @@ -709,7 +740,8 @@ bool ScenefileReader::parseGroupData(const QJsonObject &object, SceneNode *node) scale->scale.x = scaleArray[0].toDouble(); scale->scale.y = scaleArray[1].toDouble(); scale->scale.z = scaleArray[2].toDouble(); - scale->scale.w = scaleArray[3].toDouble(); + if (scaleArray.size() == 4) + scale->scale.w = scaleArray[3].toDouble(); node->transformations.push_back(scale); } @@ -722,8 +754,8 @@ bool ScenefileReader::parseGroupData(const QJsonObject &object, SceneNode *node) } QJsonArray matrixArray = object["matrix"].toArray(); - if (matrixArray.size() != 5) { - std::cout << "group matrix must be 5x5" << std::endl; + if (matrixArray.size() != 5 && matrixArray.size() != 4) { + std::cout << "group matrix must be 4x4 or 5x5" << std::endl; return false; } @@ -742,8 +774,8 @@ bool ScenefileReader::parseGroupData(const QJsonObject &object, SceneNode *node) } QJsonArray rowArray = row.toArray(); - if (rowArray.size() != 5) { - std::cout << "group matrix must be 5x5" << std::endl; + if (rowArray.size() != 5 && rowArray.size() != 4) { + std::cout << "group matrix must be 4x4 or 5x5" << std::endl; return false; } diff --git a/src/utils/sceneparser.cpp b/src/utils/sceneparser.cpp index 12f83bc..6d668ff 100644 --- a/src/utils/sceneparser.cpp +++ b/src/utils/sceneparser.cpp @@ -43,7 +43,7 @@ void initTree(SceneNode* currentNode, std::vector<RenderShapeData> *shapes, std: SceneParser::translate4(currentTranslation4d, t->translate); break; case TransformationType::TRANSFORMATION_SCALE: - SceneParser::scale4(currentTranslation4d, t->scale); + SceneParser::scale4(currentCTM, t->scale); break; case TransformationType::TRANSFORMATION_ROTATE: currentCTM *= SceneParser::getRotationMatrix4(t->angle, t->rotate3, t->rotateW); @@ -62,11 +62,11 @@ void initTree(SceneNode* currentNode, std::vector<RenderShapeData> *shapes, std: for(auto primitive : currentNode->primitives) { // primitive->material.textureData = loadTextureFromFile(QString::fromStdString(primitive->material.textureMap.filename)); RenderShapeData rsd = { - primitive: *primitive, - ctm: currentCTM, - translation4d: currentTranslation4d, - inverseCTM: glm::inverse(currentCTM), - inverseTranslation4d: -currentTranslation4d, + .primitive = *primitive, + .ctm = currentCTM, + .translation4d = currentTranslation4d, + .inverseCTM = glm::inverse(currentCTM), + .inverseTranslation4d = -currentTranslation4d, }; shapes->push_back(rsd); } @@ -176,11 +176,11 @@ void SceneParser::translate4( } void SceneParser::scale4( - glm::vec4 &v1, - glm::vec4 v2 + glm::mat4 &m, + glm::vec4 v ) { - v1.x *= v2.x; - v1.y *= v2.y; - v1.z *= v2.z; - v1.w *= v2.w; + m[0][0] *= v.x; + m[1][1] *= v.y; + m[2][2] *= v.z; + m[3][3] *= v.w; }
\ No newline at end of file diff --git a/src/utils/sceneparser.h b/src/utils/sceneparser.h index fa8a2ac..130156a 100644 --- a/src/utils/sceneparser.h +++ b/src/utils/sceneparser.h @@ -35,5 +35,5 @@ public: static void translate4(glm::vec4 &v1, glm::vec4 v2); - static void scale4(glm::vec4 &v1, glm::vec4 v2); + static void scale4(glm::mat4 &m, glm::vec4 v); }; diff --git a/src/4dvecops/rotations4d.cpp b/src/vec4ops/rotations4d.cpp index 4943c7f..4943c7f 100644 --- a/src/4dvecops/rotations4d.cpp +++ b/src/vec4ops/rotations4d.cpp diff --git a/src/vec4ops/transform4d.cpp b/src/vec4ops/transform4d.cpp new file mode 100644 index 0000000..5cc51f3 --- /dev/null +++ b/src/vec4ops/transform4d.cpp @@ -0,0 +1,18 @@ +#include "vec4ops.h" + +// this is used to transform a 4d point by a 4d matrix and its associated translation +// this is motivated by the fact that glm does not support 5d matrices, so we cannot define a mat5 to encapsulate both the rotation and translation in one matrix +// therefore, we break the 5d transformation into a 4d rotation and a 4d translation +glm::vec4 Vec4Ops::transformPoint4(glm::vec4 point4, glm::mat4 transformDirectionMatrix, glm::vec4 translationPointVector) { + // do the translation then direction + point4 = transformDirectionMatrix * point4; + point4 += translationPointVector; + return point4; +} + +glm::vec4 Vec4Ops::inverseTransformPoint4(glm::vec4 point4, glm::mat4 inverseTransformDirectionMatrix, glm::vec4 inverseTranslationPointVector) { + // do the direction then translation + point4 += inverseTranslationPointVector; + point4 = inverseTranslationPointVector * point4; + return point4; +}
\ No newline at end of file diff --git a/src/4dvecops/vec4operations.cpp b/src/vec4ops/vec4ops.cpp index 1ffe673..80cebaf 100644 --- a/src/4dvecops/vec4operations.cpp +++ b/src/vec4ops/vec4ops.cpp @@ -1,9 +1,10 @@ -#include "raytracer/raytracer.h" +#include <stdexcept> +#include "vec4ops.h" // vector operations on 4d vectors, // reference: https://hollasch.github.io/ray4/Four-Space_Visualization_of_4D_Objects.html#chapter5 -glm::vec4 cross4( +glm::vec4 Vec4Ops::cross4( glm::vec4 u, glm::vec4 v, glm::vec4 w) { @@ -23,13 +24,13 @@ glm::vec4 cross4( return result; } -glm::vec4 dot4( +glm::vec4 Vec4Ops::dot4( glm::vec4 u, glm::vec4 v) { return {u[0] * v[0], u[1] * v[1], u[2] * v[2], u[3] * v[3]}; } -glm::mat4 getViewMatrix4( +glm::mat4 Vec4Ops::getViewMatrix4( glm::vec4 fromPoint, glm::vec4 toPoint, glm::vec4 upVector, diff --git a/src/4dvecops/vec4ops.h b/src/vec4ops/vec4ops.h index 48d9139..d1c3ac8 100644 --- a/src/4dvecops/vec4ops.h +++ b/src/vec4ops/vec4ops.h @@ -21,6 +21,17 @@ public: static glm::mat4 getRotationMatrix4YW(float angleRadians); static glm::mat4 getRotationMatrix4ZW(float angleRadians); + + static glm::vec4 transformPoint4(glm::vec4 point4, glm::mat4 transformDirectionMatrix, glm::vec4 translationPointVector); + + static glm::vec4 inverseTransformPoint4(glm::vec4 point4, glm::mat4 inverseTransformDirectionMatrix, + glm::vec4 inverseTranslationPointVector); + + static glm::vec4 cross4(glm::vec4 u, glm::vec4 v, glm::vec4 w); + + static glm::vec4 dot4(glm::vec4 u, glm::vec4 v); + + static glm::mat4 getViewMatrix4(glm::vec4 fromPoint, glm::vec4 toPoint, glm::vec4 upVector, glm::vec4 lookVector); }; #endif //PROJECTS_RAY_VEC4OPS_H |