rendering-in-cgi/Assignments/Assignment2/Application2.cpp

846 lines
31 KiB
C++

#include "Application2.h"
#include "embree4/rtcore_common.h"
#include "helper.hpp"
#include "lights/light.h"
#include "math/vec2.h"
#include "math/vec3fa.h"
#include "random_sampler.hpp"
#include "ray.hpp"
#include <cmath>
#include <cstdio>
#define EPS 0.0001f
void Application2::initScene() {
Data_Constructor(&data, 1, 8);
/* select scene here */
gnomeScene();
// horseScene();
// heterogenousScene();
}
void Application2::gnomeScene() {
FileName file = workingDir + FileName("Framework/scenes/gnome/garden_gnome.obj");
/* set default camera */
camera.from = Vec3fa(-0.07894, -0.414116, -1.40016);
camera.to = camera.from + Vec3fa(0.0, 0.0, 1.0);
speed = 0.005;
Ref<SceneGraph::GroupNode> sceneGraph = loadOBJ(file, false).cast<SceneGraph::GroupNode>();
auto light = new SceneGraph::LightNodeImpl<SceneGraph::PointLight>(
SceneGraph::PointLight(Vec3fa(-0.1, -0.065, 0.21), Vec3fa(10, 10, 10)));
sceneGraph->add(light);
Ref<SceneGraph::GroupNode> flattened_scene = SceneGraph::flatten(sceneGraph, SceneGraph::INSTANCING_NONE);
Scene* scene = new Scene;
scene->add(flattened_scene);
sceneGraph = nullptr;
flattened_scene = nullptr;
auto renderScene = new RenderScene(g_device, scene);
g_render_scene = renderScene;
data.scene = renderScene;
data.densityGrid = nullptr;
data.tempGrid = nullptr;
scene = nullptr;
}
void Application2::horseScene() {
FileName file = workingDir + FileName("Framework/scenes/horse/horse.obj");
/* set default camera */
camera.from = Vec3fa(0, 0.0, -0.5);
camera.to = Vec3fa(0.0, 0.0, 0.0);
// speed = 0.005;
Ref<SceneGraph::GroupNode> sceneGraph = loadOBJ(file, false).cast<SceneGraph::GroupNode>();
auto light = new SceneGraph::QuadLightMesh(Vec3fa(-0.25, 0.5, 0), Vec3fa(0.25, 0.5, 0.5),
Vec3fa(0.25, 0.5, 0),
Vec3fa(-0.25, 0.5, 0.5), Vec3fa(5, 5, 5));
sceneGraph->add(light);
Ref<SceneGraph::GroupNode> flattened_scene = SceneGraph::flatten(sceneGraph, SceneGraph::INSTANCING_NONE);
Scene* scene = new Scene;
scene->add(flattened_scene);
sceneGraph = nullptr;
flattened_scene = nullptr;
auto renderScene = new RenderScene(g_device, scene);
g_render_scene = renderScene;
data.scene = renderScene;
data.densityGrid = nullptr;
data.tempGrid = nullptr;
scene = nullptr;
}
void Application2::heterogenousScene() {
FileName file = workingDir + FileName("Framework/scenes/box.obj");
/* set default camera */
camera.from = Vec3fa(0, 0.0, -2);
camera.to = Vec3fa(0.0, 0.0, 0.0);
Ref<SceneGraph::GroupNode> sceneGraph = loadOBJ(file, false).cast<SceneGraph::GroupNode>();
auto light = new SceneGraph::QuadLightMesh(Vec3fa(-1, 2, -1), Vec3fa(1, 2, 1),
Vec3fa(1, 2, -1),
Vec3fa(-1, 2, 1), Vec3fa(1, 1, 1));
sceneGraph->add(light);
Ref<SceneGraph::GroupNode> flattened_scene = SceneGraph::flatten(sceneGraph, SceneGraph::INSTANCING_NONE);
Scene* scene = new Scene;
scene->add(flattened_scene);
sceneGraph = nullptr;
flattened_scene = nullptr;
auto renderScene = new RenderScene(g_device, scene);
Vec3fa worldPos(-0.5, -0.5, -0.5); // Corner of the Cornell Box
Vec3fa scale(1, 1, 1); // Calculated scale
FileName filegrid = workingDir + FileName("Framework/scenes/fire/density.vol");
data.densityGrid = new Grid(filegrid.c_str(), Vec3ia(76, 184, 80), worldPos, scale);
FileName filegrid2 = workingDir + FileName("Framework/scenes/fire/temperature.vol");
data.tempGrid = new Grid(filegrid2.c_str(), Vec3ia(76, 184, 80), worldPos, scale);
g_render_scene = renderScene;
data.scene = renderScene;
scene = nullptr;
}
Vec3fa ACESFilm(Vec3fa x, float exposure) {
const Vec3fa a = Vec3fa(2.51f);
const Vec3fa b = Vec3fa(0.03f);
const Vec3fa c = Vec3fa(2.43f);
const Vec3fa d = Vec3fa(0.59f);
const Vec3fa e = Vec3fa(0.14f);
x *= exposure;
return (x * (a * x + b)) / (x * (c * x + d) + e);
}
Sample createSample(Ray &ray) {
Sample sample;
Vec3fa Ns = normalize(ray.Ng);
sample.P = ray.org + ray.tfar * ray.dir;
sample.Ng = ray.Ng;
sample.Ns = Ns;
sample.Ng = face_forward(ray.dir, normalize(sample.Ng));
sample.Ns = face_forward(ray.dir, normalize(sample.Ns));
return sample;
}
// Function that selects implementation at runtime
Vec3fa Application2::renderPixel(float x, float y, const ISPCCamera& camera, RayStats& stats, RandomSamplerWrapper& sampler) {
if (selected == 0) {
return renderPixelOrig(x, y, camera, stats, sampler);
} else if (selected == 1) {
return renderPixelHomogeneous(x, y, camera, stats, sampler);
} else if (selected == 2) {
return renderPixelHeterogeneous(x, y, camera, stats, sampler);
} else if (selected == 3) {
return renderPixelHeterogeneousNEE(x, y, camera, stats, sampler);
} else {
return Vec3fa(0.0f);
}
}
Vec3fa Application2::renderPixelHeterogeneousNEE(float x, float y, const ISPCCamera& camera, RayStats& stats, RandomSamplerWrapper& sampler) {
Vec3fa L = Vec3fa(0.0f);
Vec3fa Lw = Vec3fa(1.0f);
bool in_volume = false;
float max_density = 1.32 * density; // tested
/* initialize ray */
Ray ray(Vec3fa(camera.xfm.p), Vec3fa(normalize(x * camera.xfm.l.vx + y * camera.xfm.l.vy + camera.xfm.l.vz)), 0.0f,
inf);
for (int i = 0; i < ray_depth; i++) {
/* intersect ray with scene */
RTCIntersectArguments iargs;
rtcInitIntersectArguments(&iargs);
iargs.feature_mask = RTC_FEATURE_FLAG_TRIANGLE;
rtcIntersect1(data.g_scene, RTCRayHit_(ray), &iargs);
RayStats_addRay(stats);
const Vec3fa wo = neg(ray.dir);
float t;
if (!in_volume | (density == 0)) {
t = inf;
} else {
// printf("%f\n", density);
t = - std::log(1.0 - sampler.get1D()) / max_density;
}
if (t > 0.0 && t < ray.tfar) {
if (ray.geomID == RTC_INVALID_GEOMETRY_ID) {
// printf("here(%f,%f,%f)\n", ray.org.x, ray.org.y, ray.org.z);
break;
}
float r = sampler.get1D();
Vec3fa p = ray.org + t * ray.dir;
// printf("%f\t%f\t(%f,%f,%f)\n", t, ray.tfar, p.x, p.y, p.z);
float s = data.densityGrid->sampleW(p);
// if (s != -1.0) {
// printf("(%f,%f,%f)\tt: %f\ttfar: %f\tr: %f\t%f\ts: %f\t%f\tp:%f\n",p.x, p.y, p.z, t, ray.tfar, r, r * max_density, s, s * density, (s * density) / max_density);
// }
// if (s > 0.5) {
// printf("(%f,%f,%f)\tr: %f\t%f\ts: %f\t%f\tp:%f\n",p.x, p.y, p.z , r, r * max_density, s, s * density, (s * density) / max_density);
// }
if (sampler.get1D() * max_density < s * density) {
// NEE
int id = (int)(sampler.get1D() * data.scene->lights.size());
if (id == data.scene->lights.size())
id = data.scene->lights.size() - 1;
const Light* l = data.scene->lights.at(id);
Sample sample;
sample.P = ray.org + t * ray.dir;
sample.Ng = ray.dir;
sample.Ns = ray.dir;
Light_SampleRes ls = Lights_sample(l, sample, sampler.get2D());
/* initialize shadow ray */
Ray shadow(sample.P, ls.dir, EPS, ls.dist - EPS, 0.0f);
/* trace shadow ray */
RTCOccludedArguments sargs;
rtcInitOccludedArguments(&sargs);
sargs.feature_mask = RTC_FEATURE_FLAG_TRIANGLE;
rtcOccluded1(data.g_scene, RTCRay_(shadow), &sargs);
RayStats_addShadowRay(stats);
if (shadow.tfar >= 0.0) {
float nee_T = 1.0;
float nee_t = 0.0;
while (1) {
float r = sampler.get1D();
nee_t -= std::log(1 - r) / max_density;
if (shadow.tfar >= nee_t) {
break;
}
nee_T *= 1 - data.densityGrid->sampleW(shadow.org + nee_t * shadow.dir) / max_density;
}
float scatter = phase(scattering_parameter, -dot(-ray.dir,shadow.dir));
/* add light contribution if not occluded (NEE) */
L += Lw * nee_T * scatter * (1.0 - absorbtion) * ls.weight / data.scene->lights.size();
}
float pdf;
Vec3fa o = sample_phase_function(-ray.dir, scattering_parameter, sampler.get2D(), pdf);
float temp = data.tempGrid->sampleW(p); // Sample density from the grid
// float temp = 20;
float redWavelength = 700;
float greenWavelength = 530;
float blueWavelength = 470;
Vec3fa emissive = Vec3fa(0.0, 0.0, 0.0);
if (temp != -1.0f && temp > 0.001) {
temp *= tempearture_multiplier;
emissive = Vec3f(blackbody_radiance_normalized(redWavelength, temp),
blackbody_radiance_normalized(greenWavelength, temp),
blackbody_radiance_normalized(blueWavelength, temp));
}
L += Lw * absorbtion * emissive;
Lw *= 1.0 - absorbtion;
ray = Ray(ray.org + t * ray.dir,o,0.0,inf);
} else {
// printf("volume(%f,%f,%f), t: %f, tfar: %f\n", ray.org.x, ray.org.y, ray.org.z, t, ray.tfar);
ray = Ray(ray.org + t * ray.dir, ray.dir, 0.0, inf);
i--;
}
} else if (ray.geomID != RTC_INVALID_GEOMETRY_ID) {
Sample sample = createSample(ray);
int matId = data.scene->geometries.at(ray.geomID)->materialID;
unsigned lightID = data.scene->geometries.at(ray.geomID)->lightID;
if (lightID != unsigned(-1)) {
if (i == 0) {
const Light* l = data.scene->lights[lightID];
Light_EvalRes evalRes = Lights_eval(l, sample, -wo);
L += Lw * evalRes.value;
}
break;
}
/* calculate BRDF */
BRDF brdf;
std::vector<Material *> material_array = data.scene->materials;
Material__preprocess(material_array, matId, brdf, wo, sample);
if (brdf.name == "default") {
// printf("surface\n");
in_volume = !in_volume;
// in_volume = dot(normalize(ray.Ng), ray.dir) < 0;
ray = Ray(ray.org + ray.tfar * ray.dir, ray.dir, EPS, inf);
i--;
}
}
}
return L;
}
Vec3fa Application2::renderPixelHeterogeneous(float x, float y, const ISPCCamera& camera, RayStats& stats, RandomSamplerWrapper& sampler) {
Vec3fa L = Vec3fa(0.0f);
Vec3fa Lw = Vec3fa(1.0f);
bool in_volume = false;
float max_density = 1.32 * density; // tested
/* initialize ray */
Ray ray(Vec3fa(camera.xfm.p), Vec3fa(normalize(x * camera.xfm.l.vx + y * camera.xfm.l.vy + camera.xfm.l.vz)), 0.0f,
inf);
for (int i = 0; i < ray_depth; i++) {
/* intersect ray with scene */
RTCIntersectArguments iargs;
rtcInitIntersectArguments(&iargs);
iargs.feature_mask = RTC_FEATURE_FLAG_TRIANGLE;
rtcIntersect1(data.g_scene, RTCRayHit_(ray), &iargs);
RayStats_addRay(stats);
const Vec3fa wo = neg(ray.dir);
float t;
if (!in_volume | (density == 0)) {
t = inf;
} else {
// printf("%f\n", density);
t = - std::log(1.0 - sampler.get1D()) / max_density;
}
if (t > 0.0 && t < ray.tfar) {
if (ray.geomID == RTC_INVALID_GEOMETRY_ID) {
// printf("here(%f,%f,%f)\n", ray.org.x, ray.org.y, ray.org.z);
break;
// return Vec3fa(0.0, 0.0, 10.0);
}
float r = sampler.get1D();
Vec3fa p = ray.org + t * ray.dir;
// printf("%f\t%f\t(%f,%f,%f)\n", t, ray.tfar, p.x, p.y, p.z);
float s = data.densityGrid->sampleW(p);
// if (s != -1.0) {
// printf("(%f,%f,%f)\tt: %f\ttfar: %f\tr: %f\t%f\ts: %f\t%f\tp:%f\n",p.x, p.y, p.z, t, ray.tfar, r, r * max_density, s, s * density, (s * density) / max_density);
// }
// if (s > 0.5) {
// printf("(%f,%f,%f)\tr: %f\t%f\ts: %f\t%f\tp:%f\n",p.x, p.y, p.z , r, r * max_density, s, s * density, (s * density) / max_density);
// }
if (sampler.get1D() * max_density < s * density) {
float pdf;
Vec3fa o = sample_phase_function(-ray.dir, scattering_parameter, sampler.get2D(), pdf);
float temp = data.tempGrid->sampleW(p); // Sample density from the grid
// float temp = 20;
float redWavelength = 700;
float greenWavelength = 530;
float blueWavelength = 470;
Vec3fa emissive = Vec3fa(0.0, 0.0, 0.0);
if (temp != -1.0f && temp > 0.001) {
temp *= tempearture_multiplier;
emissive = Vec3f(blackbody_radiance_normalized(redWavelength, temp),
blackbody_radiance_normalized(greenWavelength, temp),
blackbody_radiance_normalized(blueWavelength, temp));
}
L += Lw * absorbtion * emissive;
Lw *= 1.0 - absorbtion;
ray = Ray(ray.org + t * ray.dir,o,0.0,inf);
} else {
// printf("volume(%f,%f,%f), t: %f, tfar: %f\n", ray.org.x, ray.org.y, ray.org.z, t, ray.tfar);
ray = Ray(ray.org + t * ray.dir, ray.dir, 0.0, inf);
i--;
}
} else if (ray.geomID != RTC_INVALID_GEOMETRY_ID) {
Sample sample = createSample(ray);
int matId = data.scene->geometries.at(ray.geomID)->materialID;
unsigned lightID = data.scene->geometries.at(ray.geomID)->lightID;
if (lightID != unsigned(-1)) {
const Light* l = data.scene->lights[lightID];
Light_EvalRes evalRes = Lights_eval(l, sample, -wo);
L += Lw * evalRes.value;
break;
}
/* calculate BRDF */
BRDF brdf;
std::vector<Material *> material_array = data.scene->materials;
Material__preprocess(material_array, matId, brdf, wo, sample);
if (brdf.name == "default") {
// printf("surface\n");
in_volume = !in_volume;
// in_volume = dot(normalize(ray.Ng), ray.dir) < 0;
ray = Ray(ray.org + ray.tfar * ray.dir, ray.dir, EPS, inf);
i--;
}
}
}
return L;
}
Vec3fa Application2::renderPixelHomogeneous(float x, float y, const ISPCCamera& camera, RayStats& stats, RandomSamplerWrapper& sampler) {
/* radiance accumulator and weight */
Vec3fa L = Vec3fa(0.0f);
Vec3fa Lw = Vec3fa(1.0f);
bool in_volume = scene == 0;
/* initialize ray */
Ray ray(Vec3fa(camera.xfm.p), Vec3fa(normalize(x * camera.xfm.l.vx + y * camera.xfm.l.vy + camera.xfm.l.vz)), 0.0f,
inf);
for (int i = 0; i < ray_depth; i++) {
/* intersect ray with scene */
RTCIntersectArguments iargs;
rtcInitIntersectArguments(&iargs);
iargs.feature_mask = RTC_FEATURE_FLAG_TRIANGLE;
rtcIntersect1(data.g_scene, RTCRayHit_(ray), &iargs);
RayStats_addRay(stats);
const Vec3fa wo = neg(ray.dir);
float t;
if (!in_volume | (density == 0)) {
t = inf;
} else {
// printf("%f\n", density);
t = - std::log(1.0 - sampler.get1D()) / density;
}
// if (t != t | t <= 0) {
// printf("t: %f;%f\n", t, ray.tfar);
// }
if (t > 0.0 && t < ray.tfar) {
// Nee
/* Light ray */
// return {0.0, 0.0, 1.0};
int id = (int)(sampler.get1D() * data.scene->lights.size());
if (id == data.scene->lights.size())
id = data.scene->lights.size() - 1;
const Light* l = data.scene->lights.at(id);
Sample sample;
sample.P = ray.org + t * ray.dir;
sample.Ng = ray.dir;
sample.Ns = ray.dir;
Light_SampleRes ls = Lights_sample(l, sample, sampler.get2D());
/* initialize shadow ray */
Ray shadow(sample.P, ls.dir, EPS, ls.dist - EPS, 0.0f);
/* shadow magic */
float Lwscatter = 1;
float shadow_near = EPS;
bool shadow_in_volume = in_volume;
while (1) {
/* initialize shadow ray */
Ray shadow(sample.P, ls.dir, shadow_near, ls.dist - EPS, 0.0f);
Sample shadowSample = createSample(shadow);
/* shadow ray */
RTCIntersectArguments iargs;
rtcInitIntersectArguments(&iargs);
iargs.feature_mask = RTC_FEATURE_FLAG_TRIANGLE;
rtcIntersect1(data.g_scene, RTCRayHit_(shadow), &iargs);
RayStats_addRay(stats);
if (shadow.geomID == RTC_INVALID_GEOMETRY_ID) {
if (shadow_in_volume) {
Lwscatter *= std::pow(M_E, - density * (shadow.tfar - shadow.tnear()));
}
break;
}
/* calculate BRDF */
BRDF brdf;
std::vector<Material *> material_array = data.scene->materials;
Material__preprocess(material_array, shadow.geomID, brdf, neg(shadow.dir), shadowSample);
if (brdf.name == "default") {
if (shadow_in_volume) {
Lwscatter *= std::pow(M_E, - density * (shadow.tfar - shadow.tnear()));
}
shadow_in_volume = dot(normalize(shadow.Ng), shadow.dir) < 0;
shadow_near = shadow.tfar + EPS;
} else {
Lwscatter = 0.0;
break;
}
};
// /* trace shadow ray */
// RTCOccludedArguments sargs;
// rtcInitOccludedArguments(&sargs);
// sargs.feature_mask = RTC_FEATURE_FLAG_TRIANGLE;
// rtcOccluded1(data.g_scene, RTCRay_(shadow), &sargs);
// RayStats_addShadowRay(stats);
float scatter = phase(scattering_parameter, -dot(-ray.dir,shadow.dir));
/* add light contribution if not occluded (NEE) */
if (Lwscatter > 0.0) {
// L += Lw * light_diffuse * ls.weight;
L += Lw * Lwscatter * scatter * (1.0 - absorbtion) * ls.weight / data.scene->lights.size();
// L += Lw * light_diffuse * ls.weight/ data.scene->lights.size();
}
// new direction
float pdf;
Vec3fa o = sample_phase_function(-ray.dir, scattering_parameter, sampler.get2D(), pdf);
Lw *= 1.0 - absorbtion;
ray = Ray(ray.org + t * ray.dir,o,EPS,inf);
} else if (ray.geomID != RTC_INVALID_GEOMETRY_ID) {
Sample sample = createSample(ray);
int matId = data.scene->geometries.at(ray.geomID)->materialID;
unsigned lightID = data.scene->geometries.at(ray.geomID)->lightID;
// include direct light on first ray
if (lightID != unsigned(-1)) {
if (i == 0) {
// printf("lightID: %d\n", lightID);
const Light* l = data.scene->lights[lightID];
Light_EvalRes evalRes = Lights_eval(l, sample, -wo);
L += Lw * evalRes.value;
}
break;
}
/* calculate BRDF */
BRDF brdf;
std::vector<Material *> material_array = data.scene->materials;
Material__preprocess(material_array, matId, brdf, wo, sample);
if (brdf.name == "default") {
in_volume = dot(normalize(ray.Ng), ray.dir) < 0;
ray = Ray(ray.org + ray.tfar * ray.dir, ray.dir, EPS, inf);
i--;
} else {
/* Light ray */
int id = (int)(sampler.get1D() * data.scene->lights.size());
if (id == data.scene->lights.size())
id = data.scene->lights.size() - 1;
// printf("id: %d\n", id);
const Light* l = data.scene->lights.at(id);
Light_SampleRes ls = Lights_sample(l, sample, sampler.get2D());
Vec3fa light_diffuse = Material__eval(material_array, matId, brdf, wo, sample, ls.dir);
/* shadow magic */
float Lwscatter = 1;
float shadow_near = EPS;
bool shadow_in_volume = in_volume;
while (1) {
/* initialize shadow ray */
Ray shadow(sample.P, ls.dir, shadow_near, ls.dist - EPS, 0.0f);
Sample shadowSample = createSample(shadow);
/* shadow ray */
RTCIntersectArguments iargs;
rtcInitIntersectArguments(&iargs);
iargs.feature_mask = RTC_FEATURE_FLAG_TRIANGLE;
rtcIntersect1(data.g_scene, RTCRayHit_(shadow), &iargs);
RayStats_addRay(stats);
if (shadow.geomID == RTC_INVALID_GEOMETRY_ID) {
if (shadow_in_volume) {
Lwscatter *= std::pow(M_E, - density * (shadow.tfar - shadow.tnear()));
}
break;
}
/* calculate BRDF */
BRDF brdf;
std::vector<Material *> material_array = data.scene->materials;
Material__preprocess(material_array, shadow.geomID, brdf, neg(shadow.dir), shadowSample);
if (brdf.name == "default") {
if (shadow_in_volume) {
Lwscatter *= std::pow(M_E, - density * (shadow.tfar - shadow.tnear()));
}
shadow_in_volume = dot(normalize(shadow.Ng), shadow.dir) < 0;
shadow_near = shadow.tfar + EPS;
} else {
Lwscatter = 0.0;
break;
}
};
// /* trace shadow ray */
// RTCOccludedArguments sargs;
// rtcInitOccludedArguments(&sargs);
// sargs.feature_mask = RTC_FEATURE_FLAG_TRIANGLE;
// rtcOccluded1(data.g_scene, RTCRay_(shadow), &sargs);
// RayStats_addShadowRay(stats);
/* add light contribution if not occluded (NEE) */
if (Lwscatter > 0.0) {
// L += Lw * light_diffuse * ls.weight;
L += Lw * Lwscatter *light_diffuse * ls.weight * dot(sample.Ng, ls.dir) / data.scene->lights.size();
// L += Lw * light_diffuse * ls.weight/ data.scene->lights.size();
}
// Use cosine sampling
Vec2f uv = sampler.get2D();
Sample3f wi = cosineSampleHemisphere(uv.x, uv.y, sample.Ng);
Vec3fa diffuse = Material__eval(material_array, matId, brdf, wo, sample, wi.v);
// printf("pdf: %f\n", wi.pdf);
Lw *= diffuse / wi.pdf;
ray = Ray(sample.P,wi.v,EPS,inf);
}
}
}
return L;
}
/* task that renders a single screen tile */
Vec3fa Application2::renderPixelOrig(float x, float y, const ISPCCamera& camera, RayStats& stats, RandomSamplerWrapper& sampler) {
/* radiance accumulator and weight */
Vec3fa L = Vec3fa(0.0f);
Vec3fa Lw = Vec3fa(1.0f);
float transmittance = 1.0f;
/* initialize ray */
Ray ray(Vec3fa(camera.xfm.p), Vec3fa(normalize(x * camera.xfm.l.vx + y * camera.xfm.l.vy + camera.xfm.l.vz)), 0.0f,
inf);
/* intersect ray with scene */
RTCIntersectArguments iargs;
rtcInitIntersectArguments(&iargs);
iargs.feature_mask = RTC_FEATURE_FLAG_TRIANGLE;
rtcIntersect1(data.g_scene, RTCRayHit_(ray), &iargs);
RayStats_addRay(stats);
const Vec3fa wo = neg(ray.dir);
/* shade pixels */
if (ray.geomID != RTC_INVALID_GEOMETRY_ID) {
Vec3fa Ns = normalize(ray.Ng);
Sample sample;
sample.P = ray.org + ray.tfar * ray.dir;
sample.Ng = ray.Ng;
sample.Ns = Ns;
unsigned matId = data.scene->geometries[ray.geomID]->materialID;
unsigned lightID = data.scene->geometries[ray.geomID]->lightID;
if (lightID != unsigned(-1)) {
const Light* l = data.scene->lights[lightID];
Light_EvalRes evalRes = Lights_eval(l, sample, -wo);
L += evalRes.value;
return L;
} else {
sample.Ng = face_forward(ray.dir, normalize(sample.Ng));
sample.Ns = face_forward(ray.dir, normalize(sample.Ns));
/* calculate BRDF */
BRDF brdf;
std::vector<Material *> material_array = data.scene->materials;
Material__preprocess(material_array, matId, brdf, wo, sample);
/* test if volume bounding box */
if (brdf.name == "default") {
if (boundingBox) {
return {1, 0, 0};
}
/* non scattering raymarch implementation */
Ray secondary(sample.P, ray.dir, 0.001f, inf, 0.0f);
/* trace secondary ray */
rtcInitIntersectArguments(&iargs);
iargs.feature_mask = RTC_FEATURE_FLAG_TRIANGLE;
rtcIntersect1(data.g_scene, RTCRayHit_(secondary), &iargs);
RayStats_addRay(stats);
if (secondary.geomID != RTC_INVALID_GEOMETRY_ID) {
int num_steps = 100;
Vec3fa p_c = secondary.org;
Vec3fa end = secondary.org + secondary.tfar * secondary.dir;
Vec3fa step = (end - p_c) / num_steps;
float step_length = embree::length(step);
for (int i = 0; i < num_steps; i++) {
float density = 0;
if (data.densityGrid) {
density = data.densityGrid->sampleW(p_c); // Sample density from the grid
}
float temp = 0;
if (data.tempGrid) {
temp = data.tempGrid->sampleW(p_c); // Sample density from the grid
}
float g = 0.8; // asymmetry factor of the phase function
float angle = 1.0;
// HG phase function
float p = phase(g, angle);
float pdf;
Vec3f dir = sample_phase_function(-ray.org, g, sampler.get2D(), pdf);
// if -1.0 it means that we're out of the bounding box of the grid
if (density != -1.0f) {
density *= 10;
float redWavelength = 700;
float greenWavelength = 530;
float blueWavelength = 470;
Vec3fa emissive = Vec3fa(0.0, 0.0, 0.0);
if (temp != -1.0f && temp > 0.001) {
temp *= 1000;
emissive = Vec3f(blackbody_radiance_normalized(redWavelength, temp),
blackbody_radiance_normalized(greenWavelength, temp),
blackbody_radiance_normalized(blueWavelength, temp));
}
transmittance *= std::exp(-density * step_length);
// Update transmittance using exponential decay
L += emissive * transmittance;
}
p_c += step; // Move to the next point along the ray
}
Ray light(secondary.org + secondary.tfar * secondary.dir, ray.dir, 0.001f, inf, 0.0f);
/* trace light ray after medium escaped */
rtcInitIntersectArguments(&iargs);
iargs.feature_mask = RTC_FEATURE_FLAG_TRIANGLE;
rtcIntersect1(data.g_scene, RTCRayHit_(light), &iargs);
RayStats_addRay(stats);
if (light.geomID != RTC_INVALID_GEOMETRY_ID) {
unsigned lightID2 = data.scene->geometries[light.geomID]->lightID;
if (lightID2 != unsigned(-1)) {
const Light* l = data.scene->lights[lightID2];
Light_EvalRes evalRes = Lights_eval(l, sample, -wo);
L += evalRes.value * transmittance;
return L;
}
}
}
} else {
/* sample BRDF at hit point */
Sample3f wi1;
Material__sample(material_array, matId, brdf, Lw, wo, sample, wi1, sampler.get2D());
int id = (int) (sampler.get1D() * data.scene->lights.size());
if (id == data.scene->lights.size())
id = data.scene->lights.size() - 1;
const Light* l = data.scene->lights[id];
Light_SampleRes ls = Lights_sample(l, sample, sampler.get2D());
Vec3fa diffuse = Material__eval(material_array, matId, brdf, wo, sample, ls.dir);
/* initialize shadow ray */
Ray shadow(sample.P, ls.dir, 0.001f, ls.dist - 0.001f, 0.0f);
/* trace shadow ray */
RTCOccludedArguments sargs;
rtcInitOccludedArguments(&sargs);
sargs.feature_mask = RTC_FEATURE_FLAG_TRIANGLE;
rtcOccluded1(data.g_scene, RTCRay_(shadow), &sargs);
RayStats_addShadowRay(stats);
if (shadow.tfar >= 0.0f) {
L += diffuse * ls.weight;
}
}
}
}
return ACESFilm(L, 1);
}