Add Assignment 3

This commit is contained in:
hal8174 2024-06-13 13:54:34 +02:00
parent c864d2a42f
commit 56e4862861
8 changed files with 768 additions and 3 deletions

View file

@ -0,0 +1,147 @@
#include "Application3.h"
void Application3::initScene() {
Data_Constructor(&data, 1, 8);
/* select scene here */
//standardScene();
causticScene();
}
void Application3::standardScene() {
FileName file = workingDir + FileName("Framework/scenes/cornell_box.obj");
/* set default camera */
camera.from = Vec3fa(278, 273, -800);
camera.to = Vec3fa(278, 273, 0);
Ref<SceneGraph::GroupNode> sceneGraph = loadOBJ(file, false).cast<SceneGraph::GroupNode>();
auto light = new SceneGraph::QuadLightMesh(Vec3fa(343.0, 548.0, 227.0), Vec3fa(213.0, 548.0, 332.0),
Vec3fa(343.0, 548.0, 332.0),
Vec3fa(213.0, 548.0, 227.0), Vec3fa(25, 25, 25));
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;
scene = nullptr;
}
void Application3::causticScene() {
FileName file = workingDir + FileName("Framework/scenes/caustics/ring.obj");
/* set default camera */
camera.from = Vec3fa(1, 2, 1);
camera.to = Vec3fa(0, 0, 0);
camera.fov = 60;
Ref<SceneGraph::GroupNode> sceneGraph = loadOBJ(file, false).cast<SceneGraph::GroupNode>();
auto light = new SceneGraph::QuadLightMesh(Vec3fa(0.1, 1.0, 2.0), Vec3fa(-0.1, 1.2, 2.0),
Vec3fa(-0.1, 1.0, 2.0), Vec3fa(0.1, 1.2, 2.0),
Vec3fa(50, 50, 50));
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;
scene = nullptr;
}
/*
IMPORTANT: use your own path tracing implementation from the 1st assignment!!
the only change that we made was introduction of the RandomSamplerWrapper. It wrappes the sampling routines, so you could introduce a new sampler for Metropolis Light Transport and by overwriting RandomSamplerWrapper methods: get1D(), get2D()...
also the drawGUI() function now invokes ApplicationIntegrator::drawGUI();
*/
/* task that renders a single screen tile */
Vec3fa Application3::renderPixel(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);
/* 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;
} 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);
/* 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);
/* add light contribution if not occluded */
if (shadow.tfar >= 0.0f) {
L += diffuse * ls.weight;
}
}
}
return L;
}

View file

@ -0,0 +1,26 @@
#pragma once
#include "helper.hpp"
#include "application_integrator.h"
class Application3 : public ApplicationIntegrator {
public:
Application3(int argc, char** argv) : ApplicationIntegrator(argc, argv, "Assignment 3") {
}
private:
Vec3fa renderPixel(float x, float y, const ISPCCamera& camera, RayStats& stats, RandomSamplerWrapper& sampler) override;
void drawGUI() override {
ApplicationIntegrator::drawGUI(); // NEW!
}
void initScene() override;
void standardScene();
void causticScene();
float colorLight[3] = {1.0f, 1.0f, 1.0f};
};

View file

@ -1,5 +1,9 @@
cmake_minimum_required(VERSION 3.16.0 FATAL_ERROR)
project(Assignment3)
add_executable(${PROJECT_NAME} "assignment3.cpp")
add_executable(${PROJECT_NAME} "assignment3.cpp"
Application3.cpp
Application3.h
application_integrator.h
application_integrator.cpp
helper.hpp)
target_link_libraries(${PROJECT_NAME} PUBLIC CGI-framework)

View file

@ -0,0 +1,108 @@
#include "application_integrator.h"
ApplicationIntegrator::ApplicationIntegrator(int argc, char** argv, const std::string& name):
Application(argc, argv, name)
{
resetRender();
}
void ApplicationIntegrator::drawGUI() {
bool bDirty = false;
if (ImGui::Checkbox("Metropolis", &bMetropolis)) {
resetRender();
}
if (bDirty) {
resetRender();
}
}
inline float luminance(Vec3fa v) {
return 0.2126f * v.x + 0.7152f * v.y + 0.0722f * v.z;
}
void ApplicationIntegrator::resetRender() {
Application::resetRender();
if (bMetropolis) {
data.film.count = false;
}
else {
data.film.count = true;
data.film.scalar = 1.0;
}
}
void ApplicationIntegrator::render(int* pixels, int width, int height, float time, const ISPCCamera& camera) {
deviceRender(camera);
if (!bMetropolis) {
mcRender(pixels, width, height, time, camera);
}
else {
mltRender(pixels, width, height, time, camera);
}
}
void ApplicationIntegrator::mltRender(int* pixels, int width, int height, float time, const ISPCCamera& camera) {
// data.film.scalar = ... use it for setting up the correct normalization coefficient
//
//
// you may want to use Distribution1D for the bootstrap
// d = Distribution1D(float* bis_values, num_bins)
// float integral = d.funcInt;
// int index_of_the_sampled_bin = d.SampleDiscrete(rng.get1D());
assert(0);
}
void ApplicationIntegrator::mcRender(int* pixels, int width, int height, float time, const ISPCCamera& camera) {
const int numTilesX = (width + TILE_SIZE_X - 1) / TILE_SIZE_X;
const int numTilesY = (height + TILE_SIZE_Y - 1) / TILE_SIZE_Y;
parallel_for(size_t(0), size_t(numTilesX * numTilesY), [&](const range<size_t>& range) {
const int threadIndex = (int)TaskScheduler::threadIndex();
for (size_t i = range.begin(); i < range.end(); i++)
renderTile((int)i, threadIndex, pixels, width, height, time, camera, numTilesX, numTilesY);
});
}
/* renders a single screen tile */
void ApplicationIntegrator::mcRenderTile(int taskIndex, int threadIndex, int* pixels, const unsigned int width,
const unsigned int height, const float time, const ISPCCamera& camera, const int numTilesX,
const int numTilesY) {
const unsigned int tileY = taskIndex / numTilesX;
const unsigned int tileX = taskIndex - tileY * numTilesX;
const unsigned int x0 = tileX * TILE_SIZE_X;
const unsigned int x1 = min(x0 + TILE_SIZE_X, width);
const unsigned int y0 = tileY * TILE_SIZE_Y;
const unsigned int y1 = min(y0 + TILE_SIZE_Y, height);
for (unsigned int y = y0; y < y1; y++)
for (unsigned int x = x0; x < x1; x++) {
RandomSamplerWrapper sampler;
Vec3fa L = Vec3fa(0.0f);
for (int i = 0; i < data.spp; i++)
{
sampler.init(x, y, (data.frame_count) * data.spp + i);
/* calculate pixel color */
float fx = x + sampler.get1D();
float fy = y + sampler.get1D();
L = L + renderPixel(fx, fy, camera, g_stats[threadIndex], sampler);
}
L = L / (float)data.spp;
/* write color to framebuffer */
data.film.addSplat(x, y, L);
}
}

View file

@ -0,0 +1,31 @@
#pragma once
#include "helper.hpp"
#include "distribution.hpp"
class ApplicationIntegrator: public Application {
public:
ApplicationIntegrator(int argc, char** argv, const std::string& name);
virtual ~ApplicationIntegrator() = default;
protected:
virtual void render(int* pixels, int width, int height, float time, const ISPCCamera& camera) override;
virtual void drawGUI() override;
virtual void resetRender() override;
bool bMetropolis = false;
void mltRender(int* pixels, int width, int height, float time, const ISPCCamera& camera);
void mcRender(int* pixels, int width, int height, float time, const ISPCCamera& camera);
/* renders a single screen tile */
void mcRenderTile(int taskIndex, int threadIndex, int* pixels, const unsigned int width,
const unsigned int height, const float time, const ISPCCamera& camera, const int numTilesX,
const int numTilesY);
};

