301 lines
10 KiB
C++
301 lines
10 KiB
C++
#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);
|
|
lightNode->id = unsigned(lights.size()-1);
|
|
} else {
|
|
geometries.push_back(node);
|
|
if (embree::Ref<embree::SceneGraph::TriangleMeshNode> triangleMesh = node.dynamicCast<
|
|
embree::SceneGraph::TriangleMeshNode>()) {
|
|
|
|
if(triangleMesh->material)
|
|
materialID(triangleMesh->material);
|
|
|
|
if(triangleMesh->light)
|
|
lightID(triangleMesh->light);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned materialID(embree::Ref<embree::SceneGraph::MaterialNode> material) {
|
|
if (!material)
|
|
return unsigned(-1);
|
|
|
|
if (material->id == -1) {
|
|
materials.push_back(material);
|
|
material->id = unsigned(materials.size() - 1);
|
|
}
|
|
return material->id;
|
|
}
|
|
|
|
unsigned lightID(embree::Ref<embree::SceneGraph::LightNode> light) {
|
|
if (!light)
|
|
return unsigned(-1);
|
|
|
|
if (light->id == -1) {
|
|
lights.push_back(light);
|
|
light->id = unsigned(lights.size() - 1);
|
|
}
|
|
return light->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 */}; // fast compilation fix!
|
|
|
|
struct Geometry {
|
|
Geometry(Type type) : type(type), geometry(nullptr), materialID(-1), lightID(-1), visited(false) {
|
|
}
|
|
|
|
~Geometry() { if (geometry) rtcReleaseGeometry(geometry); }
|
|
Type type;
|
|
RTCGeometry geometry;
|
|
unsigned int materialID;
|
|
unsigned int lightID;
|
|
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);
|
|
geom.lightID = scene_in->lightID(in->light);
|
|
|
|
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) {
|
|
|
|
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);
|
|
}
|
|
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];
|
|
|
|
|
|
}
|
|
|
|
~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.v3-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;
|
|
}
|