#pragma once // #include #include #include #include #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 group) { for (auto& node: group->children) { if (embree::Ref lightNode = node.dynamicCast< embree::SceneGraph::LightNode>()) { lights.push_back(lightNode); lightNode->id = unsigned(lights.size()-1); } else { geometries.push_back(node); if (embree::Ref triangleMesh = node.dynamicCast< embree::SceneGraph::TriangleMeshNode>()) { if(triangleMesh->material) materialID(triangleMesh->material); if(triangleMesh->light) lightID(triangleMesh->light); } } } } unsigned materialID(embree::Ref 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 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 > materials; //!< list of materials std::vector > geometries; //!< list of geometries std::vector > 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(numPositions); if (hasNormals) { normals = std::vector(numPositions); } if (hasTexcoords) texcoords = std::vector(numPositions); triangles = std::vector(numTriangles); } TriangleMesh(RTCDevice device, Scene* scene_in, Ref in): geom(TRIANGLE_MESH) { geom.geometry = rtcNewGeometry(device, RTC_GEOMETRY_TYPE_TRIANGLE); positions = std::vector(0); for (auto& pos: in->positions[0]) positions.push_back(pos); if (in->normals.size()) { normals = std::vector(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 positions; //!< vertex position array std::vector normals; //!< vertex normal array std::vector texcoords; //!< vertex texcoord array std::vector 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(numGeometries); materials = std::vector(numMaterials); lights = std::vector(numLights); } RenderScene(RTCDevice device, Scene* in): scene(rtcNewScene(device)), dataScene(in) { lights = std::vector(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(in->geometries.size()); for (size_t i = 0; i < in->geometries.size(); i++) geometries[i] = convertGeometry(device, in, in->geometries[i]); materials = std::vector(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 in) { Geometry* geom = nullptr; if (in->geometry) return (Geometry *) in->geometry; else if (Ref mesh = in.dynamicCast()) geom = (Geometry *) new TriangleMesh(device, scene, mesh); else THROW_RUNTIME_ERROR("unknown geometry type"); in->geometry = geom; return geom; } static Light* convertLight(Ref in) { Light* l = createLight(in); updateLight(in->get(0.0f), l); return l; } static Light* createLight(Ref 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& in, Light* out) { if (auto light = in.dynamicCast >()) AmbientLight_set(out, light->light.L); else if (auto light = in.dynamicCast >()) DirectionalLight_set(out, -normalize(light->light.D), light->light.E, 1.0f); else if (auto light = in.dynamicCast >()) DirectionalLight_set(out, -normalize(light->light.D), light->light.L * rcp(uniformSampleConePDF(light->light.cosHalfAngle)), light->light.cosHalfAngle); else if (auto light = in.dynamicCast >()) PointLight_set(out, light->light.P, light->light.I, 0.f); else if (auto light = in.dynamicCast >()) 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 geometries; //!< list of geometries std::vector materials; //!< material list std::vector 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; }