Initial commit.

This commit is contained in:
hal8174 2024-04-23 10:14:24 +02:00
commit d3bb49b3f5
1073 changed files with 484757 additions and 0 deletions

View 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
};

View 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;

View 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;
};

View 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
View 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;
}

View 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
View 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;
}