aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Doan <daviddoan@Davids-MacBook-Pro-100.local>2023-12-08 15:04:43 -0500
committerDavid Doan <daviddoan@Davids-MacBook-Pro-100.local>2023-12-08 15:04:43 -0500
commit87be193a27a4d6ab583982e6d22eaccf154fff34 (patch)
tree4db10fc80f9077db4aab78ebd288b36ef4ca9368 /src
parenta44bcf18656062785c89e8fde25c232431b0d585 (diff)
parent480c22ce9b50caad259e254d0127e99294b4c6ab (diff)
merge
Diffstat (limited to 'src')
-rw-r--r--src/4dvecops/transform4d.cpp12
-rw-r--r--src/raytracer/raytracer.cpp48
-rw-r--r--src/utils/scenefilereader.cpp94
-rw-r--r--src/utils/sceneparser.cpp24
-rw-r--r--src/utils/sceneparser.h2
-rw-r--r--src/vec4ops/rotations4d.cpp (renamed from src/4dvecops/rotations4d.cpp)0
-rw-r--r--src/vec4ops/transform4d.cpp18
-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