diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/accelerate/myqtconcurrent.cpp | 29 | ||||
-rw-r--r-- | src/illuminate/shadow.cpp | 4 | ||||
-rw-r--r-- | src/main.cpp | 172 | ||||
-rw-r--r-- | src/mainwindow.cpp | 384 | ||||
-rw-r--r-- | src/mainwindow.h | 66 | ||||
-rw-r--r-- | src/raytracer/raytracer.cpp | 62 | ||||
-rw-r--r-- | src/raytracer/raytracer.h | 26 | ||||
-rw-r--r-- | src/settings.cpp | 3 | ||||
-rw-r--r-- | src/settings.h | 21 | ||||
-rw-r--r-- | src/utils/aspectratiowidget/aspectratiowidget.hpp | 66 | ||||
-rw-r--r-- | src/utils/sceneparser.cpp | 2 |
11 files changed, 737 insertions, 98 deletions
diff --git a/src/accelerate/myqtconcurrent.cpp b/src/accelerate/myqtconcurrent.cpp index 1dff0e0..aeb160b 100644 --- a/src/accelerate/myqtconcurrent.cpp +++ b/src/accelerate/myqtconcurrent.cpp @@ -1,13 +1,13 @@ #include <QList> #include <QtConcurrent> -#include "raytracer/raytracer.h" +#include "../raytracer/raytracer.h" struct pixelRoutineArgs { glm::vec4 pCamera; glm::vec4 dCamera; const RayTraceScene &scene; - RayTracer rt; + RayTracer *rt; }; static RGBA pixelRoutine(pixelRoutineArgs args); @@ -28,12 +28,13 @@ void RayTracer::renderParallel(RGBA *imageData, const RayTraceScene &scene) 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 - l.append({ - eyeCamera, // eye - pixelDirCamera, // direction - scene, - *this - }); + pixelRoutineArgs args{ + eyeCamera, + pixelDirCamera, + scene, + this + }; + l.append(args); } } @@ -44,7 +45,7 @@ void RayTracer::renderParallel(RGBA *imageData, const RayTraceScene &scene) imageData[index++] = p; } - if (m_config.enableAntiAliasing) + if (m_enableAntiAliasing) { filterBlur(imageData, scene.width(), scene.height()); } @@ -63,18 +64,18 @@ RGBA pixelRoutine(pixelRoutineArgs args) glm::vec4 pWorld = inv * eyeCamera; glm::vec4 dWorld = glm::normalize(inv * pixelDirCamera); - if (rt.m_config.enableDepthOfField) + if (rt->m_enableDepthOfField) { // if we're doing depth of field, we need to shoot multiple rays, see camera.cpp - return RayTracer::toRGBA(rt.secondaryRays(pWorld, dWorld, scene)); + return RayTracer::toRGBA(rt->secondaryRays(pWorld, dWorld, scene)); } - if (rt.m_config.enableSuperSample) + if (rt->m_enableSuperSample) { // if we're doing super sampling, we need to shoot multiple rays, see raytracer.cpp - return rt.superSample(eyeCamera, pixelDirCamera, scene); + return rt->superSample(eyeCamera, pixelDirCamera, scene); } // shoot ray! - RGBA pixel = RayTracer::toRGBA(rt.getPixelFromRay(pWorld, dWorld, scene, 0)); + RGBA pixel = RayTracer::toRGBA(rt->getPixelFromRay(pWorld, dWorld, scene, 0)); return pixel; } diff --git a/src/illuminate/shadow.cpp b/src/illuminate/shadow.cpp index 99e2b29..efb52a7 100644 --- a/src/illuminate/shadow.cpp +++ b/src/illuminate/shadow.cpp @@ -11,7 +11,7 @@ bool RayTracer::isShadowed( directionFromIntersectionToLight = glm::normalize(directionFromIntersectionToLight); // acceleration causes "bad jaggies" so we disable it for now - if (m_config.enableAcceleration) + if (m_enableAcceleration) { RenderShapeData shapeData; auto pBias = intersectionWorld + .001f * directionFromIntersectionToLight; @@ -55,4 +55,4 @@ bool RayTracer::isShadowed( } return false; -}
\ No newline at end of file +} diff --git a/src/main.cpp b/src/main.cpp index 8cb00b8..29828d8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,85 +2,111 @@ #include <QCommandLineParser> #include <QImage> #include <QtCore> +#include <QApplication> +#include <QScreen> +#include <iostream> +#include <QSettings> +#include <QSurfaceFormat> #include <iostream> #include "utils/sceneparser.h" #include "raytracer/raytracer.h" #include "raytracer/raytracescene.h" +#include "mainwindow.h" + int main(int argc, char *argv[]) { - QCoreApplication a(argc, argv); - - QCommandLineParser parser; - parser.addHelpOption(); - parser.addPositionalArgument("config", "Path of the config file."); - parser.process(a); - - auto positionalArgs = parser.positionalArguments(); - if (positionalArgs.size() != 1) { - std::cerr << "Not enough arguments. Please provide a path to a config file (.ini) as a command-line argument." << std::endl; - a.exit(1); - return 1; - } - - QSettings settings( positionalArgs[0], QSettings::IniFormat ); - QString iScenePath = settings.value("IO/scene").toString(); - QString oImagePath = settings.value("IO/output").toString(); - - RenderData metaData; - bool success = SceneParser::parse(iScenePath.toStdString(), metaData); - - if (!success) { - std::cerr << "Error loading scene: \"" << iScenePath.toStdString() << "\"" << std::endl; - a.exit(1); - return 1; - } - - // Raytracing-relevant code starts here - - int width = settings.value("Canvas/width").toInt(); - int height = settings.value("Canvas/height").toInt(); - - // Extracting data pointer from Qt's image API - QImage image = QImage(width, height, QImage::Format_RGBX8888); - image.fill(Qt::black); - RGBA *data = reinterpret_cast<RGBA *>(image.bits()); - - // Setting up the raytracer - Config rtConfig{}; - rtConfig.enableShadow = settings.value("Feature/shadows").toBool(); - rtConfig.enableReflection = settings.value("Feature/reflect").toBool(); - rtConfig.enableRefraction = settings.value("Feature/refract").toBool(); - rtConfig.enableTextureMap = settings.value("Feature/texture").toBool(); - rtConfig.enableTextureFilter = settings.value("Feature/texture-filter").toBool(); - rtConfig.enableParallelism = settings.value("Feature/parallel").toBool(); - rtConfig.enableSuperSample = settings.value("Feature/super-sample").toBool(); - rtConfig.enableAntiAliasing = settings.value("Feature/post-process").toBool(); - rtConfig.enableAcceleration = settings.value("Feature/acceleration").toBool(); - rtConfig.enableDepthOfField = settings.value("Feature/depthoffield").toBool(); - rtConfig.maxRecursiveDepth = settings.value("Settings/maximum-recursive-depth").toInt(); - rtConfig.onlyRenderNormals = settings.value("Settings/only-render-normals").toBool(); - - RayTracer raytracer{ rtConfig }; - - RayTraceScene rtScene{ width, height, metaData }; - - // Note that we're passing `data` as a pointer (to its first element) - // Recall from Lab 1 that you can access its elements like this: `data[i]` - raytracer.render(data, rtScene); - - // Saving the image - success = image.save(oImagePath); - if (!success) { - success = image.save(oImagePath, "PNG"); - } - if (success) { - std::cout << "Saved rendered image to \"" << oImagePath.toStdString() << "\"" << std::endl; - } else { - std::cerr << "Error: failed to save image to \"" << oImagePath.toStdString() << "\"" << std::endl; - } - - a.exit(); - return 0; + // QCoreApplication a(argc, argv); + + // QCommandLineParser parser; + // parser.addHelpOption(); + // parser.addPositionalArgument("config", "Path of the config file."); + // parser.process(a); + + // auto positionalArgs = parser.positionalArguments(); + // if (positionalArgs.size() != 1) { + // std::cerr << "Not enough arguments. Please provide a path to a config file (.ini) as a command-line argument." << std::endl; + // a.exit(1); + // return 1; + // } + + // QSettings settings( positionalArgs[0], QSettings::IniFormat ); + // QString iScenePath = settings.value("IO/scene").toString(); + // QString oImagePath = settings.value("IO/output").toString(); + + // RenderData metaData; + // bool success = SceneParser::parse(iScenePath.toStdString(), metaData); + + // if (!success) { + // std::cerr << "Error loading scene: \"" << iScenePath.toStdString() << "\"" << std::endl; + // a.exit(1); + // return 1; + // } + + // // Raytracing-relevant code starts here + + // int width = settings.value("Canvas/width").toInt(); + // int height = settings.value("Canvas/height").toInt(); + + // // Extracting data pointer from Qt's image API + // QImage image = QImage(width, height, QImage::Format_RGBX8888); + // image.fill(Qt::black); + // RGBA *data = reinterpret_cast<RGBA *>(image.bits()); + + // // Setting up the raytracer + // Config rtConfig{}; + // rtConfig.enableShadow = settings.value("Feature/shadows").toBool(); + // rtConfig.enableReflection = settings.value("Feature/reflect").toBool(); + // rtConfig.enableRefraction = settings.value("Feature/refract").toBool(); + // rtConfig.enableTextureMap = settings.value("Feature/texture").toBool(); + // rtConfig.enableTextureFilter = settings.value("Feature/texture-filter").toBool(); + // rtConfig.enableParallelism = settings.value("Feature/parallel").toBool(); + // rtConfig.enableSuperSample = settings.value("Feature/super-sample").toBool(); + // rtConfig.enableAntiAliasing = settings.value("Feature/post-process").toBool(); + // rtConfig.enableAcceleration = settings.value("Feature/acceleration").toBool(); + // rtConfig.enableDepthOfField = settings.value("Feature/depthoffield").toBool(); + // rtConfig.maxRecursiveDepth = settings.value("Settings/maximum-recursive-depth").toInt(); + // rtConfig.onlyRenderNormals = settings.value("Settings/only-render-normals").toBool(); + + // RayTracer raytracer{ rtConfig }; + + // RayTraceScene rtScene{ width, height, metaData }; + + // // Note that we're passing `data` as a pointer (to its first element) + // // Recall from Lab 1 that you can access its elements like this: `data[i]` + // raytracer.render(data, rtScene); + + // // Saving the image + // success = image.save(oImagePath); + // if (!success) { + // success = image.save(oImagePath, "PNG"); + // } + // if (success) { + // std::cout << "Saved rendered image to \"" << oImagePath.toStdString() << "\"" << std::endl; + // } else { + // std::cerr << "Error: failed to save image to \"" << oImagePath.toStdString() << "\"" << std::endl; + // } + + // a.exit(); + // return 0; + + QApplication a(argc, argv); + + QCoreApplication::setApplicationName("The All Americans 4D Raytracer"); + QCoreApplication::setOrganizationName("CS 1230/2230"); + // QCoreApplication::setApplicationVersion(QT_VERSION_STR); + + QSurfaceFormat fmt; + fmt.setVersion(4, 1); + fmt.setProfile(QSurfaceFormat::CoreProfile); + QSurfaceFormat::setDefaultFormat(fmt); + + MainWindow w; + w.initialize(); + w.resize(800, 600); + w.show(); + int return_val = a.exec(); + w.finish(); + return return_val; } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp new file mode 100644 index 0000000..45c1c2c --- /dev/null +++ b/src/mainwindow.cpp @@ -0,0 +1,384 @@ +#include "mainwindow.h" +#include "settings.h" + +#include <QHBoxLayout> +#include <QVBoxLayout> +#include <QFileDialog> +#include <QSettings> +#include <QLabel> +#include <QGroupBox> +#include <iostream> + +void MainWindow::initialize() { + // create RayTracer + rayTracer = new RayTracer(this); + imageLabel = new QLabel(this); + // aspectRatioWidget = new AspectRatioWidget(this); + // aspectRatioWidget->setAspectWidget(imageLabel, 3.f/4.f); + QHBoxLayout *hLayout = new QHBoxLayout; // horizontal alignment + QVBoxLayout *vLayout = new QVBoxLayout(); // vertical alignment + vLayout->setAlignment(Qt::AlignTop); + hLayout->addLayout(vLayout); + hLayout->addWidget(imageLabel, 1); + this->setLayout(hLayout); + + QFont font; + font.setPointSize(12); + font.setBold(true); + QLabel *xy_label = new QLabel(); // XY label + xy_label->setText("XY value:"); + xy_label->setFont(font); + QLabel *xz_label = new QLabel(); // XZ label + xz_label->setText("XZ value:"); + xz_label->setFont(font); + QLabel *xw_label = new QLabel(); // XW label + xw_label->setText("XW value:"); + xw_label->setFont(font); + QLabel *yz_label = new QLabel(); // YZ label + yz_label->setText("YZ value:"); + yz_label->setFont(font); + QLabel *yw_label = new QLabel(); // YW label + yw_label->setText("YW value:"); + yw_label->setFont(font); + QLabel *zw_label = new QLabel(); // ZW label + zw_label->setText("ZW value:"); + zw_label->setFont(font); + + + // Create file uploader for scene file + uploadFile = new QPushButton(); + uploadFile->setText(QStringLiteral("Upload Scene File")); + + saveImage = new QPushButton(); + saveImage->setText(QStringLiteral("Save image")); + + QGroupBox *xyLayout = new QGroupBox(); // horizonal w slider alignment + QHBoxLayout *lxy = new QHBoxLayout(); + + xySlider = new QSlider(Qt::Orientation::Horizontal); // XY value slider + xySlider->setTickInterval(1); + xySlider->setMinimum(-1000); + xySlider->setMaximum(1000); + xySlider->setValue(0); + + xyBox = new QDoubleSpinBox(); + xyBox->setMinimum(-10.0f); + xyBox->setMaximum(10.f); + xyBox->setSingleStep(0.1f); + xyBox->setValue(0.f); + + lxy->addWidget(xySlider); + lxy->addWidget(xyBox); + xyLayout->setLayout(lxy); + + // XZ Slider + QGroupBox *xzLayout = new QGroupBox(); // horizonal w slider alignment + QHBoxLayout *lxz = new QHBoxLayout(); + + xzSlider = new QSlider(Qt::Orientation::Horizontal); // XY value slider + xzSlider->setTickInterval(1); + xzSlider->setMinimum(-1000); + xzSlider->setMaximum(1000); + xzSlider->setValue(0); + + xzBox = new QDoubleSpinBox(); + xzBox->setMinimum(-10.0f); + xzBox->setMaximum(10.f); + xzBox->setSingleStep(0.1f); + xzBox->setValue(0.f); + + lxz->addWidget(xzSlider); + lxz->addWidget(xzBox); + xzLayout->setLayout(lxz); + + // XW Slider + QGroupBox *xwLayout = new QGroupBox(); // horizonal w slider alignment + QHBoxLayout *lxw = new QHBoxLayout(); + + xwSlider = new QSlider(Qt::Orientation::Horizontal); // XY value slider + xwSlider->setTickInterval(1); + xwSlider->setMinimum(-1000); + xwSlider->setMaximum(1000); + xwSlider->setValue(0); + + xwBox = new QDoubleSpinBox(); + xwBox->setMinimum(-10.0f); + xwBox->setMaximum(10.f); + xwBox->setSingleStep(0.1f); + xwBox->setValue(0.f); + + lxw->addWidget(xwSlider); + lxw->addWidget(xwBox); + xwLayout->setLayout(lxw); + + // YZ Slider + QGroupBox *yzLayout = new QGroupBox(); // horizonal w slider alignment + QHBoxLayout *lyz = new QHBoxLayout(); + + yzSlider = new QSlider(Qt::Orientation::Horizontal); // XY value slider + yzSlider->setTickInterval(1); + yzSlider->setMinimum(-1000); + yzSlider->setMaximum(1000); + yzSlider->setValue(0); + + yzBox = new QDoubleSpinBox(); + yzBox->setMinimum(-10.0f); + yzBox->setMaximum(10.f); + yzBox->setSingleStep(0.1f); + yzBox->setValue(0.f); + + lyz->addWidget(yzSlider); + lyz->addWidget(yzBox); + yzLayout->setLayout(lyz); + + // YW Slider + QGroupBox *ywLayout = new QGroupBox(); // horizonal w slider alignment + QHBoxLayout *lyw = new QHBoxLayout(); + + ywSlider = new QSlider(Qt::Orientation::Horizontal); // XY value slider + ywSlider->setTickInterval(1); + ywSlider->setMinimum(-1000); + ywSlider->setMaximum(1000); + ywSlider->setValue(0); + + ywBox = new QDoubleSpinBox(); + ywBox->setMinimum(-10.0f); + ywBox->setMaximum(10.f); + ywBox->setSingleStep(0.1f); + ywBox->setValue(100.f); + + lyw->addWidget(ywSlider); + lyw->addWidget(ywBox); + ywLayout->setLayout(lyw); + + // ZW Slider + QGroupBox *zwLayout = new QGroupBox(); // horizonal w slider alignment + QHBoxLayout *lzw = new QHBoxLayout(); + + zwSlider = new QSlider(Qt::Orientation::Horizontal); // XY value slider + zwSlider->setTickInterval(1); + zwSlider->setMinimum(-1000); + zwSlider->setMaximum(1000); + zwSlider->setValue(0); + + zwBox = new QDoubleSpinBox(); + zwBox->setMinimum(-10.0f); + zwBox->setMaximum(10.f); + zwBox->setSingleStep(0.1f); + zwBox->setValue(100.f); + + lzw->addWidget(zwSlider); + lzw->addWidget(zwBox); + zwLayout->setLayout(lzw); + + vLayout->addWidget(uploadFile); + vLayout->addWidget(saveImage); + vLayout->addWidget(xy_label); + vLayout->addWidget(xyLayout); + vLayout->addWidget(xz_label); + vLayout->addWidget(xzLayout); + vLayout->addWidget(xw_label); + vLayout->addWidget(xwLayout); + vLayout->addWidget(yz_label); + vLayout->addWidget(yzLayout); + vLayout->addWidget(yw_label); + vLayout->addWidget(ywLayout); + vLayout->addWidget(zw_label); + vLayout->addWidget(zwLayout); + + connectUIElements(); + + onValChangexyBox(0.0f); + onValChangexzBox(0.0f); + onValChangexwBox(0.0f); + onValChangeyzBox(0.0f); + onValChangeywBox(0.0f); + onValChangezwBox(0.0f); +} + +void MainWindow::finish() { +// realtime->finish(); +// delete(realtime); +} + +void MainWindow::connectUIElements() { + connectUploadFile(); + connectSaveImage(); + connectxy(); + connectxz(); + connectxw(); + connectyz(); + connectyw(); + connectzw(); +} + +void MainWindow::connectUploadFile() { + connect(uploadFile, &QPushButton::clicked, this, &MainWindow::onUploadFile); +} + +void MainWindow::connectSaveImage() { + connect(saveImage, &QPushButton::clicked, this, &MainWindow::onSaveImage); +} + +void MainWindow::connectxy() { + connect(xySlider, &QSlider::valueChanged, this, &MainWindow::onValChangexySlider); + connect(xyBox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), + this, &MainWindow::onValChangexyBox); +} + +void MainWindow::connectxz() { + connect(xzSlider, &QSlider::valueChanged, this, &MainWindow::onValChangexzSlider); + connect(xzBox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), + this, &MainWindow::onValChangexzBox); +} + +void MainWindow::connectxw() { + connect(xwSlider, &QSlider::valueChanged, this, &MainWindow::onValChangexwSlider); + connect(xwBox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), + this, &MainWindow::onValChangexwBox); +} + +void MainWindow::connectyz() { + connect(yzSlider, &QSlider::valueChanged, this, &MainWindow::onValChangeyzSlider); + connect(yzBox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), + this, &MainWindow::onValChangeyzBox); +} + +void MainWindow::connectyw() { + connect(ywSlider, &QSlider::valueChanged, this, &MainWindow::onValChangeywSlider); + connect(ywBox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), + this, &MainWindow::onValChangeywBox); +} + +void MainWindow::connectzw() { + connect(zwSlider, &QSlider::valueChanged, this, &MainWindow::onValChangezwSlider); + connect(zwBox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), + this, &MainWindow::onValChangezwBox); +} + +void MainWindow::onUploadFile() { + // Get abs path of scene file + QString configFilePath = QFileDialog::getOpenFileName(this, tr("Upload File"), + QDir::currentPath() + .append(QDir::separator()) + .append("scenefiles") + .append(QDir::separator()) + .append("lights-camera") + .append(QDir::separator()) + .append("required"), tr("Scene Files (*.json)")); + if (configFilePath.isNull()) { + std::cout << "Failed to load null scenefile." << std::endl; + return; + } + + settings.sceneFilePath = configFilePath.toStdString(); + + std::cout << "Loaded scenefile: \"" << configFilePath.toStdString() << "\"." << std::endl; + + rayTracer->sceneChanged(imageLabel); +} + +void MainWindow::onSaveImage() { + if (settings.sceneFilePath.empty()) { + std::cout << "No scene file loaded." << std::endl; + return; + } + std::string sceneName = settings.sceneFilePath.substr(0, settings.sceneFilePath.find_last_of(".")); + sceneName = sceneName.substr(sceneName.find_last_of("/")+1); + QString filePath = QFileDialog::getSaveFileName(this, tr("Save Image"), + QDir::currentPath() + .append(QDir::separator()) + .append("student_outputs") + .append(QDir::separator()) + .append("lights-camera") + .append(QDir::separator()) + .append("required") + .append(QDir::separator()) + .append(sceneName), tr("Image Files (*.png)")); + std::cout << "Saving image to: \"" << filePath.toStdString() << "\"." << std::endl; +// realtime->saveViewportImage(filePath.toStdString()); +} + +void MainWindow::onValChangexySlider(int newValue) { + //wSlider->setValue(newValue); + xyBox->setValue(newValue/100.f); + settings.xy = xyBox->value(); + rayTracer->settingsChanged(imageLabel); +} + +void MainWindow::onValChangexyBox(double newValue) { + xySlider->setValue(int(newValue*100.f)); + //wBox->setValue(newValue); + settings.xy = xyBox->value(); + rayTracer->settingsChanged(imageLabel); +} + +void MainWindow::onValChangexzSlider(int newValue) { + //wSlider->setValue(newValue); + xzBox->setValue(newValue/100.f); + settings.xz = xzBox->value(); + rayTracer->settingsChanged(imageLabel); +} + +void MainWindow::onValChangexzBox(double newValue) { + xzSlider->setValue(int(newValue*100.f)); + //wBox->setValue(newValue); + settings.xz = xzBox->value(); + rayTracer->settingsChanged(imageLabel); +} + +void MainWindow::onValChangexwSlider(int newValue) { + //wSlider->setValue(newValue); + xwBox->setValue(newValue/100.f); + settings.xw = xwBox->value(); + rayTracer->settingsChanged(imageLabel); +} + +void MainWindow::onValChangexwBox(double newValue) { + xwSlider->setValue(int(newValue*100.f)); + //wBox->setValue(newValue); + settings.xw = xwBox->value(); + rayTracer->settingsChanged(imageLabel); +} + +void MainWindow::onValChangeyzSlider(int newValue) { + //wSlider->setValue(newValue); + yzBox->setValue(newValue/100.f); + settings.yz = yzBox->value(); + rayTracer->settingsChanged(imageLabel); +} + +void MainWindow::onValChangeyzBox(double newValue) { + yzSlider->setValue(int(newValue*100.f)); + //wBox->setValue(newValue); + settings.yz = yzBox->value(); + rayTracer->settingsChanged(imageLabel); +} + +void MainWindow::onValChangeywSlider(int newValue) { + //wSlider->setValue(newValue); + ywBox->setValue(newValue/100.f); + settings.yw = ywBox->value(); + rayTracer->settingsChanged(imageLabel); +} + +void MainWindow::onValChangeywBox(double newValue) { + ywSlider->setValue(int(newValue*100.f)); + //wBox->setValue(newValue); + settings.yw = ywBox->value(); + rayTracer->settingsChanged(imageLabel); +} + +void MainWindow::onValChangezwSlider(int newValue) { + //wSlider->setValue(newValue); + zwBox->setValue(newValue/100.f); + settings.zw = zwBox->value(); + rayTracer->settingsChanged(imageLabel); +} + +void MainWindow::onValChangezwBox(double newValue) { + zwSlider->setValue(int(newValue*100.f)); + //wBox->setValue(newValue); + settings.zw = zwBox->value(); + rayTracer->settingsChanged(imageLabel); +} diff --git a/src/mainwindow.h b/src/mainwindow.h new file mode 100644 index 0000000..6c98ae2 --- /dev/null +++ b/src/mainwindow.h @@ -0,0 +1,66 @@ +#pragma once + +#include <QMainWindow> +#include <QCheckBox> +#include <QSlider> +#include <QSpinBox> +#include <QDoubleSpinBox> +#include <QPushButton> +#include <QLabel> +// #include "realtime.h" +#include "raytracer/raytracer.h" +#include "utils/aspectratiowidget/aspectratiowidget.hpp" + +class MainWindow : public QWidget +{ + Q_OBJECT + +public: + void initialize(); + void finish(); + QLabel *imageLabel; + +private: + void connectUIElements(); + void connectUploadFile(); + void connectSaveImage(); + void connectxy(); + void connectxz(); + void connectxw(); + void connectyz(); + void connectyw(); + void connectzw(); + + RayTracer *rayTracer; + AspectRatioWidget *aspectRatioWidget; + QPushButton *uploadFile; + QPushButton *saveImage; + QSlider *xySlider; + QDoubleSpinBox *xyBox; + QSlider *xzSlider; + QDoubleSpinBox *xzBox; + QSlider *xwSlider; + QDoubleSpinBox *xwBox; + QSlider *yzSlider; + QDoubleSpinBox *yzBox; + QSlider *ywSlider; + QDoubleSpinBox *ywBox; + QSlider *zwSlider; + QDoubleSpinBox *zwBox; + +private slots: + void onUploadFile(); + void onSaveImage(); + void onValChangexySlider(int newValue); + void onValChangexyBox(double newValue); + void onValChangexzSlider(int newValue); + void onValChangexzBox(double newValue); + void onValChangexwSlider(int newValue); + void onValChangexwBox(double newValue); + void onValChangeyzSlider(int newValue); + void onValChangeyzBox(double newValue); + void onValChangeywSlider(int newValue); + void onValChangeywBox(double newValue); + void onValChangezwSlider(int newValue); + void onValChangezwBox(double newValue); +}; diff --git a/src/raytracer/raytracer.cpp b/src/raytracer/raytracer.cpp index c3466cf..93f5225 100644 --- a/src/raytracer/raytracer.cpp +++ b/src/raytracer/raytracer.cpp @@ -3,16 +3,19 @@ #include <iostream> #include "raytracer.h" #include "raytracescene.h" +#include "settings.h" +#include "mainwindow.h" //struct Ray { // glm::vec3 p; // glm::vec3 d; //}; -RayTracer::RayTracer(const Config &config) : m_config(config) {} +// RayTracer::RayTracer(const Config &config) : m_config(config) {} +RayTracer::RayTracer(QWidget *parent) : QWidget(parent) {} void RayTracer::render(RGBA *imageData, const RayTraceScene &scene) { - if(m_config.enableParallelism) + if(m_enableParallelism) { renderParallel(imageData, scene); return; @@ -53,7 +56,7 @@ glm::vec4 RayTracer::getPixelFromRay( const RayTraceScene &scene, int depth) { - if (depth > m_config.maxRecursiveDepth) + if (depth > m_maxRecursiveDepth) { return glm::vec4(0.f); } @@ -63,7 +66,7 @@ glm::vec4 RayTracer::getPixelFromRay( glm::vec4 closestIntersectionWorld; RenderShapeData intersectedShape; - if (m_config.enableAcceleration) + if (m_enableAcceleration) { float tWorld = traverseBVH(pWorld, dWorld, intersectedShape, scene.m_bvh); if (tWorld == FINF) @@ -147,4 +150,53 @@ glm::vec4 RayTracer::secondaryRays(glm::vec4 pWorld, glm::vec4 dWorld, RayTraceS } return illumination / (float) TIMES; -}
\ No newline at end of file +} + +void RayTracer::sceneChanged(QLabel* imageLabel) { + // RenderData metaData; + + bool success = SceneParser::parse(settings.sceneFilePath, m_metaData); + + if (!success) { + std::cerr << "Error loading scene: \"" << settings.sceneFilePath << "\"" << std::endl; + return; + } + + int width = 576; + int height = 432; + + // render the scene + QImage image = QImage(width, height, QImage::Format_RGBX8888); + image.fill(Qt::black); + RGBA *data = reinterpret_cast<RGBA *>(image.bits()); + + + + // RayTracer raytracer{ rtConfig }; + + RayTraceScene rtScene{ width, height, m_metaData }; + this->render(data, rtScene); + + QImage flippedImage = image.mirrored(false, false); + // make the image larger + flippedImage = flippedImage.scaled(2*width, 2*height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + imageLabel->setPixmap(QPixmap::fromImage(flippedImage)); +} + +void RayTracer::settingsChanged(QLabel* imageLabel) { + int width = 576; + int height = 432; + + QImage image = QImage(width, height, QImage::Format_RGBX8888); + image.fill(Qt::black); + RGBA *data = reinterpret_cast<RGBA *>(image.bits()); + + RayTraceScene rtScene{ width, height, m_metaData }; + this->render(data, rtScene); + + QImage flippedImage = image.mirrored(false, false); + flippedImage = flippedImage.scaled(2*width, 2*height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + imageLabel->setPixmap(QPixmap::fromImage(flippedImage)); +} + + diff --git a/src/raytracer/raytracer.h b/src/raytracer/raytracer.h index 6a16cdf..5fbe907 100644 --- a/src/raytracer/raytracer.h +++ b/src/raytracer/raytracer.h @@ -6,6 +6,8 @@ #include "raytracescene.h" #include "accelerate/kdtree.h" #include "accelerate/bvh.h" +#include <QOpenGLWidget> +#include <QLabel> // A forward declaration for the RaytraceScene class @@ -31,12 +33,12 @@ struct Config { bool onlyRenderNormals = false; }; -class RayTracer +class RayTracer : public QWidget { public: // constructor for the config - explicit RayTracer(const Config &config); - const Config &m_config; + RayTracer(QWidget *parent = nullptr); +// const Config &m_config; // Renders the scene synchronously. // The ray-tracer will render the scene and fill imageData in-place. @@ -136,5 +138,23 @@ public: // depth of field glm::vec4 secondaryRays(glm::vec4 pWorld, glm::vec4 dWorld, RayTraceScene &scene); + + // Old m_config + + bool m_enableShadow = true; + bool m_enableReflection = true; + bool m_enableRefraction = false; + bool m_enableTextureMap = false; + bool m_enableAcceleration = true; + bool m_enableParallelism = true; + int m_maxRecursiveDepth = 4; + bool m_enableAntiAliasing = false; + bool m_enableDepthOfField = false; + bool m_enableSuperSample = false; + + void sceneChanged(QLabel* imageLabel); + void settingsChanged(QLabel* imageLabel); + RenderData m_metaData; + }; diff --git a/src/settings.cpp b/src/settings.cpp new file mode 100644 index 0000000..3d3e980 --- /dev/null +++ b/src/settings.cpp @@ -0,0 +1,3 @@ +#include "settings.h" + +Settings settings; diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 0000000..ba383b3 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,21 @@ +#ifndef SETTINGS_H +#define SETTINGS_H + +#include <string> + +struct Settings { + std::string sceneFilePath; + float xy = 0.f; + float z = 0.f; + float xz = 0.f; + float yz = 0.f; + float xw = 0.f; + float yw = 0.f; + float zw = 0.f; +}; + + +// The global Settings object, will be initialized by MainWindow +extern Settings settings; + +#endif // SETTINGS_H diff --git a/src/utils/aspectratiowidget/aspectratiowidget.hpp b/src/utils/aspectratiowidget/aspectratiowidget.hpp new file mode 100644 index 0000000..9a5f81c --- /dev/null +++ b/src/utils/aspectratiowidget/aspectratiowidget.hpp @@ -0,0 +1,66 @@ +#ifndef ASPECTRATIOWIDGET_HPP +#define ASPECTRATIOWIDGET_HPP + +#include <QWidget> +#include <QBoxLayout> + +class AspectRatioWidget : public QWidget +{ + Q_OBJECT +public: + AspectRatioWidget(QWidget *parent = 0) : QWidget(parent) + { + m_layout = new QHBoxLayout(); + m_layout->setSpacing(0); + m_layout->setContentsMargins(0, 0, 0, 0); + setLayout(m_layout); + } + + // the widget we want to keep the ratio + void setAspectWidget(QWidget* widget, const double ratio = 1.0) { + m_aspect_widget = widget; + m_layout->addWidget(widget); + m_ratio = ratio; + } + void setRatio(const double ratio) { + m_ratio = ratio; + applyAspectRatio(); + } + +protected: + void resizeEvent(QResizeEvent *event) { + (void)event; + applyAspectRatio(); + } + +public slots: + void applyAspectRatio() { + int w = this->width(); + int h = this->height(); + double aspect = static_cast<double>(h)/static_cast<double>(w); + + if(aspect < m_ratio) // parent is too wide + { + int target_width = static_cast<int>(static_cast<double>(h)/m_ratio); + m_aspect_widget->setMaximumWidth(target_width); + m_aspect_widget->setMaximumHeight(h); + + } + else // parent is too high + { + int target_heigth = static_cast<int>(static_cast<double>(w)*m_ratio); + m_aspect_widget->setMaximumHeight(target_heigth); + m_aspect_widget->setMaximumWidth(w); + } + } + +private: + QHBoxLayout* m_layout; + + QWidget* m_aspect_widget; + + double m_ratio; +}; + +#endif // ASPECTRATIOWINDOW_H + diff --git a/src/utils/sceneparser.cpp b/src/utils/sceneparser.cpp index 74c605a..99c4f55 100644 --- a/src/utils/sceneparser.cpp +++ b/src/utils/sceneparser.cpp @@ -58,7 +58,7 @@ void initTree(SceneNode* currentNode, std::vector<RenderShapeData> *shapes, std: for(auto primitive : currentNode->primitives) { - primitive->material.textureData = loadTextureFromFile(QString::fromStdString(primitive->material.textureMap.filename)); + // primitive->material.textureData = loadTextureFromFile(QString::fromStdString(primitive->material.textureMap.filename)); RenderShapeData rsd = {*primitive, currentCTM, glm::inverse(currentCTM)}; shapes->push_back(rsd); } |