Initial commit.
This commit is contained in:
commit
d3bb49b3f5
1073 changed files with 484757 additions and 0 deletions
152
Framework/include/application.h
Normal file
152
Framework/include/application.h
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
#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 <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"
|
||||
|
||||
class Application {
|
||||
public:
|
||||
Application(int argc, char** argv, const std::string& name);
|
||||
|
||||
virtual ~Application() = default;
|
||||
|
||||
void run();
|
||||
|
||||
protected:
|
||||
virtual Vec3fa renderPixel(float x, float y, const ISPCCamera& camera, RayStats& stats, RandomSampler& sampler) = 0;
|
||||
|
||||
void deviceRender(const ISPCCamera& camera);
|
||||
|
||||
virtual void drawGUI() = 0;
|
||||
|
||||
virtual void initScene() = 0;
|
||||
|
||||
void render(int* pixels, int width, int height, float time, const ISPCCamera& camera);
|
||||
|
||||
void renderTile(int taskIndex, int threadIndex, int* pixels, unsigned int width,
|
||||
unsigned int height,
|
||||
float time, const ISPCCamera& camera, int numTilesX, int numTilesY);
|
||||
|
||||
void initShader();
|
||||
|
||||
void initOpenGL();
|
||||
|
||||
void renderInteractive();
|
||||
|
||||
void displayFunc();
|
||||
|
||||
void renderOpenGl();
|
||||
|
||||
GLFWwindow* createFullScreenWindow();
|
||||
|
||||
GLFWwindow* createStandardWindow(int width, int height);
|
||||
|
||||
void setCallbackFunctions();
|
||||
|
||||
void resize(int width, int height);
|
||||
|
||||
void framebufferSizeCallback(GLFWwindow*, int width, int height);
|
||||
|
||||
void mouseCursorCallback(GLFWwindow*, double xpos, double ypos);
|
||||
|
||||
void mouseButtonCallback(GLFWwindow*, int button, int action, int mods);
|
||||
|
||||
void keyCallback(GLFWwindow*, int key, int scancode, int action, int mods);
|
||||
|
||||
void scrollCallback(GLFWwindow*, double xoffset, double yoffset);
|
||||
|
||||
void initRayStats();
|
||||
|
||||
int64_t getNumRays();
|
||||
|
||||
RTCScene convertScene(RenderScene* scene_in) {
|
||||
RTCFeatureFlags g_used_features;
|
||||
RTCScene scene_out = ConvertScene(g_device, g_render_scene, RTC_BUILD_QUALITY_MEDIUM, RTC_SCENE_FLAG_NONE,
|
||||
&g_used_features);
|
||||
|
||||
/* commit changes to scene */
|
||||
rtcCommitScene(scene_out);
|
||||
|
||||
return scene_out;
|
||||
}
|
||||
|
||||
RTCDevice g_device = nullptr;
|
||||
GLFWwindow* window;
|
||||
|
||||
unsigned int texture_id = 0;
|
||||
unsigned int shaderID = 0;
|
||||
unsigned int VAO = 0;
|
||||
unsigned int VBO = 0;
|
||||
|
||||
/* framebuffer settings */
|
||||
int width = 800;
|
||||
int height = 600;
|
||||
unsigned int* pixels = nullptr;
|
||||
|
||||
double time0;
|
||||
float render_time = 0;
|
||||
Averaged<double> avg_render_time = {64, 1.0};
|
||||
Averaged<double> avg_frame_time = {64, 1.0};
|
||||
Averaged<double> avg_mrayps = {64, 1.0};
|
||||
|
||||
Camera camera;
|
||||
|
||||
int mouseMode = 0;
|
||||
double clickX = 0;
|
||||
double clickY = 0;
|
||||
|
||||
float speed = 1;
|
||||
Vec3f moveDelta = {0, 0, 0};
|
||||
|
||||
RayStats* g_stats = nullptr;
|
||||
|
||||
Data data = {};
|
||||
RenderScene* g_render_scene = nullptr;
|
||||
|
||||
bool g_accumulate = true;
|
||||
Vec3fa g_accu_vx = Vec3fa(0.0f);
|
||||
Vec3fa g_accu_vy = Vec3fa(0.0f);
|
||||
Vec3fa g_accu_vz = Vec3fa(0.0f);
|
||||
Vec3fa g_accu_p = Vec3fa(0.0f);
|
||||
|
||||
#if defined(WORKING_DIR)
|
||||
FileName workingDir = FileName(WORKING_DIR);
|
||||
#else
|
||||
FileName workingDir = FileName();
|
||||
#endif
|
||||
};
|
||||
120
Framework/include/camera.hpp
Normal file
120
Framework/include/camera.hpp
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <sys/platform.h>
|
||||
#include <math/vec3.h>
|
||||
#include <math/affinespace.h>
|
||||
|
||||
using namespace embree;
|
||||
|
||||
/* camera settings */
|
||||
struct Camera {
|
||||
enum Handedness {
|
||||
LEFT_HANDED,
|
||||
RIGHT_HANDED
|
||||
};
|
||||
|
||||
struct ISPCCamera {
|
||||
public:
|
||||
ISPCCamera(const AffineSpace3f& xfm)
|
||||
: xfm(xfm) {
|
||||
}
|
||||
|
||||
public:
|
||||
AffineSpace3f xfm;
|
||||
float render_time = 0.0f;
|
||||
};
|
||||
|
||||
public:
|
||||
Camera()
|
||||
: from(0.0001f, 0.0001f, -3.0f), to(0, 0, 0), up(0, 1, 0), fov(90), handedness(RIGHT_HANDED) {
|
||||
}
|
||||
|
||||
Camera(const Vec3fa& from, const Vec3fa& to, const Vec3fa& up, float fov, Handedness handedness)
|
||||
: from(from), to(to), up(up), fov(fov), handedness(handedness) {
|
||||
}
|
||||
|
||||
// Camera (const SceneGraph::PerspectiveCameraData& cam, Handedness handedness)
|
||||
// : from(cam.from), to(cam.to), up(cam.up), fov(cam.fov), handedness(handedness) {}
|
||||
|
||||
std::string str() const {
|
||||
std::stringstream stream;
|
||||
stream.precision(10);
|
||||
stream << "--vp " << from.x << " " << from.y << " " << from.z << " "
|
||||
<< "--vi " << to.x << " " << to.y << " " << to.z << " "
|
||||
<< "--vu " << up.x << " " << up.y << " " << up.z << " "
|
||||
<< "--fov " << fov << " "
|
||||
<< (handedness == LEFT_HANDED ? "--lefthanded" : "--righthanded");
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
AffineSpace3fa camera2world() {
|
||||
AffineSpace3fa local2world = AffineSpace3fa::lookat(from, to, up);
|
||||
if (!(local2world == local2world))
|
||||
throw std::runtime_error("invalid camera specified");
|
||||
|
||||
if (handedness == RIGHT_HANDED)
|
||||
local2world.l.vx = -local2world.l.vx;
|
||||
|
||||
return local2world;
|
||||
}
|
||||
|
||||
AffineSpace3fa world2camera() { return rcp(camera2world()); }
|
||||
Vec3fa world2camera(const Vec3fa& p) { return xfmPoint(world2camera(), p); }
|
||||
Vec3fa camera2world(const Vec3fa& p) { return xfmPoint(camera2world(), p); }
|
||||
|
||||
ISPCCamera getISPCCamera(size_t width, size_t height) {
|
||||
const float fovScale = 1.0f / tanf(deg2rad(0.5f * fov));
|
||||
const AffineSpace3fa local2world = camera2world();
|
||||
Vec3fa vx = local2world.l.vx;
|
||||
Vec3fa vy = -local2world.l.vy;
|
||||
Vec3fa vz = -0.5f * width * local2world.l.vx + 0.5f * height * local2world.l.vy + 0.5f * height * fovScale *
|
||||
local2world.l.vz;
|
||||
Vec3fa p = local2world.p;
|
||||
return ISPCCamera(AffineSpace3f(vx, vy, vz, p));
|
||||
}
|
||||
|
||||
void move(float dx, float dy, float dz) {
|
||||
AffineSpace3fa xfm = camera2world();
|
||||
Vec3fa ds = xfmVector(xfm, Vec3fa(dx, dy, dz));
|
||||
from += ds;
|
||||
to += ds;
|
||||
}
|
||||
|
||||
void rotate(float dtheta, float dphi) {
|
||||
if (handedness == RIGHT_HANDED) dtheta *= -1.0f;
|
||||
const Vec3fa up1 = normalize(up);
|
||||
Vec3fa view1 = normalize(to - from);
|
||||
view1 = xfmVector(AffineSpace3fa::rotate(up1, dtheta), view1);
|
||||
const float phi = acosf(dot(view1, up1));
|
||||
const float dphi2 = phi - clamp(phi - dphi, 0.001f * float(pi), 0.999f * float(pi));
|
||||
view1 = xfmVector(AffineSpace3fa::rotate(cross(view1, up1), dphi2), view1);
|
||||
to = from + length(to - from) * view1;
|
||||
}
|
||||
|
||||
void rotateOrbit(float dtheta, float dphi) {
|
||||
if (handedness == RIGHT_HANDED) dtheta *= -1.0f;
|
||||
const Vec3fa up1 = normalize(up);
|
||||
Vec3fa view1 = normalize(to - from);
|
||||
view1 = xfmVector(AffineSpace3fa::rotate(up1, dtheta), view1);
|
||||
const float phi = acosf(dot(view1, up1));
|
||||
const float dphi2 = phi - clamp(phi - dphi, 0.001f * float(pi), 0.999f * float(pi));
|
||||
view1 = xfmVector(AffineSpace3fa::rotate(cross(view1, up1), dphi2), view1);
|
||||
from = to - length(to - from) * view1;
|
||||
}
|
||||
|
||||
void dolly(float ds) {
|
||||
float dollySpeed = 0.01f;
|
||||
float k = powf((1.0f - dollySpeed), ds);
|
||||
from += length(to - from) * (1 - k) * normalize(to - from);
|
||||
}
|
||||
|
||||
public:
|
||||
Vec3fa from; //!< position of camera
|
||||
Vec3fa to; //!< look at point
|
||||
Vec3fa up; //!< up vector
|
||||
float fov; //!< field of view
|
||||
Handedness handedness;
|
||||
};
|
||||
|
||||
typedef Camera::ISPCCamera ISPCCamera;
|
||||
97
Framework/include/helper.hpp
Normal file
97
Framework/include/helper.hpp
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
||||
#include <sys/sysinfo.h>
|
||||
#include <embree4/rtcore.h>
|
||||
#include <lexers/parsestream.h>
|
||||
#include <algorithms/parallel_for.h>
|
||||
#include <scenegraph/scenegraph.h>
|
||||
|
||||
// #include <lights/light.h>
|
||||
|
||||
#include "scene.hpp"
|
||||
|
||||
/* size of screen tiles */
|
||||
#define TILE_SIZE_X 8
|
||||
#define TILE_SIZE_Y 8
|
||||
|
||||
struct Sample {
|
||||
embree::Vec3fa P;
|
||||
embree::Vec3fa Ng;
|
||||
embree::Vec3fa Ns;
|
||||
};
|
||||
|
||||
struct Data {
|
||||
RenderScene* scene;
|
||||
int spp;
|
||||
int max_path_length;
|
||||
|
||||
/* accumulation buffer */
|
||||
embree::Vec3ff* accu;
|
||||
unsigned int accu_width;
|
||||
unsigned int accu_height;
|
||||
unsigned int accu_count;
|
||||
|
||||
RTCScene g_scene;
|
||||
};
|
||||
|
||||
inline void Data_Constructor(Data* This, int spp, int max_path_length) {
|
||||
This->g_scene = nullptr;
|
||||
This->scene = nullptr;
|
||||
This->accu = nullptr;
|
||||
|
||||
This->spp = spp;
|
||||
This->max_path_length = max_path_length;
|
||||
|
||||
This->accu = nullptr;
|
||||
This->accu_width = 0;
|
||||
This->accu_height = 0;
|
||||
This->accu_count = 0;
|
||||
}
|
||||
|
||||
inline void Data_Destructor(Data* This) {
|
||||
rtcReleaseScene(This->g_scene);
|
||||
This->g_scene = nullptr;
|
||||
}
|
||||
|
||||
struct RayStats {
|
||||
int numRays;
|
||||
int pad[32 - 1];
|
||||
};
|
||||
|
||||
__forceinline void RayStats_addRay(RayStats &stats) { stats.numRays++; }
|
||||
__forceinline void RayStats_addShadowRay(RayStats &stats) { stats.numRays++; }
|
||||
|
||||
template<typename Ty>
|
||||
struct Averaged {
|
||||
Averaged(size_t N, double dt)
|
||||
: N(N), dt(dt) {
|
||||
}
|
||||
|
||||
void add(double v) {
|
||||
values.push_front(std::make_pair(embree::getSeconds(), v));
|
||||
if (values.size() > N) values.resize(N);
|
||||
}
|
||||
|
||||
Ty get() const {
|
||||
if (values.size() == 0) return embree::zero;
|
||||
double t_begin = values[0].first - dt;
|
||||
|
||||
Ty sum(embree::zero);
|
||||
size_t num(0);
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
if (values[i].first >= t_begin) {
|
||||
sum += values[i].second;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
if (num == 0) return 0;
|
||||
else return sum / Ty(num);
|
||||
}
|
||||
|
||||
std::deque<std::pair<double, Ty>> values;
|
||||
size_t N;
|
||||
double dt;
|
||||
};
|
||||
114
Framework/include/random_sampler.hpp
Normal file
114
Framework/include/random_sampler.hpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
// Copyright 2009-2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math/vec.h>
|
||||
|
||||
namespace embree {
|
||||
|
||||
struct RandomSampler
|
||||
{
|
||||
unsigned int s;
|
||||
};
|
||||
|
||||
__forceinline unsigned int MurmurHash3_mix(unsigned int hash, unsigned int k)
|
||||
{
|
||||
const unsigned int c1 = 0xcc9e2d51;
|
||||
const unsigned int c2 = 0x1b873593;
|
||||
const unsigned int r1 = 15;
|
||||
const unsigned int r2 = 13;
|
||||
const unsigned int m = 5;
|
||||
const unsigned int n = 0xe6546b64;
|
||||
|
||||
k *= c1;
|
||||
k = (k << r1) | (k >> (32 - r1));
|
||||
k *= c2;
|
||||
|
||||
hash ^= k;
|
||||
hash = ((hash << r2) | (hash >> (32 - r2))) * m + n;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
__forceinline unsigned int MurmurHash3_finalize(unsigned int hash)
|
||||
{
|
||||
hash ^= hash >> 16;
|
||||
hash *= 0x85ebca6b;
|
||||
hash ^= hash >> 13;
|
||||
hash *= 0xc2b2ae35;
|
||||
hash ^= hash >> 16;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
__forceinline unsigned int LCG_next(unsigned int value)
|
||||
{
|
||||
const unsigned int m = 1664525;
|
||||
const unsigned int n = 1013904223;
|
||||
|
||||
return value * m + n;
|
||||
}
|
||||
|
||||
__forceinline void RandomSampler_init(RandomSampler& self, int id)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
hash = MurmurHash3_mix(hash, id);
|
||||
hash = MurmurHash3_finalize(hash);
|
||||
|
||||
self.s = hash;
|
||||
}
|
||||
|
||||
__forceinline void RandomSampler_init(RandomSampler& self, int pixelId, int sampleId)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
hash = MurmurHash3_mix(hash, pixelId);
|
||||
hash = MurmurHash3_mix(hash, sampleId);
|
||||
hash = MurmurHash3_finalize(hash);
|
||||
|
||||
self.s = hash;
|
||||
}
|
||||
|
||||
__forceinline void RandomSampler_init(RandomSampler& self, int x, int y, int sampleId)
|
||||
{
|
||||
RandomSampler_init(self, x | (y << 16), sampleId);
|
||||
}
|
||||
|
||||
__forceinline int RandomSampler_getInt(RandomSampler& self) {
|
||||
self.s = LCG_next(self.s); return self.s >> 1;
|
||||
}
|
||||
|
||||
__forceinline unsigned int RandomSampler_getUInt(RandomSampler& self) {
|
||||
self.s = LCG_next(self.s); return self.s;
|
||||
}
|
||||
|
||||
__forceinline float RandomSampler_getFloat(RandomSampler& self) {
|
||||
return (float)RandomSampler_getInt(self) * 4.656612873077392578125e-10f;
|
||||
}
|
||||
|
||||
__forceinline float RandomSampler_get1D(RandomSampler& self) {
|
||||
return RandomSampler_getFloat(self);
|
||||
}
|
||||
|
||||
__forceinline Vec2f RandomSampler_get2D(RandomSampler& self)
|
||||
{
|
||||
const float u = RandomSampler_get1D(self);
|
||||
const float v = RandomSampler_get1D(self);
|
||||
return Vec2f(u,v);
|
||||
}
|
||||
|
||||
__forceinline Vec3fa RandomSampler_get3D(RandomSampler& self)
|
||||
{
|
||||
/*
|
||||
const float u = RandomSampler_get1D(self);
|
||||
const float v = RandomSampler_get1D(self);
|
||||
const float w = RandomSampler_get1D(self);
|
||||
return Vec3fa(u,v,w);
|
||||
*/
|
||||
const int u = RandomSampler_getUInt(self);
|
||||
const int v = RandomSampler_getUInt(self);
|
||||
const int w = RandomSampler_getUInt(self);
|
||||
return Vec3fa(srl(Vec3ia(u,v,w), 1)) * 4.656612873077392578125e-10f;
|
||||
}
|
||||
|
||||
} // namespace embree
|
||||
144
Framework/include/ray.hpp
Normal file
144
Framework/include/ray.hpp
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
// Copyright 2009-2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/platform.h>
|
||||
#include <sys/ref.h>
|
||||
#include <sys/intrinsics.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/atomic.h>
|
||||
#include <sys/vector.h>
|
||||
#include <sys/estring.h>
|
||||
|
||||
#include <math/emath.h>
|
||||
#include <math/vec2.h>
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
#include <math/bbox.h>
|
||||
#include <math/affinespace.h>
|
||||
|
||||
#include <simd/simd.h>
|
||||
|
||||
/*! Ray structure. */
|
||||
struct __aligned(16) Ray
|
||||
{
|
||||
/*! Default construction does nothing. */
|
||||
__forceinline Ray() {}
|
||||
|
||||
/*! Constructs a ray from origin, direction, and ray segment. Near
|
||||
* has to be smaller than far. */
|
||||
__forceinline Ray(const embree::Vec3fa& org,
|
||||
const embree::Vec3fa& dir,
|
||||
float tnear = 0.0f,
|
||||
float tfar = embree::inf,
|
||||
float time = 0.0f,
|
||||
int mask = -1,
|
||||
unsigned int geomID = RTC_INVALID_GEOMETRY_ID,
|
||||
unsigned int primID = RTC_INVALID_GEOMETRY_ID)
|
||||
: org(org,tnear), dir(dir,time), tfar(tfar), mask(mask), primID(primID), geomID(geomID)
|
||||
{
|
||||
instID[0] = RTC_INVALID_GEOMETRY_ID;
|
||||
#if defined(RTC_GEOMETRY_INSTANCE_ARRAY)
|
||||
instPrimID[0] = RTC_INVALID_GEOMETRY_ID;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*! Tests if we hit something. */
|
||||
__forceinline operator bool() const { return geomID != RTC_INVALID_GEOMETRY_ID; }
|
||||
|
||||
public:
|
||||
embree::Vec3ff org; //!< Ray origin + tnear
|
||||
//float tnear; //!< Start of ray segment
|
||||
embree::Vec3ff dir; //!< Ray direction + tfar
|
||||
//float time; //!< Time of this ray for motion blur.
|
||||
float tfar; //!< End of ray segment
|
||||
unsigned int mask; //!< used to mask out objects during traversal
|
||||
unsigned int id; //!< ray ID
|
||||
unsigned int flags; //!< ray flags
|
||||
|
||||
public:
|
||||
embree::Vec3f Ng; //!< Not normalized geometry normal
|
||||
float u; //!< Barycentric u coordinate of hit
|
||||
float v; //!< Barycentric v coordinate of hit
|
||||
unsigned int primID; //!< primitive ID
|
||||
unsigned int geomID; //!< geometry ID
|
||||
unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; //!< instance ID
|
||||
#if defined(RTC_GEOMETRY_INSTANCE_ARRAY)
|
||||
unsigned int instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT]; //!< instance primitive ID
|
||||
#endif
|
||||
|
||||
__forceinline float &tnear() { return org.w; };
|
||||
__forceinline float &time() { return dir.w; };
|
||||
__forceinline float const &tnear() const { return org.w; };
|
||||
__forceinline float const &time() const { return dir.w; };
|
||||
|
||||
};
|
||||
|
||||
|
||||
__forceinline void init_Ray(Ray &ray,
|
||||
const embree::Vec3fa& org,
|
||||
const embree::Vec3fa& dir,
|
||||
float tnear = 0.0f,
|
||||
float tfar = embree::inf,
|
||||
float time = 0.0f,
|
||||
int mask = -1,
|
||||
unsigned int geomID = RTC_INVALID_GEOMETRY_ID,
|
||||
unsigned int primID = RTC_INVALID_GEOMETRY_ID)
|
||||
{
|
||||
ray = Ray(org,dir,tnear,tfar,time,mask,geomID,primID);
|
||||
}
|
||||
|
||||
typedef Ray Ray1;
|
||||
|
||||
__forceinline RTCRayHit* RTCRayHit_(Ray& ray) {
|
||||
return (RTCRayHit*)&ray;
|
||||
}
|
||||
|
||||
__forceinline RTCRayHit* RTCRayHit1_(Ray& ray) {
|
||||
return (RTCRayHit*)&ray;
|
||||
}
|
||||
|
||||
__forceinline RTCRay* RTCRay_(Ray& ray) {
|
||||
return (RTCRay*)&ray;
|
||||
}
|
||||
|
||||
__forceinline RTCHit* RTCHit_(Ray& ray)
|
||||
{
|
||||
RTCHit* hit_ptr = (RTCHit*)&(ray.Ng.x);
|
||||
return hit_ptr;
|
||||
}
|
||||
|
||||
__forceinline RTCRay* RTCRay1_(Ray& ray) {
|
||||
return (RTCRay*)&ray;
|
||||
}
|
||||
|
||||
/*! Outputs ray to stream. */
|
||||
__forceinline embree_ostream operator<<(embree_ostream cout, const Ray& ray)
|
||||
{
|
||||
cout << "{ " <<
|
||||
"org = " << ray.org << ", dir = " << ray.dir << ", near = " << ray.tnear() << ", far = " << ray.tfar << ", time = " << ray.time() << ", ";
|
||||
|
||||
for (size_t i=0; i<RTC_MAX_INSTANCE_LEVEL_COUNT; i++)
|
||||
cout << "instID" << i << " = " << ray.instID[i] << ", ";
|
||||
#if defined(RTC_GEOMETRY_INSTANCE_ARRAY)
|
||||
for (size_t i=0; i<RTC_MAX_INSTANCE_LEVEL_COUNT; i++)
|
||||
cout << "instPrimID" << i << " = " << ray.instPrimID[i] << ", ";
|
||||
#endif
|
||||
|
||||
return cout << "geomID = " << ray.geomID << ", primID = " << ray.primID << ", " << "u = " << ray.u << ", v = " << ray.v << ", Ng = " << ray.Ng << " }";
|
||||
}
|
||||
|
||||
/*! ray query context passed to intersect/occluded calls */
|
||||
struct RayQueryContext
|
||||
{
|
||||
RTCRayQueryContext context;
|
||||
void* userRayExt; //!< can be used to pass extended ray data to callbacks
|
||||
void* tutorialData;
|
||||
};
|
||||
|
||||
__forceinline void InitIntersectionContext(struct RayQueryContext* context)
|
||||
{
|
||||
rtcInitRayQueryContext(&context->context);
|
||||
context->userRayExt = NULL;
|
||||
}
|
||||
159
Framework/include/sampling.hpp
Normal file
159
Framework/include/sampling.hpp
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
// Copyright 2009-2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
/*! \brief utility library containing sampling functions */
|
||||
|
||||
// convention is to return the sample (Vec3fa) generated from given Vec2f 's'ample as last parameter
|
||||
// sampling functions often come in pairs: sample and pdf (needed later for MIS)
|
||||
// good reference is "Total Compendium" by Philip Dutre http://people.cs.kuleuven.be/~philip.dutre/GI/
|
||||
|
||||
#include <math/vec.h>
|
||||
#include <math/linearspace3.h>
|
||||
|
||||
namespace embree {
|
||||
|
||||
struct Sample3f
|
||||
{
|
||||
Vec3fa v;
|
||||
float pdf;
|
||||
};
|
||||
|
||||
inline Sample3f make_Sample3f(const Vec3fa& v, const float pdf) {
|
||||
Sample3f s; s.v = v; s.pdf = pdf; return s;
|
||||
}
|
||||
|
||||
#if defined(ISPC)
|
||||
inline Sample3f make_Sample3f(const Vec3fa& v, const float pdf) {
|
||||
Sample3f s; s.v = v; s.pdf = pdf; return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline Vec3fa cartesian(const float phi, const float sinTheta, const float cosTheta)
|
||||
{
|
||||
const float sinPhi = sinf(phi);
|
||||
const float cosPhi = cosf(phi);
|
||||
//sincosf(phi, &sinPhi, &cosPhi);
|
||||
return Vec3fa(cosPhi * sinTheta,
|
||||
sinPhi * sinTheta,
|
||||
cosTheta);
|
||||
}
|
||||
|
||||
inline Vec3fa cartesian(const float phi, const float cosTheta)
|
||||
{
|
||||
return cartesian(phi, cos2sin(cosTheta), cosTheta);
|
||||
}
|
||||
|
||||
|
||||
/// cosine-weighted sampling of hemisphere oriented along the +z-axis
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline Vec3fa cosineSampleHemisphere(const Vec2f s)
|
||||
{
|
||||
const float phi = 2.0f * float(M_PI) * s.x;
|
||||
const float cosTheta = sqrt(s.y);
|
||||
const float sinTheta = sqrt(1.0f - s.y);
|
||||
return cartesian(phi, sinTheta, cosTheta);
|
||||
}
|
||||
|
||||
inline float cosineSampleHemispherePDF(const Vec3fa &dir)
|
||||
{
|
||||
return dir.z / float(M_PI);
|
||||
}
|
||||
|
||||
inline float cosineSampleHemispherePDF(float cosTheta)
|
||||
{
|
||||
return cosTheta / float(M_PI);
|
||||
}
|
||||
|
||||
/*! Cosine weighted hemisphere sampling. Up direction is provided as argument. */
|
||||
inline Sample3f cosineSampleHemisphere(const float u, const float v, const Vec3fa& N)
|
||||
{
|
||||
Vec3fa localDir = cosineSampleHemisphere(Vec2f(u,v));
|
||||
Sample3f s;
|
||||
s.v = frame(N) * localDir;
|
||||
s.pdf = cosineSampleHemispherePDF(localDir);
|
||||
return s;
|
||||
}
|
||||
|
||||
/// power cosine-weighted sampling of hemisphere oriented along the +z-axis
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline Vec3fa powerCosineSampleHemisphere(const float n, const Vec2f &s)
|
||||
{
|
||||
const float phi =float(two_pi) * s.x;
|
||||
const float cosTheta = pow(s.y, 1.0f / (n + 1.0f));
|
||||
return cartesian(phi, cosTheta);
|
||||
}
|
||||
|
||||
inline float powerCosineSampleHemispherePDF(const float cosTheta, const float n) // TODO: order of arguments
|
||||
{
|
||||
return (n + 1.0f) * (0.5f / float(M_PI)) * pow(cosTheta, n);
|
||||
}
|
||||
|
||||
inline float powerCosineSampleHemispherePDF(const Vec3fa& dir, const float n) // TODO: order of arguments
|
||||
{
|
||||
return (n + 1.0f) * (0.5f / float(M_PI)) * pow(dir.z, n);
|
||||
}
|
||||
|
||||
/// sampling of cone of directions oriented along the +z-axis
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline Vec3fa uniformSampleCone(const float cosAngle, const Vec2f &s)
|
||||
{
|
||||
const float phi =float(two_pi) * s.x;
|
||||
const float cosTheta = 1.0f - s.y * (1.0f - cosAngle);
|
||||
return cartesian(phi, cosTheta);
|
||||
}
|
||||
|
||||
inline float uniformSampleConePDF(const float cosAngle)
|
||||
{
|
||||
return rcp(float(two_pi)*(1.0f - cosAngle));
|
||||
}
|
||||
|
||||
inline float _uniformSampleConePDF(const float cosAngle)
|
||||
{
|
||||
return rcp(float(two_pi)*(1.0f - cosAngle));
|
||||
}
|
||||
|
||||
|
||||
/// sampling of disk
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline Vec3fa uniformSampleDisk(const float radius, const Vec2f &s)
|
||||
{
|
||||
const float r = sqrtf(s.x) * radius;
|
||||
const float phi =float(two_pi) * s.y;
|
||||
const float sinPhi = sinf(phi);
|
||||
const float cosPhi = cosf(phi);
|
||||
//sincosf(phi, &sinPhi, &cosPhi);
|
||||
return Vec3fa(r * cosPhi, r * sinPhi, 0.f);
|
||||
}
|
||||
|
||||
inline float uniformSampleDiskPDF(const float radius)
|
||||
{
|
||||
return rcp(float(M_PI) * sqr(radius));
|
||||
}
|
||||
|
||||
inline float _uniformSampleDiskPDF(const float radius)
|
||||
{
|
||||
return rcp(float(M_PI) * sqr(radius));
|
||||
}
|
||||
|
||||
|
||||
/// sampling of triangle abc
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline Vec3fa uniformSampleTriangle(const Vec3fa &a, const Vec3fa &b, const Vec3fa &c, const Vec2f &s)
|
||||
{
|
||||
const float su = sqrtf(s.x);
|
||||
return c + (1.0f - su) * (a-c) + (s.y*su) * (b-c);
|
||||
}
|
||||
|
||||
inline float uniformSampleTrianglePDF(const Vec3fa &a, const Vec3fa &b, const Vec3fa &c)
|
||||
{
|
||||
return 2.0f * rcp(abs(length(cross(a-c, b-c))));
|
||||
}
|
||||
|
||||
} // namespace embree
|
||||
275
Framework/include/scene.hpp
Normal file
275
Framework/include/scene.hpp
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
#pragma once
|
||||
// #include <lights/light.h>
|
||||
#include <sampling.hpp>
|
||||
#include <vector>
|
||||
#include <scenegraph/scenegraph.h>
|
||||
|
||||
#include "lights/ambient_light.h"
|
||||
#include "lights/directional_light.h"
|
||||
#include "lights/point_light.h"
|
||||
#include "lights/quad_light.h"
|
||||
|
||||
namespace embree {
|
||||
struct Light;
|
||||
}
|
||||
|
||||
using namespace embree;
|
||||
|
||||
struct Scene {
|
||||
Scene() {
|
||||
}
|
||||
|
||||
~Scene() {
|
||||
}
|
||||
|
||||
void add(embree::Ref<embree::SceneGraph::GroupNode> group) {
|
||||
for (auto& node: group->children) {
|
||||
if (embree::Ref<embree::SceneGraph::LightNode> lightNode = node.dynamicCast<
|
||||
embree::SceneGraph::LightNode>()) {
|
||||
lights.push_back(lightNode);
|
||||
} else {
|
||||
geometries.push_back(node);
|
||||
if (embree::Ref<embree::SceneGraph::TriangleMeshNode> triangleMesh = node.dynamicCast<
|
||||
embree::SceneGraph::TriangleMeshNode>()) {
|
||||
materialID(triangleMesh->material);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned materialID(embree::Ref<embree::SceneGraph::MaterialNode> material) {
|
||||
if (material->id == -1) {
|
||||
materials.push_back(material);
|
||||
material->id = unsigned(materials.size() - 1);
|
||||
}
|
||||
return material->id;
|
||||
}
|
||||
|
||||
std::vector<embree::Ref<embree::SceneGraph::MaterialNode> > materials; //!< list of materials
|
||||
std::vector<embree::Ref<embree::SceneGraph::Node> > geometries; //!< list of geometries
|
||||
std::vector<embree::Ref<embree::SceneGraph::LightNode> > lights; //!< list of lights
|
||||
};
|
||||
|
||||
enum Type { TRIANGLE_MESH, SUBDIV_MESH, CURVES, INSTANCE, INSTANCE_ARRAY, GROUP, QUAD_MESH, GRID_MESH, POINTS };
|
||||
|
||||
struct Geometry {
|
||||
Geometry(Type type) : type(type), geometry(nullptr), materialID(-1), visited(false) {
|
||||
}
|
||||
|
||||
~Geometry() { if (geometry) rtcReleaseGeometry(geometry); }
|
||||
Type type;
|
||||
RTCGeometry geometry;
|
||||
unsigned int materialID;
|
||||
bool visited;
|
||||
};
|
||||
|
||||
struct TriangleMesh {
|
||||
// ALIGNED_STRUCT_USM_(16);
|
||||
|
||||
TriangleMesh(RTCDevice device, unsigned int numTriangles, unsigned int numPositions, bool hasNormals,
|
||||
bool hasTexcoords): geom(TRIANGLE_MESH) {
|
||||
geom.geometry = rtcNewGeometry(device, RTC_GEOMETRY_TYPE_TRIANGLE);
|
||||
|
||||
positions = std::vector<Vec3fa>(numPositions);
|
||||
|
||||
if (hasNormals) {
|
||||
normals = std::vector<Vec3fa>(numPositions);
|
||||
}
|
||||
|
||||
if (hasTexcoords)
|
||||
texcoords = std::vector<Vec2f>(numPositions);
|
||||
|
||||
triangles = std::vector<SceneGraph::TriangleMeshNode::Triangle>(numTriangles);
|
||||
}
|
||||
|
||||
TriangleMesh(RTCDevice device, Scene* scene_in, Ref<SceneGraph::TriangleMeshNode> in): geom(TRIANGLE_MESH) {
|
||||
geom.geometry = rtcNewGeometry(device, RTC_GEOMETRY_TYPE_TRIANGLE);
|
||||
|
||||
positions = std::vector<Vec3fa>(0);
|
||||
for (auto& pos: in->positions[0])
|
||||
positions.push_back(pos);
|
||||
|
||||
if (in->normals.size()) {
|
||||
normals = std::vector<Vec3fa>(0);
|
||||
for (auto& normal: in->normals[0])
|
||||
normals.push_back(normal);
|
||||
}
|
||||
|
||||
texcoords = in->texcoords;
|
||||
|
||||
geom.materialID = scene_in->materialID(in->material);
|
||||
|
||||
triangles = in->triangles;
|
||||
}
|
||||
|
||||
~TriangleMesh() {
|
||||
positions.clear();
|
||||
normals.clear();
|
||||
texcoords.clear();
|
||||
triangles.clear();
|
||||
}
|
||||
|
||||
void commit() {
|
||||
RTCGeometry g = geom.geometry;
|
||||
|
||||
rtcSetSharedGeometryBuffer(g, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, positions.data(), 0,
|
||||
sizeof(SceneGraph::TriangleMeshNode::Vertex), positions.size());
|
||||
|
||||
rtcSetSharedGeometryBuffer(g, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, triangles.data(), 0,
|
||||
sizeof(SceneGraph::TriangleMeshNode::Triangle), triangles.size());
|
||||
rtcSetGeometryUserData(g, this);
|
||||
|
||||
rtcCommitGeometry(g);
|
||||
}
|
||||
|
||||
Geometry geom;
|
||||
std::vector<Vec3fa> positions; //!< vertex position array
|
||||
std::vector<Vec3fa> normals; //!< vertex normal array
|
||||
std::vector<Vec2f> texcoords; //!< vertex texcoord array
|
||||
std::vector<SceneGraph::TriangleMeshNode::Triangle> triangles; //!< list of triangles
|
||||
};
|
||||
|
||||
|
||||
struct RenderScene {
|
||||
RenderScene(RTCDevice device, unsigned int numGeometries, unsigned int numMaterials,
|
||||
unsigned int numLights): scene(rtcNewScene(device)), dataScene(nullptr) {
|
||||
geometries = std::vector<Geometry *>(numGeometries);
|
||||
materials = std::vector<Material *>(numMaterials);
|
||||
lights = std::vector<Light *>(numLights);
|
||||
}
|
||||
|
||||
RenderScene(RTCDevice device, Scene* in): scene(rtcNewScene(device)), dataScene(in) {
|
||||
geometries = std::vector<Geometry *>(in->geometries.size());
|
||||
for (size_t i = 0; i < in->geometries.size(); i++)
|
||||
geometries[i] = convertGeometry(device, in, in->geometries[i]);
|
||||
|
||||
materials = std::vector<Material *>(in->materials.size());
|
||||
for (size_t i = 0; i < in->materials.size(); i++) {
|
||||
// auto test = in->materials[i].ptr;
|
||||
auto mat = (Material*)in->materials[i].ptr;
|
||||
auto material = in->materials[i]->material();
|
||||
mat->type = material->type;
|
||||
// auto align = material->align;
|
||||
// mat->align[0] = align[0];
|
||||
// mat->align[1] = align[1];
|
||||
// mat->align[2] = align[2];
|
||||
materials[i] = mat;
|
||||
}
|
||||
|
||||
|
||||
auto test = (OBJMaterial*) materials[0];
|
||||
|
||||
lights = std::vector<Light *>(0);
|
||||
for (size_t i = 0; i < in->lights.size(); i++) {
|
||||
Light* light = convertLight(in->lights[i]->get(0.0f));
|
||||
if (light)
|
||||
lights.push_back(light);
|
||||
}
|
||||
}
|
||||
|
||||
~RenderScene() {
|
||||
geometries.clear();
|
||||
materials.clear();
|
||||
lights.clear();
|
||||
}
|
||||
|
||||
void commit() {
|
||||
for (unsigned int geomID = 0; geomID < geometries.size(); geomID++) {
|
||||
Geometry* geometry = geometries[geomID];
|
||||
rtcAttachGeometryByID(scene, geometry->geometry, geomID);
|
||||
}
|
||||
|
||||
rtcCommitScene(scene);
|
||||
}
|
||||
|
||||
static Geometry* convertGeometry(RTCDevice device, Scene* scene, Ref<SceneGraph::Node> in) {
|
||||
Geometry* geom = nullptr;
|
||||
if (in->geometry)
|
||||
return (Geometry *) in->geometry;
|
||||
else if (Ref<SceneGraph::TriangleMeshNode> mesh = in.dynamicCast<SceneGraph::TriangleMeshNode>())
|
||||
geom = (Geometry *) new TriangleMesh(device, scene, mesh);
|
||||
else
|
||||
THROW_RUNTIME_ERROR("unknown geometry type");
|
||||
|
||||
in->geometry = geom;
|
||||
return geom;
|
||||
}
|
||||
|
||||
static Light* convertLight(Ref<SceneGraph::LightNode> in) {
|
||||
Light* l = createLight(in);
|
||||
updateLight(in->get(0.0f), l);
|
||||
return l;
|
||||
}
|
||||
|
||||
static Light* createLight(Ref<SceneGraph::LightNode> in) {
|
||||
switch (in->getType()) {
|
||||
case SceneGraph::LIGHT_AMBIENT: return (Light *) AmbientLight_create();
|
||||
case SceneGraph::LIGHT_DIRECTIONAL: return (Light *) DirectionalLight_create();
|
||||
case SceneGraph::LIGHT_DISTANT: return (Light *) DirectionalLight_create();
|
||||
case SceneGraph::LIGHT_POINT: return (Light *) PointLight_create();
|
||||
case SceneGraph::LIGHT_SPOT: return nullptr;
|
||||
case SceneGraph::LIGHT_TRIANGLE: return nullptr;
|
||||
case SceneGraph::LIGHT_QUAD: return (Light *) QuadLight_create();
|
||||
default: THROW_RUNTIME_ERROR("unknown light type");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void updateLight(const Ref<SceneGraph::LightNode>& in, Light* out) {
|
||||
if (auto light = in.dynamicCast<SceneGraph::LightNodeImpl<SceneGraph::AmbientLight> >())
|
||||
AmbientLight_set(out, light->light.L);
|
||||
else if (auto light = in.dynamicCast<SceneGraph::LightNodeImpl<SceneGraph::DirectionalLight> >())
|
||||
DirectionalLight_set(out, -normalize(light->light.D), light->light.E, 1.0f);
|
||||
else if (auto light = in.dynamicCast<SceneGraph::LightNodeImpl<SceneGraph::DistantLight> >())
|
||||
DirectionalLight_set(out, -normalize(light->light.D),
|
||||
light->light.L * rcp(uniformSampleConePDF(light->light.cosHalfAngle)),
|
||||
light->light.cosHalfAngle);
|
||||
else if (auto light = in.dynamicCast<SceneGraph::LightNodeImpl<SceneGraph::PointLight> >())
|
||||
PointLight_set(out, light->light.P, light->light.I, 0.f);
|
||||
else if (auto light = in.dynamicCast<SceneGraph::LightNodeImpl<SceneGraph::QuadLight> >())
|
||||
QuadLight_set(out, light->light.v0,light->light.v1-light->light.v0,light->light.v2-light->light.v0,light->light.L);
|
||||
}
|
||||
|
||||
RTCScene scene;
|
||||
std::vector<Geometry *> geometries; //!< list of geometries
|
||||
std::vector<Material *> materials; //!< material list
|
||||
std::vector<Light *> lights; //!< list of lights
|
||||
void* dataScene;
|
||||
};
|
||||
|
||||
inline void ConvertTriangleMesh(RTCDevice device, TriangleMesh* mesh, RTCBuildQuality quality, RTCSceneFlags flags,
|
||||
RTCFeatureFlags& used_features) {
|
||||
if (mesh->geom.visited) return;
|
||||
|
||||
used_features = RTC_FEATURE_FLAG_TRIANGLE;
|
||||
|
||||
mesh->geom.visited = true;
|
||||
rtcSetGeometryBuildQuality(mesh->geom.geometry, quality);
|
||||
mesh->commit();
|
||||
}
|
||||
|
||||
extern "C" inline RTCScene ConvertScene(RTCDevice g_device, RenderScene* scene_in, RTCBuildQuality quality,
|
||||
RTCSceneFlags flags, RTCFeatureFlags* used_features_out) {
|
||||
Scene* tutorial_scene = (Scene *) scene_in->dataScene;
|
||||
if (!tutorial_scene) return scene_in->scene;
|
||||
|
||||
RTCFeatureFlags used_features = RTC_FEATURE_FLAG_NONE;
|
||||
|
||||
RTCScene scene = scene_in->scene;
|
||||
rtcSetSceneFlags(scene, flags);
|
||||
|
||||
for (unsigned int geomID = 0; geomID < scene_in->geometries.size(); geomID++) {
|
||||
Geometry* geometry = scene_in->geometries[geomID];
|
||||
if (geometry->type == TRIANGLE_MESH)
|
||||
ConvertTriangleMesh(g_device, (TriangleMesh *) geometry, quality, flags, used_features);
|
||||
else
|
||||
assert(false);
|
||||
|
||||
rtcAttachGeometryByID(scene, geometry->geometry, geomID);
|
||||
}
|
||||
|
||||
if (used_features_out)
|
||||
*used_features_out = used_features;
|
||||
|
||||
return scene;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue