Compare commits

..

2 commits

Author SHA1 Message Date
319802d895 Add Assignment 3 2024-06-13 13:54:34 +02:00
c864d2a42f Add Framwork for Assignment 3 2024-06-13 13:53:07 +02:00
21 changed files with 50815 additions and 48113 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) cmake_minimum_required(VERSION 3.16.0 FATAL_ERROR)
project(Assignment3) 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) 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) { int main(int argc, char** argv) {
auto app = new Application3(argc, argv);
app->run();
return 0; 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;
}

0
Framework/external/imgui/backends/vulkan/generate_spv.sh vendored Executable file → Normal file
View file

View file

@ -38,6 +38,7 @@
#include "camera.hpp" #include "camera.hpp"
#include "ray.hpp" #include "ray.hpp"
#include "random_sampler.hpp" #include "random_sampler.hpp"
#include "random_sampler_wrapper.hpp"
class Application { class Application {
public: public:
@ -48,15 +49,16 @@ public:
void run(); void run();
protected: protected:
virtual Vec3fa renderPixel(float x, float y, const ISPCCamera& camera, RayStats& stats, RandomSampler& sampler) = 0; virtual Vec3fa renderPixel(float x, float y, const ISPCCamera& camera, RayStats& stats, RandomSamplerWrapper& sampler) = 0;
void deviceRender(const ISPCCamera& camera); void deviceRender(const ISPCCamera& camera);
virtual void drawGUI() = 0; virtual void drawGUI() {
}
virtual void initScene() = 0; virtual void initScene() = 0;
void render(int* pixels, int width, int height, float time, const ISPCCamera& camera); virtual void render(int* pixels, int width, int height, float time, const ISPCCamera& camera);
void renderTile(int taskIndex, int threadIndex, int* pixels, unsigned int width, void renderTile(int taskIndex, int threadIndex, int* pixels, unsigned int width,
unsigned int height, unsigned int height,
@ -90,6 +92,13 @@ protected:
void scrollCallback(GLFWwindow*, double xoffset, double yoffset); void scrollCallback(GLFWwindow*, double xoffset, double yoffset);
// it is invoked when the scene changes
virtual void resetRender() {
data.accu_count = 0;
data.film.clear();
}
void initRayStats(); void initRayStats();
int64_t getNumRays(); int64_t getNumRays();
@ -130,7 +139,7 @@ protected:
double clickX = 0; double clickX = 0;
double clickY = 0; double clickY = 0;
float speed = 400; float speed = 1;
Vec3f moveDelta = {0, 0, 0}; Vec3f moveDelta = {0, 0, 0};
RayStats* g_stats = nullptr; RayStats* g_stats = nullptr;

View file

@ -0,0 +1,118 @@
#pragma once
#include <sys/platform.h>
#include <sys/sysinfo.h>
#include <sys/alloc.h>
#include <sys/ref.h>
#include <sys/vector.h>
#include <math/vec2.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <math/bbox.h>
#include <math/lbbox.h>
#include <math/affinespace.h>
#include <sys/filename.h>
#include <sys/estring.h>
#include <lexers/tokenstream.h>
#include <lexers/streamfilters.h>
#include <lexers/parsestream.h>
#include <atomic>
#include <sstream>
#include <vector>
#include <memory>
#include <map>
#include <set>
#include <deque>
#include "helper.hpp"
#include <sys/sysinfo.h>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include "camera.hpp"
#include "ray.hpp"
#include "random_sampler.hpp"
#include "random_sampler_wrapper.hpp"
// https://github.com/mmp/pbrt-v3/blob/master/src/core/pbrt.h#L403
template <typename Predicate>
int FindInterval(int size, const Predicate& pred) {
int first = 0, len = size;
while (len > 0) {
int half = len >> 1, middle = first + half;
// Bisect range based on value of _pred_ at _middle_
if (pred(middle)) {
first = middle + 1;
len -= half + 1;
}
else
len = half;
}
return clamp(first - 1, 0, size - 2);
}
struct Distribution1D {
Distribution1D(){}
// Distribution1D Public Methods
Distribution1D(const float* f, int n) : func(f, f + n), cdf(n + 1) {
// Compute integral of step function at $x_i$
cdf[0] = 0;
for (int i = 1; i < n + 1; ++i) cdf[i] = cdf[i - 1] + func[i - 1] / n;
// Transform step function integral into CDF
funcInt = cdf[n];
if (funcInt == 0) {
for (int i = 1; i < n + 1; ++i) cdf[i] = float(i) / float(n);
}
else {
for (int i = 1; i < n + 1; ++i) cdf[i] /= funcInt;
}
}
int Count() const { return (int)func.size(); }
float SampleContinuous(float u, float* pdf, int* off = nullptr) const {
// Find surrounding CDF segments and _offset_
int offset = FindInterval((int)cdf.size(),
[&](int index) { return cdf[index] <= u; });
if (off) *off = offset;
// Compute offset along CDF segment
float du = u - cdf[offset];
if ((cdf[offset + 1] - cdf[offset]) > 0) {
du /= (cdf[offset + 1] - cdf[offset]);
}
assert(!std::isnan(du));
// Compute PDF for sampled offset
if (pdf) *pdf = (funcInt > 0) ? func[offset] / funcInt : 0;
// Return $x\in{}[0,1)$ corresponding to sample
return (offset + du) / Count();
}
int SampleDiscrete(float u, float* pdf = nullptr,
float* uRemapped = nullptr) const {
// Find surrounding CDF segments and _offset_
int offset = FindInterval((int)cdf.size(),
[&](int index) { return cdf[index] <= u; });
if (pdf) *pdf = (funcInt > 0) ? func[offset] / (funcInt * Count()) : 0;
if (uRemapped)
*uRemapped = (u - cdf[offset]) / (cdf[offset + 1] - cdf[offset]);
if (uRemapped) assert(*uRemapped >= 0.f && *uRemapped <= 1.f);
return offset;
}
float DiscretePDF(int index) const {
assert(index >= 0 && index < Count());
return func[index] / (funcInt * Count());
}
// Distribution1D Public Data
std::vector<float> func, cdf;
float funcInt;
};

185
Framework/include/film.hpp Normal file
View file

@ -0,0 +1,185 @@
#pragma once
#include <sys/platform.h>
#include <sys/sysinfo.h>
#include <sys/alloc.h>
#include <sys/ref.h>
#include <sys/vector.h>
#include <math/vec2.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <math/bbox.h>
#include <math/lbbox.h>
#include <math/affinespace.h>
#include <sys/filename.h>
#include <sys/estring.h>
#include <lexers/tokenstream.h>
#include <lexers/streamfilters.h>
#include <lexers/parsestream.h>
#include <atomic>
#include <sstream>
#include <vector>
#include <memory>
#include <map>
#include <set>
#include <deque>
#include "helper.hpp"
#include <sys/sysinfo.h>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include "camera.hpp"
#include "ray.hpp"
#include "random_sampler.hpp"
#include "random_sampler_wrapper.hpp"
inline unsigned int packColor(unsigned int r, unsigned int g, unsigned int b) {
return (b << 16) + (g << 8) + r;
}
#include <atomic>
// AtomicFloat Class
class AtomicFloat {
public:
// AtomicFloat Public Methods
explicit AtomicFloat(float v = 0.0f) {
bits = floatToBits(v);
}
operator float() const {
return bitsToFloat(bits);
}
float operator=(float v) {
bits = floatToBits(v);
return v;
}
void add(float v) {
uint32_t oldBits = bits, newBits;
do {
newBits = floatToBits(bitsToFloat(oldBits) + v);
} while (!bits.compare_exchange_weak(oldBits, newBits));
}
private:
// AtomicFloat Private Data
std::atomic<uint32_t> bits;
// Helper functions to convert between float and uint32_t
static uint32_t floatToBits(float f) {
uint32_t u;
memcpy(&u, &f, sizeof(uint32_t));
return u;
}
static float bitsToFloat(uint32_t u) {
float f;
memcpy(&f, &u, sizeof(uint32_t));
return f;
}
};
class Film {
public:
Film() {
}
Film(unsigned int width, unsigned int height)
{
init(width, height);
}
void init(unsigned int w, unsigned int h) {
width = w;
height = h;
size_t size = width * height;
accu_x = std::make_unique<AtomicFloat[]>(size);
accu_y = std::make_unique<AtomicFloat[]>(size);
accu_z = std::make_unique<AtomicFloat[]>(size);
splat_count = std::make_unique<std::atomic<unsigned int>[]>(size);
clear();
}
// atomic safe
void addSplat(int x, int y, const Vec3fa& value) {
size_t index = y * width + x;
accu_x[index].add(value.x);
accu_y[index].add(value.y);
accu_z[index].add(value.z);
if(count)
splat_count[index].fetch_add(1, std::memory_order_relaxed);
}
void writeToFramebuffer(unsigned int* pixels) {
parallel_for(size_t(0), size_t(width * height), [&](const range<size_t>& range) {
for (size_t i = range.begin(); i < range.end(); ++i) {
pixels[i] = getPackedColor(i);
}
});
}
unsigned int getPackedColor(size_t index) const {
float divider = 1.0;
if (count) {
unsigned int count = splat_count[index].load(std::memory_order_relaxed);
if (count == 0) return 0; // Return black if no splats
divider = 1.0 / count;
}
float accu_x_val = accu_x[index] *divider* scalar;
float accu_y_val = accu_y[index] * divider* scalar;
float accu_z_val = accu_z[index] * divider* scalar;
unsigned int r = static_cast<unsigned int>(255.01f * clamp(accu_x_val, 0.0f, 1.0f));
unsigned int g = static_cast<unsigned int>(255.01f * clamp(accu_y_val, 0.0f, 1.0f));
unsigned int b = static_cast<unsigned int>(255.01f * clamp(accu_z_val, 0.0f, 1.0f));
return packColor(r, g, b);
}
unsigned int getPackedColor(int x, int y) const {
return getPackedColor(y * width + x);
}
void clear() {
parallel_for(size_t(0), size_t(width * height), [&](const range<size_t>& range) {
for (size_t i = range.begin(); i < range.end(); ++i) {
accu_x[i] = 0.0f;
accu_y[i] = 0.0f;
accu_z[i] = 0.0f;
splat_count[i].store(0, std::memory_order_relaxed);
}
});
}
float scalar = 1.0;
unsigned int width, height;
bool count = true;
private:
std::unique_ptr<AtomicFloat[]> accu_x, accu_y, accu_z;
std::unique_ptr<std::atomic<unsigned int>[]> splat_count;
};

View file

@ -9,6 +9,7 @@
#include <algorithms/parallel_for.h> #include <algorithms/parallel_for.h>
#include <scenegraph/scenegraph.h> #include <scenegraph/scenegraph.h>
#include <scenegraph/grid.h> #include <scenegraph/grid.h>
#include "film.hpp"
// #include <lights/light.h> // #include <lights/light.h>
#include "scene.hpp" #include "scene.hpp"
@ -23,6 +24,7 @@ struct Sample {
embree::Vec3fa Ns; embree::Vec3fa Ns;
}; };
struct Data { struct Data {
RenderScene* scene; RenderScene* scene;
Grid* densityGrid; Grid* densityGrid;
@ -31,25 +33,23 @@ struct Data {
int max_path_length; int max_path_length;
/* accumulation buffer */ /* accumulation buffer */
embree::Vec3ff* accu; Film film;
unsigned int accu_width;
unsigned int accu_height;
unsigned int accu_count; unsigned int accu_count;
unsigned int frame_count = 0;
RTCScene g_scene; RTCScene g_scene;
}; };
inline void Data_Constructor(Data* This, int spp, int max_path_length) { inline void Data_Constructor(Data* This, int spp, int max_path_length) {
This->g_scene = nullptr; This->g_scene = nullptr;
This->scene = nullptr; This->scene = nullptr;
This->accu = nullptr;
This->spp = spp; This->spp = spp;
This->max_path_length = max_path_length; This->max_path_length = max_path_length;
This->accu = nullptr;
This->accu_width = 0;
This->accu_height = 0;
This->accu_count = 0; This->accu_count = 0;
} }

View file

@ -0,0 +1,37 @@
#pragma once
#include <random_sampler.hpp>
namespace embree {
// Wrapper class
class RandomSamplerWrapper {
public:
RandomSampler sampler;
virtual void init(int id) {
RandomSampler_init(sampler, id);
}
virtual void init(int pixelID, int sampleID) {
RandomSampler_init(sampler, pixelID, sampleID);
}
virtual void init(int x, int y, int sampleID) {
RandomSampler_init(sampler, x, y, sampleID);
}
virtual float get1D() {
return RandomSampler_get1D(sampler);
}
virtual Vec2f get2D() {
return RandomSampler_get2D(sampler);
}
virtual Vec3fa get3D() {
return RandomSampler_get3D(sampler);
}
};
}

View file

@ -107,6 +107,37 @@ inline Vec3fa uniformSampleCone(const float cosAngle, const Vec2f &s)
return cartesian(phi, cosTheta); return cartesian(phi, cosTheta);
} }
inline float erfInv(float x) {
float w, p;
x = clamp(x, -.99999f, .99999f);
w = -std::log((1 - x) * (1 + x));
if (w < 5) {
w = w - 2.5f;
p = 2.81022636e-08f;
p = 3.43273939e-07f + p * w;
p = -3.5233877e-06f + p * w;
p = -4.39150654e-06f + p * w;
p = 0.00021858087f + p * w;
p = -0.00125372503f + p * w;
p = -0.00417768164f + p * w;
p = 0.246640727f + p * w;
p = 1.50140941f + p * w;
}
else {
w = std::sqrt(w) - 3;
p = -0.000200214257f;
p = 0.000100950558f + p * w;
p = 0.00134934322f + p * w;
p = -0.00367342844f + p * w;
p = 0.00573950773f + p * w;
p = -0.0076224613f + p * w;
p = 0.00943887047f + p * w;
p = 1.00167406f + p * w;
p = 2.83297682f + p * w;
}
return p * x;
}
inline float uniformSampleConePDF(const float cosAngle) inline float uniformSampleConePDF(const float cosAngle)
{ {
return rcp(float(two_pi)*(1.0f - cosAngle)); return rcp(float(two_pi)*(1.0f - cosAngle));

View file

@ -54,11 +54,6 @@ namespace embree
data.resize(res.x * res.y * res.z); data.resize(res.x * res.y * res.z);
file.read(reinterpret_cast<char*>(data.data()), data.size() * sizeof(float)); file.read(reinterpret_cast<char*>(data.data()), data.size() * sizeof(float));
float max = 0;
for (size_t i = 0; i < res.x * res.y * res.z; i++) {
max = std::max(data[i], max);
}
printf("max:\t%f\n", max);
file.close(); file.close();
} }

38
Framework/scenes/box2.obj Normal file
View file

@ -0,0 +1,38 @@
# Blender 4.1.1
# www.blender.org
o box
v -0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v -0.500000 -0.500000 -0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 -0.500000 0.500000
v 0.500000 0.500000 0.500000
v 0.500000 -0.500000 -0.500000
v 0.500000 0.500000 -0.500000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -1.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
s 0
f 1/1/1 2/2/1 4/3/1 3/4/1
f 3/4/2 4/3/2 8/5/2 7/6/2
f 7/6/3 8/5/3 6/7/3 5/8/3
f 5/8/4 6/7/4 2/9/4 1/10/4
f 3/11/5 7/6/5 5/8/5 1/12/5
f 8/5/6 4/13/6 2/14/6 6/7/6

View file

@ -0,0 +1,29 @@
# Blender 4.1.1 MTL File: 'None'
# www.blender.org
newmtl copper
Ns 196.513947
Ka 1.000000 1.000000 1.000000
Kd 0.800416 0.334137 0.043725
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 2.000000
d 1.000000
type metal
illum 3
newmtl white
Ka 0 0 0
Kd 1 1 1
Ks 0 0 0
newmtl oldwhite
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2

File diff suppressed because it is too large Load diff

View file

@ -1,14 +1,32 @@
newmtl white # Blender 4.1.1 MTL File: 'None'
Ka 0 0 0 # www.blender.org
Kd 1 1 1
Ks 0 0 0
newmtl green
Ka 0 0 0
Kd 0 1 0
Ks 0 0 0
newmtl blue newmtl blue
Ka 0 0 0 Ns 0.000000
Kd 0 0 1 Ka 1.000000 1.000000 1.000000
Ks 0 0 0 Kd 0.000000 0.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
newmtl green
Ns 0.000000
Ka 1.000000 1.000000 1.000000
Kd 0.000000 1.000000 0.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1
newmtl white
Ns 0.000000
Ka 1.000000 1.000000 1.000000
Kd 1.000000 1.000000 1.000000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 1

File diff suppressed because it is too large Load diff

View file

@ -185,14 +185,8 @@ void Application::deviceRender(const ISPCCamera& camera) {
} }
/* create accumulator */ /* create accumulator */
if (data.accu_width != width || data.accu_height != height) { if (data.film.width != width || data.film.height != height) {
alignedUSMFree(data.accu); data.film.init(width, height);
data.accu = (Vec3ff *) alignedUSMMalloc((width * height) * sizeof(Vec3ff), 16,
EMBREE_USM_SHARED_DEVICE_READ_WRITE);
data.accu_width = width;
data.accu_height = height;
for (unsigned int i = 0; i < width * height; i++)
data.accu[i] = Vec3ff(0.0f);
} }
/* reset accumulator */ /* reset accumulator */
@ -208,13 +202,14 @@ void Application::deviceRender(const ISPCCamera& camera) {
g_accu_p = camera.xfm.p; g_accu_p = camera.xfm.p;
if (camera_changed) { if (camera_changed) {
data.accu_count = 0; resetRender();
for (unsigned int i = 0; i < width * height; i++)
data.accu[i] = Vec3ff(0.0f);
} else } else
data.accu_count++; data.accu_count++;
data.frame_count++;
} }
void Application::renderInteractive() { void Application::renderInteractive() {
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
glfwPollEvents(); glfwPollEvents();
@ -243,6 +238,8 @@ void Application::displayFunc() {
/* render image using ISPC */ /* render image using ISPC */
initRayStats(); initRayStats();
render((int *) pixels, width, height, time, ispccamera); render((int *) pixels, width, height, time, ispccamera);
data.film.writeToFramebuffer(pixels);
double dt0 = getSeconds() - t0; double dt0 = getSeconds() - t0;
if (ispccamera.render_time != 0.0) dt0 = ispccamera.render_time; if (ispccamera.render_time != 0.0) dt0 = ispccamera.render_time;
avg_render_time.add(dt0); avg_render_time.add(dt0);
@ -270,6 +267,10 @@ void Application::displayFunc() {
ImGui::Checkbox("Accumulate", &g_accumulate); ImGui::Checkbox("Accumulate", &g_accumulate);
ImGui::InputInt("SPP", &data.spp); ImGui::InputInt("SPP", &data.spp);
if (ImGui::Button("Reset")) {
resetRender();
};
double render_dt = avg_render_time.get(); double render_dt = avg_render_time.get();
double render_fps = render_dt != 0.0 ? 1.0f / render_dt : 0.0; double render_fps = render_dt != 0.0 ? 1.0f / render_dt : 0.0;
ImGui::Text("Render: %3.2f fps", render_fps); ImGui::Text("Render: %3.2f fps", render_fps);
@ -332,27 +333,22 @@ void Application::renderTile(int taskIndex, int threadIndex, int* pixels, const
for (unsigned int y = y0; y < y1; y++) for (unsigned int y = y0; y < y1; y++)
for(unsigned int x = x0; x < x1; x++) { for(unsigned int x = x0; x < x1; x++) {
RandomSampler sampler; RandomSamplerWrapper sampler;
Vec3fa L = Vec3fa(0.0f); Vec3fa L = Vec3fa(0.0f);
for (int i=0; i<data.spp; i++) for (int i=0; i<data.spp; i++)
{ {
RandomSampler_init(sampler, x, y, data.accu_count*data.spp+i); sampler.init(x, y, (data.frame_count) * data.spp + i);
/* calculate pixel color */ /* calculate pixel color */
float fx = x + RandomSampler_get1D(sampler); float fx = x + sampler.get1D();
float fy = y + RandomSampler_get1D(sampler); float fy = y + sampler.get1D();
L = L + renderPixel(fx,fy,camera,g_stats[threadIndex],sampler); L = L + renderPixel(fx,fy,camera,g_stats[threadIndex],sampler);
} }
L = L/(float)data.spp; L = L/(float)data.spp;
/* write color to framebuffer */ /* write color to framebuffer */
Vec3ff accu_color = data.accu[y*width+x] + Vec3ff(L.x,L.y,L.z,1.0f); data.accu[y*width+x] = accu_color; data.film.addSplat(x, y, L);
float f = rcp(max(0.001f,accu_color.w));
unsigned int r = (unsigned int) (255.01f * clamp(accu_color.x*f,0.0f,1.0f));
unsigned int g = (unsigned int) (255.01f * clamp(accu_color.y*f,0.0f,1.0f));
unsigned int b = (unsigned int) (255.01f * clamp(accu_color.z*f,0.0f,1.0f));
pixels[y*width+x] = (b << 16) + (g << 8) + r;
} }
} }