// Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include "scenegraph.h" // #include "xml_loader.h" // #include "xml_writer.h" #include "obj_loader.h" // #include "ply_loader.h" // #include "corona_loader.h" namespace embree { // extern "C" RTCDevice g_device; void (*SceneGraph::opaque_geometry_destruction)(void *) = nullptr; Ref SceneGraph::load(const FileName &filename, const bool singleObject) { if (toLowerCase(filename.ext()) == std::string("obj")) return loadOBJ(filename, false, singleObject); // else if (toLowerCase(filename.ext()) == std::string("ply" )) return loadPLY(filename); // else if (toLowerCase(filename.ext()) == std::string("xml" )) return loadXML(filename); // else if (toLowerCase(filename.ext()) == std::string("scn" )) return loadCorona(filename); else throw std::runtime_error("unknown scene format: " + filename.ext()); } void SceneGraph::LightNode::calculateStatistics(Statistics& stat) { indegree++; if (indegree == 1) stat.numLights++; } void SceneGraph::GroupNode::print(std::ostream &cout, int depth) { cout << "GroupNode @ " << this << " { " << std::endl; tab(cout, depth + 1); cout << "closed = " << closed << std::endl; for (size_t i = 0; i < children.size(); i++) { tab(cout, depth + 1); cout << "child" << i << " = "; children[i]->print(cout, depth + 1); } tab(cout, depth); cout << "}" << std::endl; } void SceneGraph::MaterialNode::print(std::ostream &cout, int depth) { cout << "MaterialNode @ " << this << " { closed = " << closed << " }" << std::endl; } void SceneGraph::TriangleMeshNode::print(std::ostream &cout, int depth) { cout << "TriangleMeshNode @ " << this << " { closed = " << closed << " }" << std::endl; } void SceneGraph::LightNode::print(std::ostream& cout, int depth) { cout << "LightNode @ " << this << " { closed = " << closed << " }" << std::endl; } void SceneGraph::Node::calculateInDegree() { indegree++; } void SceneGraph::TriangleMeshNode::calculateInDegree() { indegree++; if (indegree == 1 && material != 0) material->calculateInDegree(); } void SceneGraph::GroupNode::calculateInDegree() { indegree++; if (indegree == 1) { for (auto &c: children) c->calculateInDegree(); } } bool SceneGraph::Node::calculateClosed(bool group_instancing) { assert(indegree); closed = true; hasLightOrCamera = false; return indegree == 1; } bool SceneGraph::GroupNode::calculateClosed(bool group_instancing) { assert(indegree); if (!closed) { closed = group_instancing; hasLightOrCamera = false; for (auto &c: children) { closed &= c->calculateClosed(group_instancing); hasLightOrCamera |= c->hasLightOrCamera; } } return closed && (indegree == 1); } bool SceneGraph::LightNode::calculateClosed(bool group_instancing) { assert(indegree); closed = true; hasLightOrCamera = true; return indegree == 1; } void SceneGraph::Node::resetInDegree() { closed = false; indegree--; } void SceneGraph::TriangleMeshNode::resetInDegree() { closed = false; if (indegree == 1 && material != 0) material->resetInDegree(); indegree--; } void SceneGraph::GroupNode::resetInDegree() { closed = false; if (indegree == 1) { for (auto &c: children) c->resetInDegree(); } indegree--; } void SceneGraph::TriangleMeshNode::verify() const { const size_t N = numVertices(); if (normals.size() && normals.size() != positions.size()) THROW_RUNTIME_ERROR("incompatible number of time steps"); for (const auto &p: positions) if (p.size() != N) THROW_RUNTIME_ERROR("incompatible vertex array sizes"); for (const auto &n: normals) if (n.size() && n.size() != N) THROW_RUNTIME_ERROR("incompatible vertex array sizes"); if (texcoords.size() && texcoords.size() != N) THROW_RUNTIME_ERROR("incompatible vertex array sizes"); for (auto &tri: triangles) { if (size_t(tri.v0) >= N || size_t(tri.v1) >= N || size_t(tri.v2) >= N) THROW_RUNTIME_ERROR("invalid triangle"); } } bool test_location(const std::vector> &in, ssize_t ipos, std::vector> &out, ssize_t opos) { if (opos < 0) return false; for (ssize_t i = ipos, j = opos; i < ipos + 4 && j < (ssize_t) out[0].size(); i++, j++) { for (size_t k = 0; k < in.size(); k++) { if (any(abs((vfloat4) in[k][i].m128 - (vfloat4) out[k][j].m128) > 0.01f * (vfloat4) max( abs(in[k][i]), abs(out[k][j])).m128)) return false; } } return true; } std::pair quad_index2(int p, int a0, int a1, int b0, int b1) { if (b0 == a0) return std::make_pair(p - 1, b1); else if (b0 == a1) return std::make_pair(p + 0, b1); else if (b1 == a0) return std::make_pair(p - 1, b0); else if (b1 == a1) return std::make_pair(p + 0, b0); else return std::make_pair(0, -1); } std::pair quad_index3(int a0, int a1, int a2, int b0, int b1, int b2) { if (b0 == a0) return quad_index2(0, a2, a1, b1, b2); else if (b0 == a1) return quad_index2(1, a0, a2, b1, b2); else if (b0 == a2) return quad_index2(2, a1, a0, b1, b2); else if (b1 == a0) return quad_index2(0, a2, a1, b0, b2); else if (b1 == a1) return quad_index2(1, a0, a2, b0, b2); else if (b1 == a2) return quad_index2(2, a1, a0, b0, b2); else if (b2 == a0) return quad_index2(0, a2, a1, b0, b1); else if (b2 == a1) return quad_index2(1, a0, a2, b0, b1); else if (b2 == a2) return quad_index2(2, a1, a0, b0, b1); else return std::make_pair(0, -1); } struct SceneGraphFlattener { Ref node; std::map, Ref> object_mapping; std::map unique_id; SceneGraphFlattener(Ref in, SceneGraph::InstancingMode instancing) { in->calculateInDegree(); in->calculateClosed(instancing == SceneGraph::INSTANCING_GROUP); std::vector> geometries; if (instancing != SceneGraph::INSTANCING_NONE) { if (instancing == SceneGraph::INSTANCING_FLATTENED) convertFlattenedInstances(geometries, in); else if (instancing == SceneGraph::INSTANCING_MULTI_LEVEL) convertMultiLevelInstances(geometries, in); else convertInstances(geometries, in, one); convertLightsAndCameras(geometries, in, one); } else { convertGeometries(geometries, in, one); convertLightsAndCameras(geometries, in, one); } in->resetInDegree(); node = new SceneGraph::GroupNode(geometries); } std::string makeUniqueID(std::string id) { if (id == "") id = "camera"; std::map::iterator i = unique_id.find(id); if (i == unique_id.end()) { unique_id[id] = 0; return id; } else { int n = ++unique_id[id]; return id + "_" + toString(n); } } void convertLightsAndCameras(std::vector> &group, const Ref &node, const SceneGraph::Transformations &spaces) { if (!node->hasLightOrCamera) return; /*if (Ref xfmNode = node.dynamicCast()) { convertLightsAndCameras(group,xfmNode->child, spaces*xfmNode->spaces); } else */ if (Ref groupNode = node.dynamicCast()) { for (const auto &child: groupNode->children) convertLightsAndCameras(group, child, spaces); } // else if (Ref lightNode = node.dynamicCast()) { // if (spaces.size() != 1) throw std::runtime_error("animated lights cannot get instantiated with a transform animation"); // group.push_back(lightNode->transform(spaces[0]).dynamicCast()); // } else if (Ref lightNode = node.dynamicCast()) { if (spaces.size() == 1) group.push_back(lightNode->transform(spaces[0]).dynamicCast()); else { // std::vector> lights(spaces.size()); // for (size_t i=0; itransform(spaces[i]); // // group.push_back(new SceneGraph::AnimatedLightNode(std::move(lights),spaces.time_range)); } } // else if (Ref cameraNode = node.dynamicCast()) // { // if (spaces.size() != 1) throw std::runtime_error("animated cameras cannot get instantiated with a transform animation"); // group.push_back(new SceneGraph::AnimatedPerspectiveCameraNode(cameraNode,spaces[0],makeUniqueID(cameraNode->name))); // } // else if (Ref cameraNode = node.dynamicCast()) // { // if (spaces.size() == 1) // group.push_back(new SceneGraph::PerspectiveCameraNode(cameraNode,spaces[0],makeUniqueID(cameraNode->name))); // else // { // std::vector> cameras(spaces.size()); // for (size_t i=0; iname))); // } // } } void convertGeometries(std::vector> &group, const Ref &node, const SceneGraph::Transformations &spaces) { /*if (Ref xfmNode = node.dynamicCast()) { convertGeometries(group, xfmNode->child, spaces * xfmNode->spaces); } else if (Ref xfmNode = node.dynamicCast< SceneGraph::MultiTransformNode>()) { for (size_t i = 0; i < xfmNode->spaces.size(); ++i) convertGeometries(group, xfmNode->child, spaces * xfmNode->spaces[i]); } else */if (Ref groupNode = node.dynamicCast()) { for (const auto &child: groupNode->children) convertGeometries(group, child, spaces); } else if (Ref mesh = node.dynamicCast()) { group.push_back(new SceneGraph::TriangleMeshNode(mesh, spaces)); } /*else if (Ref mesh = node.dynamicCast()) { group.push_back(new SceneGraph::QuadMeshNode(mesh, spaces)); } else if (Ref mesh = node.dynamicCast()) { group.push_back(new SceneGraph::GridMeshNode(mesh, spaces)); } else if (Ref mesh = node.dynamicCast()) { group.push_back(new SceneGraph::SubdivMeshNode(mesh, spaces)); } else if (Ref mesh = node.dynamicCast()) { group.push_back(new SceneGraph::HairSetNode(mesh, spaces)); } else if (Ref mesh = node.dynamicCast()) { group.push_back(new SceneGraph::PointSetNode(mesh, spaces)); }*/ } Ref lookupGeometries(Ref node) { if (object_mapping.find(node) == object_mapping.end()) { std::vector> geometries; convertGeometries(geometries, node, one); object_mapping[node] = new SceneGraph::GroupNode(geometries); } return object_mapping[node]; } void convertInstances(std::vector> &group, const Ref &node, const std::vector &spaces) { /*if (node->isClosed()) { //if (group.size() % 10000 == 0) std::cout << "." << std::flush; group.push_back(new SceneGraph::MultiTransformNode(spaces, lookupGeometries(node))); } else if (Ref xfmNode = node.dynamicCast()) { for (size_t i = 0; i < spaces.size(); ++i) convertInstances(group, xfmNode->child, spaces[i] * xfmNode->spaces); } else if (Ref xfmNode = node.dynamicCast< SceneGraph::MultiTransformNode>()) { convertInstances(group, xfmNode->child, spaces * xfmNode->spaces); } else */if (Ref groupNode = node.dynamicCast()) { for (const auto &child: groupNode->children) convertInstances(group, child, spaces); } } void convertInstances(std::vector> &group, const Ref &node, const SceneGraph::Transformations &spaces) { /*if (node->isClosed()) { //if (group.size() % 10000 == 0) std::cout << "." << std::flush; group.push_back(new SceneGraph::TransformNode(spaces, lookupGeometries(node))); } else if (Ref xfmNode = node.dynamicCast()) { convertInstances(group, xfmNode->child, spaces * xfmNode->spaces); } else if (Ref xfmNode = node.dynamicCast< SceneGraph::MultiTransformNode>()) { convertInstances(group, xfmNode->child, spaces * xfmNode->spaces); } else */if (Ref groupNode = node.dynamicCast()) { for (const auto &child: groupNode->children) convertInstances(group, child, spaces); } } void convertMultiLevelInstances(std::vector> &group, const Ref &node) { if (Ref groupNode = node.dynamicCast()) { for (const auto &child: groupNode->children) convertMultiLevelInstances(group, child); } else if (node.dynamicCast()) { group.push_back(node); } /*else if (node.dynamicCast()) { group.push_back(node); } else if (node.dynamicCast()) { group.push_back(node); } else if (node.dynamicCast()) { group.push_back(node); } else if (node.dynamicCast()) { group.push_back(node); } else if (node.dynamicCast()) { group.push_back(node); }*/ else if (object_mapping.find(node) != object_mapping.end()) { group.push_back(object_mapping[node]); } /*else if (Ref xfmNode = node.dynamicCast()) { auto new_node = new SceneGraph::TransformNode(xfmNode->spaces, convertMultiLevelInstances(xfmNode->child)); object_mapping[node] = new_node; group.push_back(new_node); } else if (Ref xfmNode = node.dynamicCast< SceneGraph::MultiTransformNode>()) { auto new_node = new SceneGraph::MultiTransformNode(xfmNode->spaces, convertMultiLevelInstances(xfmNode->child)); object_mapping[node] = new_node; group.push_back(new_node); }*/ } Ref convertMultiLevelInstances(const Ref &node) { if (object_mapping.find(node) != object_mapping.end()) { return object_mapping[node]; } std::vector> group; convertMultiLevelInstances(group, node); auto new_node = new SceneGraph::GroupNode(group); object_mapping[node] = new_node; return new_node; } void convertFlattenedInstances(std::vector> &group, const Ref &node) { /*if (Ref xfmNode = node.dynamicCast()) { group.push_back(node); } else */if (Ref groupNode = node.dynamicCast()) { for (const auto &child: groupNode->children) convertFlattenedInstances(group, child); } } }; Ref SceneGraph::flatten(Ref node, InstancingMode mode) { return SceneGraphFlattener(node, mode).node; } Ref SceneGraph::flatten(Ref node, SceneGraph::InstancingMode mode) { return flatten(node.dynamicCast(), mode).dynamicCast(); } }