Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
290 lines (268 sloc) 6.99 KB
#include "TraceUnit.hpp"
TraceUnit::TraceUnit()
{
// nothing to create
}
TraceUnit::~TraceUnit()
{
delete m_BvhPtr;
m_BvhPtr = nullptr;
}
void TraceUnit::setScene(LWScene *sc){
m_ScenePtr = sc;
}
void TraceUnit::Init(Texture *imagePtr, int camWidth, int camHeight)
{
m_ImagePtr = imagePtr;
//setup Ray Map
updateRayMap();
//setup tiles
int tileSizeX = 128, tileSizeY = 128;
tiles = setupTiles(camWidth, camHeight, tileSizeX, tileSizeY);
//setup BVH
cout << "building QBVH tree...." << endl;
m_BvhPtr = new BVH();
m_BvhPtr->Build(m_ScenePtr);
cout << "QBVH tree built!" << endl;
}
void TraceUnit::clearImage(int camWidth, int camHeight)
{
if (!(m_ImagePtr == nullptr))
{
delete m_ImagePtr;
m_ImagePtr = nullptr;
}
m_ImagePtr = new Texture("Render result", camWidth, camHeight);
m_ImagePtr->setInterpolationMode(INTPOL_PIXELS);
m_ImagePtr->setQuadraticFittingMode(FIT_STRETCHXY);
}
void TraceUnit::updateRayMap()
{
rayMap = m_ScenePtr->cam.getRayMap(p_MaxBounces);
}
//returns true if a sample is completed, otherwise false to allow avoiding freezing
bool TraceUnit::renderNextChunk()
{
vector<thread> tileThreads;
int availableThreads = thread::hardware_concurrency();
for (int i = 0; i < availableThreads; i++)
{
if (m_currentTile < (signed int)tiles.size())
tileThreads.push_back(std::thread(&TraceUnit::renderTile, this, m_currentTile));
m_currentTile++;
}
int activeThreads = tileThreads.size();
while (activeThreads>0)
{
for (size_t i = 0; i < tileThreads.size(); i++)
{
if (tileThreads[i].joinable())
{
tileThreads[i].join();
activeThreads--;
}
}
}
if (m_currentTile >= (signed int)tiles.size())
{
m_currentTile = 0;
m_samplesRendered++;
return true;
}
else return false;
}
void TraceUnit::renderTile(int tileIndex)
{
tile thisTile = tiles[tileIndex];
for (int x = thisTile.posX; x < thisTile.posX + thisTile.scaleX; x++)
{
for (int y = thisTile.posY; y < thisTile.posY + thisTile.scaleY; y++)
{
colRGB current = m_ImagePtr->getRGB(x, y);
float t;
colRGB next = ((current*(float)m_samplesRendered) + raycast(rayMap[x][y], t)) / (float)(m_samplesRendered + 1);
m_ImagePtr->setRGB(next, x, y);
}
}
}
colRGB TraceUnit::raycast(Ray ray, float &t)
{
DifferentialGeometry closest;
closest.i.hit = false;
bool hasHit=false;
float minT = ray.isPrimary ? 1.0f : 0.0001f;
for (size_t i = 0; i < m_BvhPtr->unsortedIndices.size(); i++)
{
shapeNodeIdx idxStruct = m_BvhPtr->unsortedIndices[i];
m_ScenePtr->shapes[idxStruct.shapeIdx]->getIntersection(idxStruct.subIdx1, idxStruct.subIdx2, ray, closest, minT, m_BackfaceCulling);
if (closest.i.hit)
{
hasHit = true;
}
}
traverseBVH(ray, m_BvhPtr->outerNode, closest, hasHit, minT);
closest.dir = ray.ln.dir;
closest.bounces = ray.bounces;
//shade closest intersection
if (hasHit == false)
{
closest.mat = materialPointer::BACKGROUND_MATERIAL;
}
else
{
t = closest.i.t / closest.dir.Length();
}
return shade(closest);
}
void TraceUnit::traverseBVH(Ray &ray, bvhNode *node, DifferentialGeometry &dg, bool &hasHit, float minT)
{
//intersect with volume and check if its closer than the already found distance
bool aabbHit = false;
if (hasHit)
{
aabbHit = node->bounds.intersect(ray, dg.i.t);
}
else
{
aabbHit = node->bounds.intersect(ray);
}
if (aabbHit)
{
//solve this nodes assigned shapes intersections
for (size_t i = 0; i < node->Indices.size(); i++)
{
shapeNodeIdx idxStruct = node->Indices[i];
m_ScenePtr->shapes[idxStruct.shapeIdx]->getIntersection(idxStruct.subIdx1, idxStruct.subIdx2, ray, dg, minT, m_BackfaceCulling);
if (dg.i.hit)
{
hasHit = true;
}
}
//traverse hierachy for existing child nodes
if (!(node->Child0 == nullptr))
{
traverseBVH(ray, node->Child0, dg, hasHit, minT);
}
if (!(node->Child1 == nullptr))
{
traverseBVH(ray, node->Child1, dg, hasHit, minT);
}
if (!(node->Child2 == nullptr))
{
traverseBVH(ray, node->Child2, dg, hasHit, minT);
}
if (!(node->Child3 == nullptr))
{
traverseBVH(ray, node->Child3, dg, hasHit, minT);
}
}
}
bool TraceUnit::shadowRay(line ln)
{
bool hasHit = false;
for (size_t i = 0; i < m_BvhPtr->unsortedIndices.size(); i++)
{
shapeNodeIdx idxStruct = m_BvhPtr->unsortedIndices[i];
if (m_ScenePtr->shapes[idxStruct.shapeIdx]->castsShadow())
{
if (m_ScenePtr->shapes[idxStruct.shapeIdx]->shadowIntersection(idxStruct.subIdx1, idxStruct.subIdx2, ln))
hasHit = true;
}
}
if (!hasHit)
{
Ray ray;
ray.ln = ln;
ray.precalculate();
shadowTraverseBVH(ray, m_BvhPtr->outerNode, hasHit);
}
return hasHit;
}
void TraceUnit::shadowTraverseBVH(Ray &ray, bvhNode *node, bool &hasHit)
{
if (node->bounds.intersect(ray))
{
for (size_t i = 0; i < node->Indices.size(); i++)
{
shapeNodeIdx idxStruct = node->Indices[i];
if (m_ScenePtr->shapes[idxStruct.shapeIdx]->castsShadow())
{
if (m_ScenePtr->shapes[idxStruct.shapeIdx]->shadowIntersection(idxStruct.subIdx1, idxStruct.subIdx2, ray.ln))
hasHit = true;
}
}
//traverse hierachy for existing child nodes
if (!(node->Child0 == nullptr) && !hasHit)
{
shadowTraverseBVH(ray, node->Child0, hasHit);
}
if (!(node->Child1 == nullptr) && !hasHit)
{
shadowTraverseBVH(ray, node->Child1, hasHit);
}
if (!(node->Child2 == nullptr) && !hasHit)
{
shadowTraverseBVH(ray, node->Child2, hasHit);
}
if (!(node->Child3 == nullptr) && !hasHit)
{
shadowTraverseBVH(ray, node->Child3, hasHit);
}
}
}
colRGB TraceUnit::shade(DifferentialGeometry dg)
{
shader *mat = m_ScenePtr->materials[dg.mat];
return mat->shade(dg, m_ScenePtr, this);
}
float TraceUnit::getLightIntensity(light *L, point3 P)
{
float ret = 0.f;
if (L->getType() == LightType::LIGHT_POINT)
{
if (!shadowRay(line(P, (L->getPosition() - P).Norm(0.00001f))))
{
ret = 1.f;
}
}
if (L->getType() == LightType::LIGHT_AREA)
{
float sampleDifferential = (1.0f / (float)((AreaLight*)L)->samplesSq);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0, sampleDifferential);
for (float x = 0.f; x < 1.f; x += sampleDifferential)
{
for (float y = 0.f; y < 1.f; y += sampleDifferential)
{
point3 pos = ((AreaLight*)L)->pos + (x + (float)dis(gen))*((AreaLight*)L)->dir1 + (y + (float)dis(gen))*((AreaLight*)L)->dir2;
float hitValue = 1.f / (float)(((AreaLight*)L)->samplesSq*((AreaLight*)L)->samplesSq);
if (!shadowRay(line(P, (pos - P).Norm(0.00001f))))
{
ret += hitValue;
}
}
}
}
ret *= L->getIntensity();
return ret;
}
vector<tile> TraceUnit::setupTiles(int camWidth, int camHeight, int tileSizeX, int tileSizeY)
{
vector<tile> tiles;
for (int x = 0; x < camWidth; x += tileSizeX)
{
for (int y = 0; y < camHeight; y += tileSizeY)
{
tile T;
T.posX = x;
T.posY = y;
if (x + tileSizeX > camWidth)T.scaleX = camWidth - x;
else T.scaleX = tileSizeX;
if (y + tileSizeY > camHeight)T.scaleY = camHeight - y;
else T.scaleY = tileSizeY;
tiles.push_back(T);
}
}
return tiles;
}