Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assignment 3 Problem3 #15

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added build-with-BSP/torus knot with BSP.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added build-with-BSP/torus knot.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
87 changes: 83 additions & 4 deletions src/BSPNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
#pragma once

#include "types.h"
#include "BSPNode.h"
#include "BoundingBox.h"
#include "IPrim.h"
#include "ray.h"

class CBSPNode;
using ptr_bspnode_t = std::shared_ptr<CBSPNode>;
Expand Down Expand Up @@ -48,11 +52,86 @@ class CBSPNode
{
if (isLeaf()) {
// --- PUT YOUR CODE HERE ---
return false;
} else {
// --- PUT YOUR CODE HERE ---
return false;
for (auto EachPrim : m_vpPrims) {
//if (EachPrim->intersect(ray)) {
EachPrim->intersect(ray);
//return true;
//}
}
return (ray.hit && ray.t < t1 + Epsilon);
//return false;
}
else {
/*
Each branch node has two children, there are only 3 cases for sub - node intersections :
intersecting with the left child only
intersecting with the right child only
both
update ray.t
*/
// check for left and right child if anyone hits
/*if (Left()->intersect(ray, t0, t1)) { return true; };
if (Right()->intersect(ray, t0, t1)) { return true; };
return false;*/

//DistanceFromOriToSplitePlane and the value ray needs
double Distance = m_splitVal - ray.org[m_splitDim];
double RayValue = Distance / ray.dir[m_splitDim];
//if the ray direction of the splitdimension is negative meaning the distance is also opposite
/*if (ray.dir[m_splitDim] < 0) {
auto FrontNode = Right() ;
auto BackNode = Left();
}
else {
auto FrontNode = Left();
auto BackNode = Right();
}*/
auto FrontNode = (ray.dir[m_splitDim] < 0) ? Right() : Left();
auto BackNode = (ray.dir[m_splitDim] < 0) ? Left() : Right();

//consider three cases
if (t0 >= RayValue) {
//meaning the distance ray hit to the splite value is at the left/back
return BackNode->intersect(ray, t0, t1);
}
else if (t1 <= RayValue) {
return FrontNode->intersect(ray, t0, t1);
}
else {
// travese both children. front one first, back one last
if (FrontNode->intersect(ray, t0, RayValue))
return true;
return BackNode->intersect(ray, RayValue, t1);
}
}
//if (isLeaf()) {
// for (auto& pPrim : m_vpPrims)
// pPrim->intersect(ray);
// return (ray.hit && ray.t < t1 + Epsilon);
//}
//else {
// // distance from ray origin to the split plane of the current volume (may be negative)
// double d = (m_splitVal - ray.org[m_splitDim]) / ray.dir[m_splitDim];

// auto frontNode = (ray.dir[m_splitDim] < 0) ? Right() : Left();
// auto backNode = (ray.dir[m_splitDim] < 0) ? Left() : Right();

// if (d <= t0) {
// // t0..t1 is totally behind d, only go to back side
// return backNode->intersect(ray, t0, t1);
// }
// else if (d >= t1) {
// // t0..t1 is totally in front of d, only go to front side
// return frontNode->intersect(ray, t0, t1);
// }
// else {
// // travese both children. front one first, back one last
// if (frontNode->intersect(ray, t0, d))
// return true;

// return backNode->intersect(ray, d, t1);
// }
//}
}

/**
Expand Down
100 changes: 75 additions & 25 deletions src/BSPTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ namespace {
{
CBoundingBox res;
// --- PUT YOUR CODE HERE ---
for (auto EachPrim : vpPrims) {
res.extend(EachPrim->getBoundingBox());
}
return res;
}

// Returns the best dimension index for next split
Expand Down Expand Up @@ -40,6 +44,15 @@ class CBSPTree
* @param minPrimitives The minimum number of primitives in a leaf-node.
* This parameters should be alway above 1.
*/
/*
As soon as you have reached a maximum depth (e.g. 20),
or you have less then a minimum number of primitives (e.g. 3 or 4),
stop subdividing and generate a leaf node. Otherweise,
split your bounding box in the middle (in the maximum dimension),
sort your current primitives into two vector left and right,
and recursively call BuildTree with the respective bounding boxes and vector for left and right.
Start subdivision with a list of all primitives, the total scene bounds, and an initial recursion depth of 0.
*/
void build(const std::vector<ptr_prim_t>& vpPrims, size_t maxDepth = 20, size_t minPrimitives = 3) {
m_treeBoundingBox = calcBoundingBox(vpPrims);
m_maxDepth = maxDepth;
Expand All @@ -55,7 +68,15 @@ class CBSPTree
bool intersect(Ray& ray) const
{
// --- PUT YOUR CODE HERE ---
return false;

double t0 = 0;
double t1 = ray.t;
m_treeBoundingBox.clip(ray, t0, t1);
if (t1 < t0) return false;

return m_root->intersect(ray, t0, t1);

//return false;
}


Expand All @@ -69,33 +90,62 @@ class CBSPTree
*/
ptr_bspnode_t build(const CBoundingBox& box, const std::vector<ptr_prim_t>& vpPrims, size_t depth)
{
// Check for stoppong criteria
if (depth >= m_maxDepth || vpPrims.size() <= m_minPrimitives)
return std::make_shared<CBSPNode>(vpPrims); // => Create a leaf node and break recursion

// else -> prepare for creating a branch node
// First split the bounding volume into two halfes
int splitDim = MaxDim(box.getMaxPoint() - box.getMinPoint()); // Calculate split dimension as the dimension where the aabb is the widest
float splitVal = (box.getMinPoint()[splitDim] + box.getMaxPoint()[splitDim]) / 2; // Split the aabb exactly in two halfes
auto splitBoxes = box.split(splitDim, splitVal);
CBoundingBox& lBox = splitBoxes.first;
CBoundingBox& rBox = splitBoxes.second;

// Second order the primitives into new nounding boxes
std::vector<ptr_prim_t> lPrim;
std::vector<ptr_prim_t> rPrim;
for (auto pPrim : vpPrims) {
if (pPrim->getBoundingBox().overlaps(lBox))
lPrim.push_back(pPrim);
if (pPrim->getBoundingBox().overlaps(rBox))
rPrim.push_back(pPrim);
//first check if we need to build branch instead of returning single node
if (depth >= m_maxDepth || vpPrims.size() <= m_minPrimitives) {
return std::make_shared<CBSPNode>(vpPrims);
}
/*
we need to have splitDim and splitval
MaxDim for retuning best index
split value according to the target dimensions value
*/
std::cout << "size of vectors " << vpPrims.size() << std::endl;
int splitDim = MaxDim(box.getMaxPoint() - box.getMinPoint());
auto MaxPoint = box.getMaxPoint();
auto MinPoint = box.getMinPoint();
//float splitVal = (MaxPoint[splitDim] - MinPoint[splitDim]) / 2.0f;
float splitVal = (MaxPoint[splitDim] + MinPoint[splitDim]) / 2.0f;
/*std::cout << "Max Point " << MaxPoint << " Min Point" << MinPoint << std::endl;
std::cout << "splitdim " << splitDim << " splitval " << splitVal << std::endl;
*/

/*
build branch
CBSPNode(int splitDim, float splitVal, ptr_bspnode_t left, ptr_bspnode_t right)
: CBSPNode(std::nullopt, splitDim, splitVal, left, right)
{}
*/
std::pair<CBoundingBox, CBoundingBox> SplitPair = box.split(splitDim, splitVal);
auto LeftBox = SplitPair.first;
auto RightBox = SplitPair.second;
/*
sort current prims
check if leftbox and rightbox overlaps with each prims
*/
std::vector <ptr_prim_t> PrimsForLeft;
std::vector <ptr_prim_t> PrimsForRight;
for (auto EachPrim : vpPrims) {
//if overlap with left box then added to left box's prims, same to the right
/*if (LeftBox.overlaps(EachPrim->getBoundingBox())) {
PrimsForLeft.push_back(EachPrim);
}
if (LeftBox.overlaps(EachPrim->getBoundingBox())) {
PrimsForRight.push_back(EachPrim);
}*/
if (EachPrim->getBoundingBox().overlaps(LeftBox)) {
PrimsForLeft.push_back(EachPrim);
}
if (EachPrim->getBoundingBox().overlaps(RightBox)) {
PrimsForRight.push_back(EachPrim);
}

// Next build recursively 2 subtrees for both halfes
auto pLeft = build(lBox, lPrim, depth + 1);
auto pRight = build(rBox, rPrim, depth + 1);
}
//building branches to next right and left by boxes constructed above
auto NextLeft = build(LeftBox, PrimsForLeft, depth + 1);
auto NextRight = build(RightBox, PrimsForRight, depth + 1);
auto NextBranch = std::make_shared<CBSPNode>(splitDim, splitVal, NextLeft, NextRight);

return std::make_shared<CBSPNode>(splitDim, splitVal, pLeft, pRight);
return NextBranch;
}


Expand Down
60 changes: 58 additions & 2 deletions src/BoundingBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,85 @@ namespace {

void CBoundingBox::extend(const Vec3f& p)
{
// --- PUT YOUR CODE HERE ---
//extend untill it inncludes p
m_minPoint = Min3f(p, m_minPoint);
m_maxPoint = Max3f(p, m_maxPoint);
}

void CBoundingBox::extend(const CBoundingBox& box)
{
// --- PUT YOUR CODE HERE ---
Vec3f MaxPoint = box.getMaxPoint();
this->extend(MaxPoint);
Vec3f MinPoint = box.getMinPoint();
this->extend(MinPoint);

//the code above does not contain epsilon parts
//so i copied from the orgin and see if it works fine about the scene bound
/*extend(box.m_minPoint - Vec3f::all(Epsilon));
extend(box.m_maxPoint + Vec3f::all(Epsilon));*/

}

std::pair<CBoundingBox, CBoundingBox> CBoundingBox::split(int dim, float val) const
{
// --- PUT YOUR CODE HERE ---
auto res = std::make_pair(*this, *this);
//first one consider as the small value one, change the max value to the val
//second one consider as the bigger value one, channge the min value to the val
res.first.m_maxPoint.val[dim] = val;
res.second.m_minPoint.val[dim] = val;
return res;
}

bool CBoundingBox::overlaps(const CBoundingBox& box) const
{
// --- PUT YOUR CODE HERE ---
/*for (int i = 0; i < 3; i++) {
if (box.getMinPoint().val[i] > this->getMinPoint().val[i]) {
if (box.getMaxPoint().val[i] < this->getMaxPoint().val[i]) {
return true;;
}
}

}
return false;
*/

//mine doesnt work so i copied one from the library with Epsilon
for (int dim = 0; dim < 3; dim++) {
if (box.m_minPoint[dim] - Epsilon > m_maxPoint[dim]) return false;
if (box.m_maxPoint[dim] + Epsilon < m_minPoint[dim]) return false;
}
return true;

}

void CBoundingBox::clip(const Ray& ray, double& t0, double& t1) const
{
// --- PUT YOUR CODE HERE ---
//For clipping a ray with the bounding box of a scene,
//you can best use the slabs algorithm
for (int i = 0; i < 3; ++i) {
float den = ray.dir.val[i];
float a, b;
if (den != 0) {
if (den > 0.0f) {
a = (this->m_minPoint.val[i] - ray.org.val[i]) / den;
b = (this->m_maxPoint.val[i] - ray.org.val[i]) / den;
}

if (den < 0.0f) {
a = (this->m_maxPoint.val[i] - ray.org.val[i]) / den;
b = (this->m_minPoint.val[i] - ray.org.val[i]) / den;
}
if (a > t0) t0 = a;
if (b < t1) t1 = b;
if (t0 > t1) {
return;
}
}


}
}

14 changes: 12 additions & 2 deletions src/PrimPlane.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,18 @@ class CPrimPlane : public IPrim

virtual CBoundingBox getBoundingBox(void) const override
{
CBoundingBox bounds;
// --- PUT YOUR CODE HERE ---
Vec3f Minpoints = Vec3f::all(-INFINITY);
Vec3f Maxpoints = Vec3f::all(INFINITY);
//check which direction the plane faces
for (int i = 0; i < 3; i++) {
if (m_normal[i] == 1) {
/*Maxpoints[i] = 0;
Minpoints[i] = 0;*/
Maxpoints[i] = m_origin[i];
Minpoints[i] = m_origin[i];
}
}
CBoundingBox bounds(Maxpoints, Minpoints);
return bounds;
}

Expand Down
6 changes: 5 additions & 1 deletion src/PrimSphere.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,12 @@ class CPrimSphere : public IPrim

virtual CBoundingBox getBoundingBox(void) const override
{
CBoundingBox res;
Vec3f MinPoints = m_origin - Vec3f::all(m_radius);
Vec3f MaxPoints = m_origin + Vec3f::all(m_radius);

CBoundingBox res(MinPoints, MaxPoints);
// --- PUT YOUR CODE HERE ---

return res;
}

Expand Down
18 changes: 14 additions & 4 deletions src/PrimTriangle.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
// Triangle Geometrical Primitive class
// Written by Sergey Kosov in 2005 for Rendering Competition
#pragma once

#include "IPrim.h"
namespace {
inline Vec3f Min3f(const Vec3f a, const Vec3f b, const Vec3f c)
{
return Vec3f(MIN(a.val[0], b.val[0], c.val[0]), MIN(a.val[1], b.val[1], c.val[1]), MIN(a.val[2], b.val[2], c.val[2]));
}

inline Vec3f Max3f(const Vec3f a, const Vec3f b, const Vec3f c)
{
return Vec3f(MAX(a.val[0], b.val[0], c.val[0]), MAX(a.val[1], b.val[1], c.val[1]), MAX(a.val[2], b.val[2], c.val[2]));
}
}
// ================================ Triangle Primitive Class ================================
/**
* @brief Triangle Geometrical Primitive class
Expand Down Expand Up @@ -68,9 +77,10 @@ class CPrimTriangle : public IPrim

virtual CBoundingBox getBoundingBox(void) const override
{
CBoundingBox res;
// --- PUT YOUR CODE HERE ---
return res;
auto MinPoints = Min3f(m_a, m_b, m_c);
auto MaxPoints = Max3f(m_a, m_b, m_c);
CBoundingBox res(MinPoints, MaxPoints);
return res;
}


Expand Down
Loading