rendering-in-cgi/Framework/include/scene.hpp
2024-05-14 11:47:15 +02:00

298 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;
enum Type { TRIANGLE_MESH, SUBDIV_MESH, CURVES, INSTANCE, INSTANCE_ARRAY, GROUP, QUAD_MESH, GRID_MESH , POINTS };
}
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
};
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;
}
}
~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;
}