View file

@ -1,4 +1,9 @@
#include "Application3.h"
int main(int argc, char** argv) {
auto app = new Application3(argc, argv);
app->run();
return 0;
}

View file

@ -0,0 +1,444 @@
#pragma once
#include <application.h>
#include <sampling.hpp>
#include <random_sampler_wrapper.hpp>
#include <scenegraph/obj_loader.h>
#include <lights/ambient_light.h>
#include <lights/directional_light.h>
#include <lights/point_light.h>
#include <lights/quad_light.h>
#include <lights/spot_light.h>
using namespace embree;
inline Vec3fa reflect(const Vec3fa& V, const Vec3fa& N) { return 2.0f * dot(V, N) * N - V; }
inline Vec3fa face_forward(const Vec3fa& dir, const Vec3fa& _Ng) {
const Vec3fa Ng = _Ng;
return dot(dir, Ng) < 0.0f ? Ng : neg(Ng);
}
inline Light_SampleRes Lights_sample(const Light* self,
const Sample& sp, /*! point to generate the sample for >*/
const Vec2f s) /*! random numbers to generate the sample >*/
{
LightType ty = self->type;
switch (ty) {
case LIGHT_AMBIENT: return AmbientLight_sample(self, sp, s);
case LIGHT_POINT: return PointLight_sample(self, sp, s);
case LIGHT_DIRECTIONAL: return DirectionalLight_sample(self, sp, s);
case LIGHT_SPOT: return SpotLight_sample(self, sp, s);
case LIGHT_QUAD: return QuadLight_sample(self, sp, s);
default: {
Light_SampleRes res;
res.weight = Vec3fa(0, 0, 0);
res.dir = Vec3fa(0, 0, 0);
res.dist = 0;
res.pdf = inf;
return res;
}
}
}
inline Light_EvalRes Lights_eval(const Light* self,
const Sample& sp,
const Vec3fa& dir) {
LightType ty = self->type;
switch (ty) {
case LIGHT_AMBIENT: return AmbientLight_eval(self, sp, dir);
case LIGHT_POINT: return PointLight_eval(self, sp, dir);
case LIGHT_DIRECTIONAL: return DirectionalLight_eval(self, sp, dir);
case LIGHT_SPOT: return SpotLight_eval(self, sp, dir);
case LIGHT_QUAD: return QuadLight_eval(self, sp, dir);
default: {
Light_EvalRes res;
res.value = Vec3fa(0, 0, 0);
res.dist = inf;
res.pdf = 0.f;
return res;
}
}
}
struct BRDF {
float Ns; /*< specular exponent */
float Ni; /*< optical density for the surface (index of refraction) */
Vec3fa Ka; /*< ambient reflectivity */
Vec3fa Kd; /*< diffuse reflectivity */
Vec3fa Ks; /*< specular reflectivity */
Vec3fa Kt; /*< transmission filter */
float dummy[30];
};
////////////////////////////////////////////////////////////////////////////////
// Lambertian BRDF //
////////////////////////////////////////////////////////////////////////////////
struct Lambertian {
Vec3fa R;
};
inline Vec3fa Lambertian__eval(const Lambertian* This,
const Vec3fa& wo, const Sample& dg, const Vec3fa& wi) {
return This->R * (1.0f / (float) (float(M_PI))) * clamp(dot(wi, dg.Ns));
}
inline Vec3fa Lambertian__sample(const Lambertian* This,
const Vec3fa& wo,
const Sample& dg,
Sample3f& wi,
const Vec2f& s) {
wi = cosineSampleHemisphere(s.x, s.y, dg.Ns);
return Lambertian__eval(This, wo, dg, wi.v);
}
inline void Lambertian__Constructor(Lambertian* This, const Vec3fa& R) {
This->R = R;
}
inline Lambertian make_Lambertian(const Vec3fa& R) {
Lambertian v;
Lambertian__Constructor(&v, R);
return v;
}
////////////////////////////////////////////////////////////////////////////////
// Matte Material //
////////////////////////////////////////////////////////////////////////////////
inline void MatteMaterial__preprocess(MatteMaterial* material, BRDF& brdf, const Vec3fa& wo, const Sample& sp) {
}
inline Vec3fa MatteMaterial__eval(MatteMaterial* This, const BRDF& brdf, const Vec3fa& wo, const Sample& sp,
const Vec3fa& wi) {
Lambertian lambertian = make_Lambertian(Vec3fa((Vec3fa) This->reflectance));
return Lambertian__eval(&lambertian, wo, sp, wi);
}
inline Vec3fa MatteMaterial__sample(MatteMaterial* This, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo,
const Sample& sp, Sample3f& wi_o, const Vec2f& s) {
Lambertian lambertian = make_Lambertian(Vec3fa((Vec3fa) This->reflectance));
return Lambertian__sample(&lambertian, wo, sp, wi_o, s);
}
////////////////////////////////////////////////////////////////////////////////
// OBJ Material //
////////////////////////////////////////////////////////////////////////////////
inline void OBJMaterial__preprocess(OBJMaterial* material, BRDF& brdf, const Vec3fa& wo, const Sample& sp) {
float d = material->d;
// if (material->map_d) d *= getTextureTexel1f(material->map_d, dg.u, dg.v);
brdf.Ka = Vec3fa(material->Ka);
//if (material->map_Ka) { brdf.Ka *= material->map_Ka->get(dg.st); }
brdf.Kd = d * Vec3fa(material->Kd);
// if (material->map_Kd) brdf.Kd = brdf.Kd * getTextureTexel3f(material->map_Kd, dg.u, dg.v);
brdf.Ks = d * Vec3fa(material->Ks);
//if (material->map_Ks) brdf.Ks *= material->map_Ks->get(dg.st);
brdf.Ns = material->Ns;
//if (material->map_Ns) { brdf.Ns *= material->map_Ns.get(dg.st); }
brdf.Kt = (1.0f - d) * Vec3fa(material->Kt);
brdf.Ni = material->Ni;
}
inline Vec3fa OBJMaterial__eval(OBJMaterial* material, const BRDF& brdf, const Vec3fa& wo, const Sample& sp,
const Vec3fa& wi) {
Vec3fa R = Vec3fa(0.0f);
const float Md = max(max(brdf.Kd.x, brdf.Kd.y), brdf.Kd.z);
const float Ms = max(max(brdf.Ks.x, brdf.Ks.y), brdf.Ks.z);
const float Mt = max(max(brdf.Kt.x, brdf.Kt.y), brdf.Kt.z);
if (Md > 0.0f) {
R = R + (1.0f / float(M_PI)) * clamp(dot(wi, sp.Ns)) * brdf.Kd;
}
if (Ms > 0.0f) {
const Sample3f refl = make_Sample3f(reflect(wo, sp.Ns), 1.0f);
if (dot(refl.v, wi) > 0.0f) {
R = R + (brdf.Ns + 2) * float(one_over_two_pi) * powf(max(1e-10f, dot(refl.v, wi)), brdf.Ns) *
clamp(dot(wi, sp.Ns)) * brdf.Ks;
}
}
if (Mt > 0.0f) {
}
return R;
}
inline Vec3fa OBJMaterial__sample(OBJMaterial* material, const BRDF& brdf, const Vec3fa& Lw, const Vec3fa& wo,
const Sample& sp, Sample3f& wi_o, const Vec2f& s) {
Vec3fa cd = Vec3fa(0.0f);
Sample3f wid = make_Sample3f(Vec3fa(0.0f), 0.0f);
if (max(max(brdf.Kd.x, brdf.Kd.y), brdf.Kd.z) > 0.0f) {
wid = cosineSampleHemisphere(s.x, s.y, sp.Ns);
cd = float(one_over_pi) * clamp(dot(wid.v, sp.Ns)) * brdf.Kd;
}
Vec3fa cs = Vec3fa(0.0f);
Sample3f wis = make_Sample3f(Vec3fa(0.0f), 0.0f);
if (max(max(brdf.Ks.x, brdf.Ks.y), brdf.Ks.z) > 0.0f) {
const Sample3f refl = make_Sample3f(reflect(wo, sp.Ns), 1.0f);
wis.v = powerCosineSampleHemisphere(brdf.Ns, s);
wis.pdf = powerCosineSampleHemispherePDF(wis.v, brdf.Ns);
wis.v = frame(refl.v) * wis.v;
cs = (brdf.Ns + 2) * float(one_over_two_pi) * powf(max(dot(refl.v, wis.v), 1e-10f), brdf.Ns) *
clamp(dot(wis.v, sp.Ns)) * brdf.Ks;
}
Vec3fa ct = Vec3fa(0.0f);
Sample3f wit = make_Sample3f(Vec3fa(0.0f), 0.0f);
if (max(max(brdf.Kt.x, brdf.Kt.y), brdf.Kt.z) > 0.0f) {
wit = make_Sample3f(neg(wo), 1.0f);
ct = brdf.Kt;
}
const Vec3fa md = Lw * cd / wid.pdf;
const Vec3fa ms = Lw * cs / wis.pdf;
const Vec3fa mt = Lw * ct / wit.pdf;
const float Cd = wid.pdf == 0.0f ? 0.0f : max(max(md.x, md.y), md.z);
const float Cs = wis.pdf == 0.0f ? 0.0f : max(max(ms.x, ms.y), ms.z);
const float Ct = wit.pdf == 0.0f ? 0.0f : max(max(mt.x, mt.y), mt.z);
const float C = Cd + Cs + Ct;
if (C == 0.0f) {
wi_o = make_Sample3f(Vec3fa(0, 0, 0), 0);
return Vec3fa(0, 0, 0);
}
const float CPd = Cd / C;
const float CPs = Cs / C;
const float CPt = Ct / C;
if (s.x < CPd) {
wi_o = make_Sample3f(wid.v, wid.pdf * CPd);
return cd;
} else if (s.x < CPd + CPs) {
wi_o = make_Sample3f(wis.v, wis.pdf * CPs);
return cs;
} else {
wi_o = make_Sample3f(wit.v, wit.pdf * CPt);
return ct;
}
}
////////////////////////////////////////////////////////////////////////////////
// Metal Material //
////////////////////////////////////////////////////////////////////////////////
// =======================================================
struct FresnelConductor
{
Vec3fa eta; //!< Real part of refraction index
Vec3fa k; //!< Imaginary part of refraction index
};
inline Vec3fa fresnelConductor(const float cosi, const Vec3fa &eta, const Vec3fa &k)
{
const Vec3fa tmp = eta * eta + k * k;
const Vec3fa Rpar = (tmp * (cosi * cosi) - 2.0f * eta * cosi + Vec3fa(1.0f)) *
rcp(tmp * (cosi * cosi) + 2.0f * eta * cosi + Vec3fa(1.0f));
const Vec3fa Rper = (tmp - 2.0f * eta * cosi + Vec3fa(cosi * cosi)) *
rcp(tmp + 2.0f * eta * cosi + Vec3fa(cosi * cosi));
return 0.5f * (Rpar + Rper);
}
inline Vec3fa eval(const FresnelConductor &This, const float cosTheta)
{
return fresnelConductor(cosTheta, This.eta, This.k);
}
inline FresnelConductor make_FresnelConductor(const Vec3fa &eta, const Vec3fa &k)
{
FresnelConductor m;
m.eta = eta;
m.k = k;
return m;
}
// =======================================================
struct PowerCosineDistribution
{
float exp;
};
inline float eval(const PowerCosineDistribution &This, const float cosThetaH)
{
return (This.exp + 2) * (1.0f / (2.0f * (float(M_PI)))) * powf(fabs(cosThetaH), This.exp);
}
inline void sample(const PowerCosineDistribution &This, const Vec3fa &wo, const Vec3fa &N, Sample3f &wi, const Vec2f s)
{
Vec3fa dir = powerCosineSampleHemisphere(This.exp, s);
Sample3f wh;
wh.v = frame(N) * dir;
wh.pdf = powerCosineSampleHemispherePDF(dir, This.exp);
Sample3f r = make_Sample3f(reflect(wo, wh.v), 1.0f);
wi = make_Sample3f(r.v, wh.pdf / (4.0f * fabs(dot(wo, wh.v))));
}
inline PowerCosineDistribution make_PowerCosineDistribution(const float _exp)
{
PowerCosineDistribution m;
m.exp = _exp;
return m;
}
inline void MetalMaterial__preprocess(MetalMaterial *material, BRDF &brdf, const Vec3fa &wo, const Sample &sp)
{
}
inline Vec3fa MetalMaterial__eval(MetalMaterial *material, const BRDF &brdf, const Vec3fa &wo, const Sample &sp, const Vec3fa &wi)
{
const FresnelConductor fresnel = make_FresnelConductor(Vec3fa(material->eta), Vec3fa(material->k));
const PowerCosineDistribution distribution = make_PowerCosineDistribution(rcp(material->roughness));
const float cosThetaO = dot(wo, sp.Ns);
const float cosThetaI = dot(wi, sp.Ns);
if (cosThetaI <= 0.0f || cosThetaO <= 0.0f)
return Vec3fa(0.f);
const Vec3fa wh = normalize(wi + wo);
const float cosThetaH = dot(wh, sp.Ns);
const float cosTheta = dot(wi, wh); // = dot(wo, wh);
const Vec3fa F = eval(fresnel, cosTheta);
const float D = eval(distribution, cosThetaH);
const float G = min(1.0f, min(2.0f * cosThetaH * cosThetaO / cosTheta,
2.0f * cosThetaH * cosThetaI / cosTheta));
return (Vec3fa(material->reflectance) * F) * D * G * rcp(4.0f * cosThetaO);
}
inline Vec3fa MetalMaterial__sample(MetalMaterial *material, const BRDF &brdf, const Vec3fa &Lw, const Vec3fa &wo, const Sample &sp, Sample3f &wi_o, const Vec2f &s)
{
const PowerCosineDistribution distribution = make_PowerCosineDistribution(rcp(material->roughness));
if (dot(wo, sp.Ns) <= 0.0f)
{
wi_o = make_Sample3f(Vec3fa(0.0f), 0.0f);
return Vec3fa(0.f);
}
sample(distribution, wo, sp.Ns, wi_o, s);
if (dot(wi_o.v, sp.Ns) <= 0.0f)
{
wi_o = make_Sample3f(Vec3fa(0.0f), 0.0f);
return Vec3fa(0.f);
}
return MetalMaterial__eval(material, brdf, wo, sp, wi_o.v);
}
////////////////////////////////////////////////////////////////////////////////
// ReflectiveMetal Material //
////////////////////////////////////////////////////////////////////////////////
inline void ReflectiveMetalMaterial__preprocess(ReflectiveMetalMaterial *material, BRDF &brdf, const Vec3fa &wo, const Sample &sp)
{
}
inline Vec3fa ReflectiveMetalMaterial__eval(ReflectiveMetalMaterial *material, const BRDF &brdf, const Vec3fa &wo, const Sample &sp, const Vec3fa &wi)
{
return Vec3fa(0.0f);
}
inline Vec3fa ReflectiveMetalMaterial__sample(ReflectiveMetalMaterial *material, const BRDF &brdf, const Vec3fa &Lw, const Vec3fa &wo, const Sample &sp, Sample3f &wi_o, const Vec2f &s)
{
wi_o = make_Sample3f(reflect(wo,sp.Ns),1.0f);
return Vec3fa(material->reflectance) * fresnelConductor(dot(wo,sp.Ns),Vec3fa((Vec3fa)material->eta),Vec3fa((Vec3fa)material->k));
}
////////////////////////////////////////////////////////////////////////////////
// Material //
////////////////////////////////////////////////////////////////////////////////
inline void Material__preprocess(std::vector<Material *> materials, unsigned int materialID,
BRDF &brdf, const Vec3fa &wo, const Sample &sp)
{
auto id = materialID;
{
if (id < materials.size()) // FIXME: workaround for ISPC bug, location reached with empty execution mask
{
Material *material = materials[id];
switch (material->type)
{
case MATERIAL_OBJ:
OBJMaterial__preprocess((OBJMaterial *)material, brdf, wo, sp);
break;
case MATERIAL_MATTE:
MatteMaterial__preprocess((MatteMaterial *)material, brdf, wo, sp);
break;
case MATERIAL_METAL:
MetalMaterial__preprocess((MetalMaterial *)material, brdf, wo, sp);
break;
case MATERIAL_REFLECTIVE_METAL:
ReflectiveMetalMaterial__preprocess((ReflectiveMetalMaterial *)material, brdf, wo, sp);
break;
default:
break;
}
}
}
}
inline Vec3fa Material__eval(std::vector<Material *> materials, unsigned int materialID,
const BRDF &brdf, const Vec3fa &wo, const Sample &sp, const Vec3fa &wi)
{
Vec3fa c = Vec3fa(0.0f);
auto id = materialID;
{
if (id < materials.size()) // FIXME: workaround for ISPC bug, location reached with empty execution mask
{
Material *material = materials[id];
switch (material->type)
{
case MATERIAL_OBJ:
c = OBJMaterial__eval((OBJMaterial *)material, brdf, wo, sp, wi);
break;
case MATERIAL_MATTE:
c = MatteMaterial__eval((MatteMaterial *)material, brdf, wo, sp, wi);
break;
case MATERIAL_METAL:
c = MetalMaterial__eval((MetalMaterial *)material, brdf, wo, sp, wi);
break;
case MATERIAL_REFLECTIVE_METAL:
c = ReflectiveMetalMaterial__eval((ReflectiveMetalMaterial *)material, brdf, wo, sp, wi);
break;
default:
std::cout << "No Material found" << std::endl;
c = Vec3fa(0.0f);
}
}
}
return c;
}
inline Vec3fa Material__sample(std::vector<Material *> materials, unsigned int materialID,
const BRDF &brdf, const Vec3fa &Lw, const Vec3fa &wo, const Sample &sp, Sample3f &wi_o,
const Vec2f &s)
{
Vec3fa c = Vec3fa(0.0f);
auto id = materialID;
{
if (id < materials.size()) // FIXME: workaround for ISPC bug, location reached with empty execution mask
{
Material *material = materials[id];
switch (material->type)
{
case MATERIAL_OBJ:
c = OBJMaterial__sample((OBJMaterial *)material, brdf, Lw, wo, sp, wi_o, s);
break;
case MATERIAL_MATTE:
c = MatteMaterial__sample((MatteMaterial *)material, brdf, Lw, wo, sp, wi_o, s);
break;
case MATERIAL_METAL:
c = MetalMaterial__sample((MetalMaterial *)material, brdf, Lw, wo, sp, wi_o, s);
break;
case MATERIAL_REFLECTIVE_METAL:
c = ReflectiveMetalMaterial__sample((ReflectiveMetalMaterial *)material, brdf, Lw, wo, sp, wi_o, s);
break;
default:
wi_o = make_Sample3f(Vec3fa(0.0f), 0.0f);
c = Vec3fa(0.0f);
break;
}
}
}
return c;
}