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,190 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
namespace embree {
namespace SceneGraph {
enum LightType {
LIGHT_AMBIENT,
LIGHT_POINT,
LIGHT_DIRECTIONAL,
LIGHT_SPOT,
LIGHT_DISTANT,
LIGHT_TRIANGLE,
LIGHT_QUAD,
};
class Light {
ALIGNED_CLASS_(16)
public:
Light(LightType type) : type(type) {
}
LightType getType() const { return type; }
private:
LightType type;
};
class AmbientLight : public Light {
public:
AmbientLight(const Vec3fa& L)
: Light(LIGHT_AMBIENT), L(L) {
}
AmbientLight transform(const AffineSpace3fa& space) const {
return AmbientLight(L);
}
static AmbientLight lerp(const AmbientLight& light0, const AmbientLight& light1, const float f) {
return AmbientLight(embree::lerp(light0.L, light1.L, f));
}
public:
Vec3fa L; //!< radiance of ambient light
};
class PointLight : public Light {
public:
PointLight(const Vec3fa& P, const Vec3fa& I)
: Light(LIGHT_POINT), P(P), I(I) {
}
PointLight transform(const AffineSpace3fa& space) const {
return PointLight(xfmPoint(space, P), I);
}
static PointLight lerp(const PointLight& light0, const PointLight& light1, const float f) {
return PointLight(embree::lerp(light0.P, light1.P, f),
embree::lerp(light0.I, light1.I, f));
}
public:
Vec3fa P; //!< position of point light
Vec3fa I; //!< radiant intensity of point light
};
class DirectionalLight : public Light {
public:
DirectionalLight(const Vec3fa& D, const Vec3fa& E)
: Light(LIGHT_DIRECTIONAL), D(D), E(E) {
}
DirectionalLight transform(const AffineSpace3fa& space) const {
return DirectionalLight(xfmVector(space, D), E);
}
static DirectionalLight lerp(const DirectionalLight& light0, const DirectionalLight& light1,
const float f) {
return DirectionalLight(embree::lerp(light0.D, light1.D, f),
embree::lerp(light0.E, light1.E, f));
}
public:
Vec3fa D; //!< Light direction
Vec3fa E; //!< Irradiance (W/m^2)
};
class SpotLight : public Light {
public:
SpotLight(const Vec3fa& P, const Vec3fa& D, const Vec3fa& I, float angleMin, float angleMax)
: Light(LIGHT_SPOT), P(P), D(D), I(I), angleMin(angleMin), angleMax(angleMax) {
}
SpotLight transform(const AffineSpace3fa& space) const {
return SpotLight(xfmPoint(space, P), xfmVector(space, D), I, angleMin, angleMax);
}
static SpotLight lerp(const SpotLight& light0, const SpotLight& light1, const float f) {
return SpotLight(embree::lerp(light0.P, light1.P, f),
embree::lerp(light0.D, light1.D, f),
embree::lerp(light0.I, light1.I, f),
embree::lerp(light0.angleMin, light1.angleMin, f),
embree::lerp(light0.angleMax, light1.angleMax, f));
}
public:
Vec3fa P; //!< Position of the spot light
Vec3fa D; //!< Light direction of the spot light
Vec3fa I; //!< Radiant intensity (W/sr)
float angleMin, angleMax; //!< Linear falloff region
};
class DistantLight : public Light {
public:
DistantLight(const Vec3fa& D, const Vec3fa& L, const float halfAngle)
: Light(LIGHT_DISTANT), D(D), L(L), halfAngle(halfAngle), radHalfAngle(deg2rad(halfAngle)),
cosHalfAngle(cos(deg2rad(halfAngle))) {
}
DistantLight transform(const AffineSpace3fa& space) const {
return DistantLight(xfmVector(space, D), L, halfAngle);
}
static DistantLight lerp(const DistantLight& light0, const DistantLight& light1, const float f) {
return DistantLight(embree::lerp(light0.D, light1.D, f),
embree::lerp(light0.L, light1.L, f),
embree::lerp(light0.halfAngle, light1.halfAngle, f));
}
public:
Vec3fa D; //!< Light direction
Vec3fa L; //!< Radiance (W/(m^2*sr))
float halfAngle; //!< Half illumination angle
float radHalfAngle; //!< Half illumination angle in radians
float cosHalfAngle; //!< Cosine of half illumination angle
};
class TriangleLight : public Light {
public:
TriangleLight(const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2, const Vec3fa& L)
: Light(LIGHT_TRIANGLE), v0(v0), v1(v1), v2(v2), L(L) {
}
TriangleLight transform(const AffineSpace3fa& space) const {
return TriangleLight(xfmPoint(space, v0), xfmPoint(space, v1), xfmPoint(space, v2), L);
}
static TriangleLight lerp(const TriangleLight& light0, const TriangleLight& light1, const float f) {
return TriangleLight(embree::lerp(light0.v0, light1.v0, f),
embree::lerp(light0.v1, light1.v1, f),
embree::lerp(light0.v2, light1.v2, f),
embree::lerp(light0.L, light1.L, f));
}
public:
Vec3fa v0;
Vec3fa v1;
Vec3fa v2;
Vec3fa L;
};
class QuadLight : public Light {
public:
QuadLight(const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2, const Vec3fa& v3, const Vec3fa& L)
: Light(LIGHT_QUAD), v0(v0), v1(v1), v2(v2), v3(v3), L(L) {
}
QuadLight transform(const AffineSpace3fa& space) const {
return QuadLight(xfmPoint(space, v0), xfmPoint(space, v1), xfmPoint(space, v2), xfmPoint(space, v3), L);
}
static QuadLight lerp(const QuadLight& light0, const QuadLight& light1, const float f) {
return QuadLight(embree::lerp(light0.v0, light1.v0, f),
embree::lerp(light0.v1, light1.v1, f),
embree::lerp(light0.v2, light1.v2, f),
embree::lerp(light0.v3, light1.v3, f),
embree::lerp(light0.L, light1.L, f));
}
public:
Vec3fa v0;
Vec3fa v1;
Vec3fa v2;
Vec3fa v3;
Vec3fa L;
};
}
}

View file

@ -0,0 +1,263 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#if defined (CPPTUTORIAL) && !defined(_MATERIALS_H_CPPTUTORIAL) || !defined(_MATERIALS_H_)
#if defined (CPPTUTORIAL)
#define _MATERIALS_H_CPPTUTORIAL
#else
#define _MATERIALS_H_
#endif
//#pragma once
#if !defined(ISPC)
// #include "texture.h"
#include "scenegraph.h"
#endif
#if !defined(ISPC)
namespace embree
{
#endif
#if defined(ISPC) || defined(CPPTUTORIAL)
#define MATERIAL_BASE_CLASS
#define PREFIX(x) ISPC##x
#else
#define MATERIAL_BASE_CLASS : public SceneGraph::MaterialNode
#define PREFIX(x) x
#endif
#if !defined(CPPTUTORIAL)
enum MaterialType
{
MATERIAL_OBJ,
MATERIAL_THIN_DIELECTRIC,
MATERIAL_METAL,
MATERIAL_VELVET,
MATERIAL_DIELECTRIC,
MATERIAL_METALLIC_PAINT,
MATERIAL_MATTE,
MATERIAL_MIRROR,
MATERIAL_REFLECTIVE_METAL,
MATERIAL_HAIR
};
#endif
struct PREFIX(Material)
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
Material (MaterialType type)
: type(type) {}
#endif
#if !defined(ISPC)
__aligned(16)
#endif
int type;
int align[3];
};
struct PREFIX(MatteMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
MatteMaterial (const Vec3fa& reflectance)
: base(MATERIAL_MATTE), reflectance(reflectance) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa reflectance;
};
struct PREFIX(MirrorMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
MirrorMaterial (const Vec3fa& reflectance)
: base(MATERIAL_MIRROR), reflectance(reflectance) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa reflectance;
};
struct PREFIX(ThinDielectricMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
ThinDielectricMaterial (const Vec3fa& transmission, const float eta, const float thickness)
: base(MATERIAL_THIN_DIELECTRIC), transmission(transmission), transmissionFactor(log(transmission)*thickness), eta(eta), thickness(thickness) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa transmission;
Vec3fa transmissionFactor;
float eta;
float thickness;
};
struct PREFIX(OBJMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
OBJMaterial (const std::string name = "")
: SceneGraph::MaterialNode(name), base(MATERIAL_OBJ), illum(0), d(1.f), Ns(1.f), Ni(1.f), Ka(0.f), Kd(1.f), Ks(0.f), Kt(1.0f) {}
// map_d(nullptr), map_Ka(nullptr), map_Kd(nullptr), map_Ks(nullptr), map_Kt(nullptr), map_Ns(nullptr), map_Displ(nullptr) {}
OBJMaterial (float d, const Vec3fa& Kd, const Vec3fa& Ks, const float Ns, const std::string name = "")
: base(MATERIAL_OBJ), illum(0), d(d), Ns(Ns), Ni(1.f), Ka(0.f), Kd(Kd), Ks(Ks), Kt(1.0f) {}
// map_d(nullptr), map_Ka(nullptr), map_Kd(nullptr), map_Ks(nullptr), map_Kt(nullptr), map_Ns(nullptr), map_Displ(nullptr) {}
OBJMaterial (float d, const Vec3fa& Ka, const Vec3fa& Kd, const Vec3fa& Ks, const Vec3fa& Kt, const float Ns, const std::string name = "")
: base(MATERIAL_OBJ), illum(0), d(d), Ns(Ns), Ni(1.f), Ka(Ka), Kd(Kd), Ks(Ks), Kt(Kt) {}
// OBJMaterial (float d, const std::shared_ptr<Texture> map_d,
// const Vec3fa& Ka, const std::shared_ptr<Texture> map_Ka,
// const Vec3fa& Kd, const std::shared_ptr<Texture> map_Kd,
// const Vec3fa& Ks, const std::shared_ptr<Texture> map_Ks,
// const Vec3fa& Kt, const std::shared_ptr<Texture> map_Kt,
// const float Ns, const std::shared_ptr<Texture> map_Ns,
// const std::shared_ptr<Texture> map_Displ)
// : base(MATERIAL_OBJ), illum(0), d(d), Ns(Ns), Ni(1.f), Ka(Ka), Kd(Kd), Ks(Ks), Kt(Kt),
// map_d(nullptr), map_Ka(nullptr), map_Kd(nullptr), map_Ks(nullptr), map_Kt(nullptr), map_Ns(nullptr), map_Displ(nullptr),
// _map_d(map_d), _map_Ka(map_Ka), _map_Kd(map_Kd), _map_Ks(map_Ks), _map_Kt(map_Kt), _map_Ns(map_Ns), _map_Displ(map_Displ) {}
virtual Material* material()
{
// map_d = _map_d.get();
// map_Ka = _map_Ka.get();
// map_Kd = _map_Kd.get();
// map_Ks = _map_Ks.get();
// map_Kt = _map_Kt.get();
// map_Ns = _map_Ns.get();
// map_Displ = _map_Displ.get();
return &base;
}
~OBJMaterial() { // FIXME: destructor never called
}
#endif
PREFIX(Material) base;
int illum; /*< illumination model */
float d; /*< dissolve factor, 1=opaque, 0=transparent */
float Ns; /*< specular exponent */
float Ni; /*< optical density for the surface (index of refraction) */
Vec3fa Ka; /*< ambient reflectivity */
Vec3fa Kd; /*< diffuse reflectivity */
Vec3fa Ks; /*< specular reflectivity */
Vec3fa Kt; /*< transmission filter */
// const Texture* map_d; /*< d texture */
// const Texture* map_Ka; /*< Ka texture */
// const Texture* map_Kd; /*< Kd texture */
// const Texture* map_Ks; /*< Ks texture */
// const Texture* map_Kt; /*< Kt texture */
// const Texture* map_Ns; /*< Ns texture */
// const Texture* map_Displ; /*< Displ texture */
#if !defined(ISPC) && !defined(CPPTUTORIAL)
// std::shared_ptr<Texture> _map_d; /*< d texture */
// std::shared_ptr<Texture> _map_Ka; /*< Ka texture */
// std::shared_ptr<Texture> _map_Kd; /*< Kd texture */
// std::shared_ptr<Texture> _map_Ks; /*< Ks texture */
// std::shared_ptr<Texture> _map_Kt; /*< Kt texture */
// std::shared_ptr<Texture> _map_Ns; /*< Ns texture */
// std::shared_ptr<Texture> _map_Displ; /*< Displ texture */
#endif
};
struct PREFIX(MetalMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
MetalMaterial (const Vec3fa& reflectance, const Vec3fa& eta, const Vec3fa& k)
: base(MATERIAL_REFLECTIVE_METAL), reflectance(reflectance), eta(eta), k(k), roughness(0.0f) {}
MetalMaterial (const Vec3fa& reflectance, const Vec3fa& eta, const Vec3fa& k, const float roughness)
: base(MATERIAL_METAL), reflectance(reflectance), eta(eta), k(k), roughness(roughness) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa reflectance;
Vec3fa eta;
Vec3fa k;
float roughness;
};
typedef PREFIX(MetalMaterial) PREFIX(ReflectiveMetalMaterial);
struct PREFIX(VelvetMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
VelvetMaterial (const Vec3fa& reflectance, const float backScattering, const Vec3fa& horizonScatteringColor, const float horizonScatteringFallOff)
: base(MATERIAL_VELVET), reflectance(reflectance), horizonScatteringColor(horizonScatteringColor), backScattering(backScattering), horizonScatteringFallOff(horizonScatteringFallOff) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa reflectance;
Vec3fa horizonScatteringColor;
float backScattering;
float horizonScatteringFallOff;
};
struct PREFIX(DielectricMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
DielectricMaterial (const Vec3fa& transmissionOutside, const Vec3fa& transmissionInside, const float etaOutside, const float etaInside)
: base(MATERIAL_DIELECTRIC), transmissionOutside(transmissionOutside), transmissionInside(transmissionInside), etaOutside(etaOutside), etaInside(etaInside) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa transmissionOutside;
Vec3fa transmissionInside;
float etaOutside;
float etaInside;
};
struct PREFIX(MetallicPaintMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
MetallicPaintMaterial (const Vec3fa& shadeColor, const Vec3fa& glitterColor, float glitterSpread, float eta)
: base(MATERIAL_METALLIC_PAINT), shadeColor(shadeColor), glitterColor(glitterColor), glitterSpread(glitterSpread), eta(eta) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa shadeColor;
Vec3fa glitterColor;
float glitterSpread;
float eta;
};
struct PREFIX(HairMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
HairMaterial (const Vec3fa& Kr, const Vec3fa& Kt, float nx, float ny)
: base(MATERIAL_HAIR), Kr(Kr), Kt(Kt), nx(nx), ny(ny) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa Kr;
Vec3fa Kt;
float nx;
float ny;
};
#undef MATERIAL_BASE_CLASS
#undef PREFIX
#if !defined(ISPC)
}
#endif
#endif

View file

@ -0,0 +1,715 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#include "obj_loader.h"
// #include "texture.h"
namespace embree {
/*! Three-index vertex, indexing start at 0, -1 means invalid vertex. */
struct Vertex {
unsigned int v, vt, vn;
Vertex() {
};
Vertex(unsigned int v) : v(v), vt(v), vn(v) {
};
Vertex(unsigned int v, unsigned int vt, unsigned int vn) : v(v), vt(vt), vn(vn) {
};
};
struct Crease {
float w;
unsigned int a, b;
Crease() : w(0), a(-1), b(-1) {
};
Crease(float w, unsigned int a, unsigned int b) : w(w), a(a), b(b) {
};
};
static inline bool operator <(const Vertex& a, const Vertex& b) {
if (a.v != b.v) return a.v < b.v;
if (a.vn != b.vn) return a.vn < b.vn;
if (a.vt != b.vt) return a.vt < b.vt;
return false;
}
/*! Fill space at the end of the token with 0s. */
static inline const char* trimEnd(const char* token) {
if (*token == 0) return token;
char* pe = (char *) token;
while (*pe) pe++;
pe--;
while ((*pe == ' ' || *pe == '\t' || *pe == '\r') && pe >= token) *pe-- = 0;
return token;
}
/*! Determine if character is a separator. */
static inline bool isSep(const char c) {
return (c == ' ') || (c == '\t');
}
/*! Parse separator. */
static inline const char* parseSep(const char*& token) {
size_t sep = strspn(token, " \t");
if (!sep)
THROW_RUNTIME_ERROR("separator expected");
return token += sep;
}
/*! Parse optional separator. */
static inline const char* parseSepOpt(const char*& token) {
return token += strspn(token, " \t");
}
/*! Read float from a string. */
static inline float getFloat(const char*& token) {
token += strspn(token, " \t");
float n = (float) atof(token);
token += strcspn(token, " \t\r");
return n;
}
/*! Read int from a string. */
static inline int getInt(const char*& token) {
token += strspn(token, " \t");
int n = atoi(token);
token += strcspn(token, " \t\r");
return n;
}
/*! Read Vec2f from a string. */
static inline Vec2f getVec2f(const char*& token) {
float x = getFloat(token);
float y = getFloat(token);
return Vec2f(x, y);
}
/*! Read Vec3f from a string. */
static inline Vec3f getVec3f(const char*& token) {
float x = getFloat(token);
token += strspn(token, " \t");
if (*token == 0) return Vec3f(x);
float y = getFloat(token);
float z = getFloat(token);
return Vec3f(x, y, z);
}
/*! Read Vec3fa from a string. */
static inline Vec3fa getVec3fa(const char*& token) {
float x = getFloat(token);
token += strspn(token, " \t");
if (*token == 0) return Vec3f(x);
float y = getFloat(token);
float z = getFloat(token);
return Vec3fa(x, y, z);
}
class OBJLoader {
public:
/*! Constructor. */
OBJLoader(const FileName& fileName, const bool subdivMode, const bool combineIntoSingleObject);
/*! output model */
Ref<SceneGraph::GroupNode> group;
private:
/*! file to load */
FileName path;
/*! load only quads and ignore triangles */
bool subdivMode;
/*! Geometry buffer. */
avector<Vec3fa> v;
avector<Vec3fa> vn;
std::vector<Vec2f> vt;
std::vector<Crease> ec;
std::vector<std::vector<Vertex> > curGroup;
std::vector<avector<Vec3ff> > curGroupHair;
/*! Material handling. */
std::string curMaterialName;
Ref<SceneGraph::MaterialNode> curMaterial;
std::map<std::string, Ref<SceneGraph::MaterialNode> > material;
// std::map<std::string, std::shared_ptr<Texture>> textureMap;
private:
void loadMTL(const FileName& fileName);
unsigned int fix_v(int index);
unsigned int fix_vt(int index);
unsigned int fix_vn(int index);
void flushFaceGroup();
void flushTriGroup();
// void flushHairGroup();
Vertex getUInt3(const char*& token);
uint32_t getVertex(std::map<Vertex, uint32_t>& vertexMap, Ref<SceneGraph::TriangleMeshNode> mesh,
const Vertex& i);
// std::shared_ptr<Texture> loadTexture(const FileName& fname);
};
OBJLoader::OBJLoader(const FileName& fileName, const bool subdivMode, const bool combineIntoSingleObject)
: group(new SceneGraph::GroupNode), path(fileName.path()), subdivMode(subdivMode) {
/* open file */
std::ifstream cin;
cin.open(fileName.c_str());
if (!cin.is_open()) {
THROW_RUNTIME_ERROR("cannot open " + fileName.str());
return;
}
/* generate default material */
Ref<SceneGraph::MaterialNode> defaultMaterial = new OBJMaterial("default");
curMaterialName = "default";
curMaterial = defaultMaterial;
while (cin.peek() != -1) {
/* load next multiline */
std::string line;
std::getline(cin, line);
while (!line.empty() && line[line.size() - 1] == '\\') {
line[line.size() - 1] = ' ';
std::string next_line;
std::getline(cin, next_line);
if (next_line.empty()) break;
line += next_line;
}
const char* token = trimEnd(line.c_str() + strspn(line.c_str(), " \t"));
if (token[0] == 0) continue;
/*! parse position */
if (token[0] == 'v' && isSep(token[1])) {
v.push_back(getVec3f(token += 2));
continue;
}
/* parse normal */
if (token[0] == 'v' && token[1] == 'n' && isSep(token[2])) {
vn.push_back(getVec3f(token += 3));
continue;
}
/* parse texcoord */
if (token[0] == 'v' && token[1] == 't' && isSep(token[2])) {
vt.push_back(getVec2f(token += 3));
continue;
}
/*! parse face */
if (token[0] == 'f' && isSep(token[1])) {
parseSep(token += 1);
std::vector<Vertex> face;
while (token[0]) {
Vertex vtx = getUInt3(token);
face.push_back(vtx);
parseSepOpt(token);
}
curGroup.push_back(face);
continue;
}
/*! parse corona hair */
if (!strncmp(token, "hair", 4) && isSep(token[4])) {
throw std::runtime_error("corona hair is deimplemented");
}
/*! parse edge crease */
if (token[0] == 'e' && token[1] == 'c' && isSep(token[2])) {
parseSep(token += 2);
float w = getFloat(token);
parseSepOpt(token);
unsigned int a = fix_v(getInt(token));
parseSepOpt(token);
unsigned int b = fix_v(getInt(token));
parseSepOpt(token);
ec.push_back(Crease(w, a, b));
continue;
}
/*! use material */
if (!strncmp(token, "usemtl", 6) && isSep(token[6])) {
if (!combineIntoSingleObject) flushFaceGroup();
std::string name(parseSep(token += 6));
if (material.find(name) == material.end()) {
curMaterial = defaultMaterial;
curMaterialName = "default";
} else {
curMaterial = material[name];
curMaterialName = name;
}
continue;
}
/* load material library */
if (!strncmp(token, "mtllib", 6) && isSep(token[6])) {
loadMTL(path + std::string(parseSep(token += 6)));
continue;
}
// ignore unknown stuff
}
flushFaceGroup();
cin.close();
}
struct ExtObjMaterial {
public:
enum Type { NONE, MATTE, GLASS, METAL, METALLIC_PAINT };
Ref<SceneGraph::MaterialNode> select() const {
// std::shared_ptr<Texture> nulltex;
if (type == NONE) {
// return new OBJMaterial(d,map_d,Ka,map_Ka,Kd,map_Kd,Ks,map_Ks,Kt,map_Kt,Ns,map_Ns,map_Displ);
return new OBJMaterial(d, Ka, Kd, Ks, Kt, Ns);
} else if (type == MATTE) {
if (coat_eta != 1.0f)
return new MetallicPaintMaterial(Kd, zero, 0.0f, eta.x);
else
// return new OBJMaterial(1.0f,nulltex,zero,nulltex,Kd,map_Kd,Ks,nulltex,zero,nulltex,1.0f/(1E-6f+roughness),nulltex,nulltex);
return new OBJMaterial(1.0f, zero, Kd, Ks, zero, 1.0f / (1E-6f + roughness));
} else if (type == GLASS) {
return new ThinDielectricMaterial(Vec3fa(1.0f), eta.x, 0.1f);
} else if (type == METAL) {
if (roughness == 0.0f) {
if (eta == Vec3fa(1.0f) && k == Vec3fa(0.0f)) return new MirrorMaterial(Kd);
else return new MetalMaterial(Kd, eta, k);
} else return new MetalMaterial(Kd, eta, k, roughness);
} else if (type == METALLIC_PAINT) {
return new MetallicPaintMaterial(Kd, Ks, 0.0f, coat_eta);
}
return new MatteMaterial(Vec3fa(0.5f));
}
public:
Type type = NONE;
int illum = 0; /*< illumination model */
float d = 1.0f; /*< dissolve factor, 1=opaque, 0=transparent */
float Ns = 1.0f; /*< specular exponent */
float Ni = 1.0f; /*< optical density for the surface (index of refraction) */
Vec3fa Ka = zero; /*< ambient reflectivity */
Vec3fa Kd = one; /*< diffuse reflectivity */
Vec3fa Ks = zero; /*< specular reflectivity */
// Vec3fa Kt = zero; /*< transmission filter */
Vec3fa Kt = one; /*< transmission filter */
// ^ Because many textures were deleted
// std::shared_ptr<Texture> map_d; /*< d texture */
// std::shared_ptr<Texture> map_Ka; /*< Ka texture */
// std::shared_ptr<Texture> map_Kd; /*< Kd texture */
// std::shared_ptr<Texture> map_Ks; /*< Ks texture */
// std::shared_ptr<Texture> map_Kt; /*< Kt texture */
// std::shared_ptr<Texture> map_Ns; /*< Ns texture */
// std::shared_ptr<Texture> map_Displ; /*< Displ texture */
float roughness = zero;
// std::shared_ptr<Texture> roughnessMap;
float coat_eta = one;
float coat_roughness = zero;
// std::shared_ptr<Texture> coat_roughnessMap;
float bump = zero;
Vec3f eta = Vec3f(1.4f);
Vec3f k = Vec3f(3.0f);
};
// std::shared_ptr<Texture> OBJLoader::loadTexture(const FileName& fname)
// {
// if (textureMap.find(fname.str()) != textureMap.end())
// return textureMap[fname.str()];
// return std::shared_ptr<Texture>(Texture::load(path+fname));
// }
/* load material file */
void OBJLoader::loadMTL(const FileName& fileName) {
std::ifstream cin;
cin.open(fileName.c_str());
if (!cin.is_open()) {
std::cerr << "cannot open " << fileName.str() << std::endl;
return;
}
std::string name;
ExtObjMaterial cur;
while (cin.peek() != -1) {
/* load next multiline */
std::string line;
std::getline(cin, line);
while (!line.empty() && line[line.size() - 1] == '\\') {
line[line.size() - 1] = ' ';
std::string next_line;
std::getline(cin, next_line);
if (next_line.empty()) break;
line += next_line;
}
const char* token = trimEnd(line.c_str() + strspn(line.c_str(), " \t"));
if (token[0] == 0) continue; // ignore empty lines
if (token[0] == '#') continue; // ignore comments
if (!strncmp(token, "newmtl", 6)) {
if (name != "") {
material[name] = cur.select();
material[name]->name = name;
}
parseSep(token += 6);
name = token;
cur = ExtObjMaterial();
continue;
}
if (name == "")
THROW_RUNTIME_ERROR("invalid material file: newmtl expected first");
try {
if (!strncmp(token, "illum", 5)) {
parseSep(token += 5);
continue;
}
if (!strncmp(token, "d", 1)) {
parseSep(token += 1);
cur.d = getFloat(token);
continue;
}
if (!strncmp(token, "Ns", 2)) {
parseSep(token += 2);
cur.Ns = getFloat(token);
continue;
}
if (!strncmp(token, "Ni", 2)) {
parseSep(token += 2);
cur.Ni = getFloat(token);
continue;
}
// if (!strncmp(token, "map_d", 5) || !strncmp(token, "d_map", 5)) {
// parseSep(token += 5);
// cur.map_d = loadTexture(FileName(token));
// continue;
// }
// if (!strncmp(token, "map_Ka", 6) || !strncmp(token, "Ka_map", 6)) {
// parseSep(token += 6);
// cur.map_Ka = loadTexture(FileName(token));
// continue;
// }
// if (!strncmp(token, "map_Kd", 6) || !strncmp(token, "Kd_map", 6)) {
// parseSep(token += 6);
// cur.map_Kd = loadTexture(FileName(token));
// continue;
// }
// if (!strncmp(token, "map_Ks", 6) || !strncmp(token, "Ks_map", 6)) {
// parseSep(token += 6);
// cur.map_Ks = loadTexture(FileName(token));
// continue;
// }
// if (!strncmp(token, "map_Kt", 6) || !strncmp(token, "Kt_map", 6)) {
// parseSep(token += 6);
// cur.map_Kt = loadTexture(FileName(token));
// continue;
// }
// if (!strncmp(token, "map_Tf", 6) || !strncmp(token, "Tf_map", 6)) {
// parseSep(token += 6);
// cur.map_Kt = loadTexture(FileName(token));
// continue;
// }
// if (!strncmp(token, "map_Ns", 6) || !strncmp(token, "Ns_map", 6)) {
// parseSep(token += 6);
// cur.map_Ns = loadTexture(FileName(token));
// continue;
// }
// if (!strncmp(token, "map_Displ", 9) || !strncmp(token, "Displ_map", 9)) {
// parseSep(token += 9);
// cur.map_Displ = loadTexture(FileName(token));
// continue;
// }
if (!strncmp(token, "Ka", 2)) {
parseSep(token += 2);
cur.Ka = getVec3f(token);
continue;
}
if (!strncmp(token, "Kd", 2)) {
parseSep(token += 2);
cur.Kd = getVec3f(token);
continue;
}
if (!strncmp(token, "Ks", 2)) {
parseSep(token += 2);
cur.Ks = getVec3f(token);
continue;
}
if (!strncmp(token, "Kt", 2)) {
parseSep(token += 2);
cur.Kt = getVec3f(token);
continue;
}
if (!strncmp(token, "Tf", 2)) {
parseSep(token += 2);
cur.Kt = getVec3f(token);
continue;
}
/* extended OBJ */
if (!strncmp(token, "type", 4)) {
parseSep(token += 4);
std::string type = token;
if (type == "matte") cur.type = ExtObjMaterial::MATTE;
else if (type == "glass") cur.type = ExtObjMaterial::GLASS;
else if (type == "metal") cur.type = ExtObjMaterial::METAL;
else if (type == "metallicPaint") cur.type = ExtObjMaterial::METALLIC_PAINT;
else if (type == "principled") cur.type = ExtObjMaterial::NONE;
else if (type == "luminous") cur.type = ExtObjMaterial::NONE;
continue;
}
/* OSPRay principled material extensions */
if (!strncmp(token, "baseColor", 9)) {
parseSep(token += 9);
cur.Kd = getVec3f(token);
continue;
}
if (!strncmp(token, "ior", 3)) {
parseSep(token += 3);
cur.Ni = getFloat(token);
continue;
}
// if (!strncmp(token, "map_baseColor", 13)) { parseSep(token += 13); cur.map_Kd = loadTexture(FileName(token)); continue; }
// if (!strncmp(token, "map_specular", 12)) { parseSep(token += 12); cur.map_Ks = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "map_normal.scale", 16)) {
parseSep(token += 16);
continue;
}
// if (!strncmp(token, "map_normal", 10)) { parseSep(token += 10); cur.map_Displ = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "transmissionColor", 17)) {
parseSep(token += 17);
cur.Kt = getVec3f(token);
continue;
}
if (!strncmp(token, "transmission", 12)) {
parseSep(token += 12);
cur.Kt = Vec3f(getFloat(token));
continue;
}
// if (!strncmp(token, "roughnessMap", 12)) { parseSep(token += 12); cur.roughnessMap = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "roughness", 9)) {
parseSep(token += 9);
cur.roughness = getFloat(token);
cur.Ns = 1.0f / (cur.roughness + 1E-6f);
continue;
}
// if (!strncmp(token, "colorMap", 8)) { parseSep(token += 8); cur.map_Kd = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "color", 5)) {
parseSep(token += 5);
cur.Kd = getVec3f(token);
continue;
}
if (!strncmp(token, "coat.color", 10)) {
parseSep(token += 10);
cur.Kd = getVec3f(token);
continue;
}
if (!strncmp(token, "coat.eta", 8)) {
parseSep(token += 8);
cur.coat_eta = getFloat(token);
continue;
}
// if (!strncmp(token, "coat.roughnessMap",17)) { parseSep(token += 17); cur.coat_roughnessMap = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "coat.roughness", 14)) {
parseSep(token += 14);
cur.coat_roughness = getFloat(token);
continue;
}
// if (!strncmp(token, "bumpMap", 7)) { parseSep(token += 7); cur.map_Displ = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "bump", 4)) {
parseSep(token += 4);
cur.bump = getFloat(token);
continue;
}
if (!strncmp(token, "eta", 3)) {
parseSep(token += 3);
cur.eta = getVec3f(token);
continue;
}
if (!strncmp(token, "k", 1)) {
parseSep(token += 1);
cur.k = getVec3f(token);
continue;
}
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
if (name != "") {
material[name] = cur.select();
material[name]->name = name;
}
cin.close();
}
/*! handles relative indices and starts indexing from 0 */
unsigned int OBJLoader::fix_v(int index) {
return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) v.size() + index));
}
unsigned int OBJLoader::fix_vt(int index) {
return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) vt.size() + index));
}
unsigned int OBJLoader::fix_vn(int index) {
return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) vn.size() + index));
}
/*! Parse differently formatted triplets like: n0, n0/n1/n2, n0//n2, n0/n1. */
/*! All indices are converted to C-style (from 0). Missing entries are assigned -1. */
Vertex OBJLoader::getUInt3(const char*& token) {
Vertex v(-1);
v.v = fix_v(atoi(token));
token += strcspn(token, "/ \t\r");
if (token[0] != '/') return (v);
token++;
// it is i//n
if (token[0] == '/') {
token++;
v.vn = fix_vn(atoi(token));
token += strcspn(token, " \t\r");
return (v);
}
// it is i/t/n or i/t
v.vt = fix_vt(atoi(token));
token += strcspn(token, "/ \t\r");
if (token[0] != '/') return (v);
token++;
// it is i/t/n
v.vn = fix_vn(atoi(token));
token += strcspn(token, " \t\r");
return (v);
}
uint32_t OBJLoader::getVertex(std::map<Vertex, uint32_t>& vertexMap, Ref<SceneGraph::TriangleMeshNode> mesh,
const Vertex& i) {
const std::map<Vertex, uint32_t>::iterator& entry = vertexMap.find(i);
if (entry != vertexMap.end()) return (entry->second);
if (i.v >= v.size()) std::cout << "WARNING: corrupted OBJ file" << std::endl;
else mesh->positions[0].push_back(v[i.v]);
if (i.vn != -1) {
while (mesh->normals[0].size() < mesh->positions[0].size()) mesh->normals[0].push_back(zero);
// some vertices might not had a normal
if (i.vn >= vn.size()) std::cout << "WARNING: corrupted OBJ file" << std::endl;
else mesh->normals[0][mesh->positions[0].size() - 1] = vn[i.vn];
}
if (i.vt != -1) {
while (mesh->texcoords.size() < mesh->positions[0].size()) mesh->texcoords.push_back(zero);
// some vertices might not had a texture coordinate
if (i.vt >= vt.size()) std::cout << "WARNING: corrupted OBJ file" << std::endl;
else mesh->texcoords[mesh->positions[0].size() - 1] = vt[i.vt];
}
return (vertexMap[i] = (unsigned int) (mesh->positions[0].size()) - 1);
}
void OBJLoader::flushFaceGroup() {
flushTriGroup();
// flushHairGroup();
}
/*! end current facegroup and append to mesh */
void OBJLoader::flushTriGroup() {
if (curGroup.empty()) return;
if (subdivMode) {
throw std::runtime_error("Deimplemented");
// Ref<SceneGraph::SubdivMeshNode> mesh = new SceneGraph::SubdivMeshNode(curMaterial,BBox1f(0,1),1);
// mesh->normals.resize(1);
// group->add(mesh.cast<SceneGraph::Node>());
// for (size_t i=0; i<v.size(); i++) mesh->positions[0].push_back(v[i]);
// for (size_t i=0; i<vn.size(); i++) mesh->normals[0].push_back(vn[i]);
// for (size_t i=0; i<vt.size(); i++) mesh->texcoords.push_back(vt[i]);
// for (size_t i=0; i<ec.size(); ++i) {
// assert(((size_t)ec[i].a < v.size()) && ((size_t)ec[i].b < v.size()));
// mesh->edge_creases.push_back(Vec2i(ec[i].a, ec[i].b));
// mesh->edge_crease_weights.push_back(ec[i].w);
// }
// for (size_t j=0; j<curGroup.size(); j++)
// {
// const std::vector<Vertex>& face = curGroup[j];
// mesh->verticesPerFace.push_back(int(face.size()));
// for (size_t i=0; i<face.size(); i++)
// mesh->position_indices.push_back(face[i].v);
// }
// if (mesh->normals[0].size() == 0)
// mesh->normals.clear();
// mesh->verify();
} else {
Ref<SceneGraph::TriangleMeshNode> mesh = new SceneGraph::TriangleMeshNode(curMaterial, BBox1f(0, 1), 1);
mesh->normals.resize(1);
group->add(mesh.cast<SceneGraph::Node>());
// merge three indices into one
std::map<Vertex, uint32_t> vertexMap;
for (size_t j = 0; j < curGroup.size(); j++) {
/* iterate over all faces */
const std::vector<Vertex>& face = curGroup[j];
/* triangulate the face with a triangle fan */
Vertex i0 = face[0], i1 = Vertex(-1), i2 = face[1];
for (size_t k = 2; k < face.size(); k++) {
i1 = i2;
i2 = face[k];
uint32_t v0, v1, v2;
v0 = getVertex(vertexMap, mesh, i0);
v1 = getVertex(vertexMap, mesh, i1);
v2 = getVertex(vertexMap, mesh, i2);
assert(v0 < mesh->numVertices());
assert(v1 < mesh->numVertices());
assert(v2 < mesh->numVertices());
mesh->triangles.push_back(SceneGraph::TriangleMeshNode::Triangle(v0, v1, v2));
}
}
/* there may be vertices without normals or texture coordinates, thus we have to make these arrays the same size here */
if (mesh->normals[0].size()) while (mesh->normals[0].size() < mesh->numVertices()) mesh->normals[0].
push_back(zero);
if (mesh->texcoords.size()) while (mesh->texcoords.size() < mesh->numVertices()) mesh->texcoords.
push_back(zero);
if (mesh->normals[0].size() == 0)
mesh->normals.clear();
mesh->verify();
}
curGroup.clear();
ec.clear();
}
Ref<SceneGraph::Node> loadOBJ(const FileName& fileName, const bool subdivMode, const bool combineIntoSingleObject) {
OBJLoader loader(fileName, subdivMode, combineIntoSingleObject);
return loader.group.cast<SceneGraph::Node>();
}
}

View file

@ -0,0 +1,12 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "scenegraph.h"
namespace embree
{
Ref<SceneGraph::Node> loadOBJ(const FileName& fileName,
const bool subdivMode = false,
const bool combineIntoSingleObject = false);
}

View file

@ -0,0 +1,411 @@
// 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::Node> 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->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->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<avector<Vec3ff>> &in, ssize_t ipos, std::vector<avector<Vec3ff>> &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<int, int> 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<int, int> 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<SceneGraph::Node> node;
std::map<Ref<SceneGraph::Node>, Ref<SceneGraph::Node>> object_mapping;
std::map<std::string, int> unique_id;
SceneGraphFlattener(Ref<SceneGraph::Node> in, SceneGraph::InstancingMode instancing) {
in->calculateInDegree();
in->calculateClosed(instancing == SceneGraph::INSTANCING_GROUP);
std::vector<Ref<SceneGraph::Node>> 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<std::string, int>::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<Ref<SceneGraph::Node>> &group, const Ref<SceneGraph::Node> &node,
const SceneGraph::Transformations &spaces) {
if (!node->hasLightOrCamera)
return;
/*if (Ref<SceneGraph::TransformNode> xfmNode = node.dynamicCast<SceneGraph::TransformNode>()) {
convertLightsAndCameras(group,xfmNode->child, spaces*xfmNode->spaces);
}
else */
if (Ref<SceneGraph::GroupNode> groupNode = node.dynamicCast<SceneGraph::GroupNode>()) {
for (const auto &child: groupNode->children)
convertLightsAndCameras(group, child, spaces);
}
// else if (Ref<SceneGraph::AnimatedLightNode> lightNode = node.dynamicCast<SceneGraph::AnimatedLightNode>()) {
// 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<SceneGraph::Node>());
// }
else if (Ref<SceneGraph::LightNode> lightNode = node.dynamicCast<SceneGraph::LightNode>()) {
if (spaces.size() == 1)
group.push_back(lightNode->transform(spaces[0]).dynamicCast<SceneGraph::Node>());
else {
// std::vector<Ref<SceneGraph::LightNode>> lights(spaces.size());
// for (size_t i=0; i<spaces.size(); i++)
// lights[i] = lightNode->transform(spaces[i]);
//
// group.push_back(new SceneGraph::AnimatedLightNode(std::move(lights),spaces.time_range));
}
}
// else if (Ref<SceneGraph::AnimatedPerspectiveCameraNode> cameraNode = node.dynamicCast<SceneGraph::AnimatedPerspectiveCameraNode>())
// {
// 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<SceneGraph::PerspectiveCameraNode> cameraNode = node.dynamicCast<SceneGraph::PerspectiveCameraNode>())
// {
// if (spaces.size() == 1)
// group.push_back(new SceneGraph::PerspectiveCameraNode(cameraNode,spaces[0],makeUniqueID(cameraNode->name)));
// else
// {
// std::vector<Ref<SceneGraph::PerspectiveCameraNode>> cameras(spaces.size());
// for (size_t i=0; i<spaces.size(); i++)
// cameras[i] = new SceneGraph::PerspectiveCameraNode(cameraNode,spaces[i]);
//
// group.push_back(new SceneGraph::AnimatedPerspectiveCameraNode(std::move(cameras),spaces.time_range,makeUniqueID(cameraNode->name)));
// }
// }
}
void convertGeometries(std::vector<Ref<SceneGraph::Node>> &group, const Ref<SceneGraph::Node> &node,
const SceneGraph::Transformations &spaces) {
/*if (Ref<SceneGraph::TransformNode> xfmNode = node.dynamicCast<SceneGraph::TransformNode>()) {
convertGeometries(group, xfmNode->child, spaces * xfmNode->spaces);
} else if (Ref<SceneGraph::MultiTransformNode> 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<SceneGraph::GroupNode> groupNode = node.dynamicCast<SceneGraph::GroupNode>()) {
for (const auto &child: groupNode->children)
convertGeometries(group, child, spaces);
} else if (Ref<SceneGraph::TriangleMeshNode> mesh = node.dynamicCast<SceneGraph::TriangleMeshNode>()) {
group.push_back(new SceneGraph::TriangleMeshNode(mesh, spaces));
} /*else if (Ref<SceneGraph::QuadMeshNode> mesh = node.dynamicCast<SceneGraph::QuadMeshNode>()) {
group.push_back(new SceneGraph::QuadMeshNode(mesh, spaces));
} else if (Ref<SceneGraph::GridMeshNode> mesh = node.dynamicCast<SceneGraph::GridMeshNode>()) {
group.push_back(new SceneGraph::GridMeshNode(mesh, spaces));
} else if (Ref<SceneGraph::SubdivMeshNode> mesh = node.dynamicCast<SceneGraph::SubdivMeshNode>()) {
group.push_back(new SceneGraph::SubdivMeshNode(mesh, spaces));
} else if (Ref<SceneGraph::HairSetNode> mesh = node.dynamicCast<SceneGraph::HairSetNode>()) {
group.push_back(new SceneGraph::HairSetNode(mesh, spaces));
} else if (Ref<SceneGraph::PointSetNode> mesh = node.dynamicCast<SceneGraph::PointSetNode>()) {
group.push_back(new SceneGraph::PointSetNode(mesh, spaces));
}*/
}
Ref<SceneGraph::Node> lookupGeometries(Ref<SceneGraph::Node> node) {
if (object_mapping.find(node) == object_mapping.end()) {
std::vector<Ref<SceneGraph::Node>> geometries;
convertGeometries(geometries, node, one);
object_mapping[node] = new SceneGraph::GroupNode(geometries);
}
return object_mapping[node];
}
void convertInstances(std::vector<Ref<SceneGraph::Node>> &group, const Ref<SceneGraph::Node> &node,
const std::vector<SceneGraph::Transformations> &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<SceneGraph::TransformNode> xfmNode = node.dynamicCast<SceneGraph::TransformNode>()) {
for (size_t i = 0; i < spaces.size(); ++i)
convertInstances(group, xfmNode->child, spaces[i] * xfmNode->spaces);
} else if (Ref<SceneGraph::MultiTransformNode> xfmNode = node.dynamicCast<
SceneGraph::MultiTransformNode>()) {
convertInstances(group, xfmNode->child, spaces * xfmNode->spaces);
} else */if (Ref<SceneGraph::GroupNode> groupNode = node.dynamicCast<SceneGraph::GroupNode>()) {
for (const auto &child: groupNode->children)
convertInstances(group, child, spaces);
}
}
void convertInstances(std::vector<Ref<SceneGraph::Node>> &group, const Ref<SceneGraph::Node> &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<SceneGraph::TransformNode> xfmNode = node.dynamicCast<SceneGraph::TransformNode>()) {
convertInstances(group, xfmNode->child, spaces * xfmNode->spaces);
} else if (Ref<SceneGraph::MultiTransformNode> xfmNode = node.dynamicCast<
SceneGraph::MultiTransformNode>()) {
convertInstances(group, xfmNode->child, spaces * xfmNode->spaces);
} else */if (Ref<SceneGraph::GroupNode> groupNode = node.dynamicCast<SceneGraph::GroupNode>()) {
for (const auto &child: groupNode->children)
convertInstances(group, child, spaces);
}
}
void convertMultiLevelInstances(std::vector<Ref<SceneGraph::Node>> &group, const Ref<SceneGraph::Node> &node) {
if (Ref<SceneGraph::GroupNode> groupNode = node.dynamicCast<SceneGraph::GroupNode>()) {
for (const auto &child: groupNode->children)
convertMultiLevelInstances(group, child);
} else if (node.dynamicCast<SceneGraph::TriangleMeshNode>()) {
group.push_back(node);
} /*else if (node.dynamicCast<SceneGraph::QuadMeshNode>()) {
group.push_back(node);
} else if (node.dynamicCast<SceneGraph::GridMeshNode>()) {
group.push_back(node);
} else if (node.dynamicCast<SceneGraph::SubdivMeshNode>()) {
group.push_back(node);
} else if (node.dynamicCast<SceneGraph::HairSetNode>()) {
group.push_back(node);
} else if (node.dynamicCast<SceneGraph::PointSetNode>()) {
group.push_back(node);
}*/ else if (object_mapping.find(node) != object_mapping.end()) {
group.push_back(object_mapping[node]);
} /*else if (Ref<SceneGraph::TransformNode> xfmNode = node.dynamicCast<SceneGraph::TransformNode>()) {
auto new_node = new SceneGraph::TransformNode(xfmNode->spaces,
convertMultiLevelInstances(xfmNode->child));
object_mapping[node] = new_node;
group.push_back(new_node);
} else if (Ref<SceneGraph::MultiTransformNode> 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<SceneGraph::Node> convertMultiLevelInstances(const Ref<SceneGraph::Node> &node) {
if (object_mapping.find(node) != object_mapping.end()) {
return object_mapping[node];
}
std::vector<Ref<SceneGraph::Node>> group;
convertMultiLevelInstances(group, node);
auto new_node = new SceneGraph::GroupNode(group);
object_mapping[node] = new_node;
return new_node;
}
void convertFlattenedInstances(std::vector<Ref<SceneGraph::Node>> &group, const Ref<SceneGraph::Node> &node) {
/*if (Ref<SceneGraph::TransformNode> xfmNode = node.dynamicCast<SceneGraph::TransformNode>()) {
group.push_back(node);
} else */if (Ref<SceneGraph::GroupNode> groupNode = node.dynamicCast<SceneGraph::GroupNode>()) {
for (const auto &child: groupNode->children)
convertFlattenedInstances(group, child);
}
}
};
Ref<SceneGraph::Node> SceneGraph::flatten(Ref<Node> node, InstancingMode mode) {
return SceneGraphFlattener(node, mode).node;
}
Ref<SceneGraph::GroupNode> SceneGraph::flatten(Ref<SceneGraph::GroupNode> node, SceneGraph::InstancingMode mode) {
return flatten(node.dynamicCast<SceneGraph::Node>(), mode).dynamicCast<SceneGraph::GroupNode>();
}
}

View file

@ -0,0 +1,663 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#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 "lights.h"
#include "embree4/rtcore.h"
RTC_NAMESPACE_USE
namespace embree {
struct Material;
namespace SceneGraph {
struct Node;
struct MaterialNode;
struct TriangleMeshNode;
struct Statistics {
Statistics()
: numTriangleMeshes(0), numTriangles(0), numTriangleBytes(0),
numQuadMeshes(0), numQuads(0), numQuadBytes(0),
numSubdivMeshes(0), numPatches(0), numSubdivBytes(0),
numCurveSets(0), numCurves(0), numCurveBytes(0),
numGridMeshNodes(0), numGrids(0), numGridBytes(0),
numPointSets(0), numPoints(0), numPointBytes(0),
numTransformNodes(0),
numTransformedObjects(0),
numLights(0),
numCameras(0),
numMaterials(0) {
}
void print();
size_t numTriangleMeshes;
size_t numTriangles;
size_t numTriangleBytes;
size_t numQuadMeshes;
size_t numQuads;
size_t numQuadBytes;
size_t numSubdivMeshes;
size_t numPatches;
size_t numSubdivBytes;
size_t numCurveSets;
size_t numCurves;
size_t numCurveBytes;
size_t numGridMeshNodes;
size_t numGrids;
size_t numGridBytes;
size_t numPointSets;
size_t numPoints;
size_t numPointBytes;
size_t numTransformNodes;
size_t numTransformedObjects;
size_t numLights;
size_t numCameras;
size_t numMaterials;
};
extern void (*opaque_geometry_destruction)(void*);
Ref<Node> load(const FileName& fname, bool singleObject = false);
struct Node : public RefCount {
Node(bool closed = false)
: indegree(0), closed(closed), hasLightOrCamera(false), id(-1), geometry(nullptr) {
}
Node(const std::string& name)
: name(name), indegree(0), closed(false), id(-1), geometry(nullptr) {
}
~Node() {
if (opaque_geometry_destruction)
opaque_geometry_destruction(geometry);
}
/* prints scenegraph */
virtual void print(std::ostream& cout, int depth = 0) = 0;
/* sets material */
virtual void setMaterial(Ref<MaterialNode> material) {
};
/* calculates the number of parent nodes pointing to this node */
virtual void calculateInDegree();
/* calculates for each node if its subtree is closed, indegrees have to be calculated first */
virtual bool calculateClosed(bool group_instancing);
/* resets the number of parent nodes pointing to this node */
virtual void resetInDegree();
/* checks if the node is closed */
__forceinline bool isClosed() const { return closed; }
/* calculates bounding box of node */
virtual BBox3fa bounds() const {
return empty;
}
virtual BBox3fa bounds(size_t i) const {
return empty;
}
/* calculates linear bounding box of node */
virtual LBBox3fa lbounds() const {
return empty;
}
virtual LBBox3fa lbounds(size_t i) const {
return empty;
}
/* calculates number of primitives */
virtual size_t numPrimitives() const {
return 0;
}
public:
std::string fileName; // when set to some filename the exporter references this file
std::string name; // name of this node
size_t indegree; // number of nodes pointing to us
bool closed; // determines if the subtree may represent an instance
bool hasLightOrCamera;
unsigned int id;
void* geometry;
};
struct Transformations {
__forceinline Transformations() {
}
__forceinline Transformations(OneTy)
: time_range(0.0f, 1.0f) {
spaces.push_back(one);
}
__forceinline Transformations(const BBox1f& time_range, size_t N)
: time_range(time_range), spaces(N) {
}
__forceinline Transformations(const AffineSpace3fa& space)
: time_range(0.0f, 1.0f) {
spaces.push_back(space);
}
__forceinline Transformations(const AffineSpace3fa& space0, const AffineSpace3fa& space1)
: time_range(0.0f, 1.0f) {
spaces.push_back(space0);
spaces.push_back(space1);
}
__forceinline Transformations(const avector<AffineSpace3ff>& spaces)
: time_range(0.0f, 1.0f), spaces(spaces) { assert(spaces.size()); }
__forceinline size_t size() const {
return spaces.size();
}
__forceinline AffineSpace3ff& operator[](const size_t i) { return spaces[i]; }
__forceinline const AffineSpace3ff& operator[](const size_t i) const { return spaces[i]; }
BBox3fa bounds(const BBox3fa& cbounds) const {
BBox3fa r = empty;
for (size_t i = 0; i < spaces.size(); i++)
r.extend(xfmBounds(spaces[i], cbounds));
return r;
}
LBBox3fa lbounds(const LBBox3fa& cbounds) const {
assert(spaces.size());
if (spaces.size() == 1) {
return LBBox3fa(xfmBounds(spaces[0], cbounds.bounds0),
xfmBounds(spaces[0], cbounds.bounds1));
} else {
avector<BBox3fa> bounds(spaces.size());
for (size_t i = 0; i < spaces.size(); i++) {
const float f = float(i) / float(spaces.size() - 1);
bounds[i] = xfmBounds(spaces[i], cbounds.interpolate(f));
}
return LBBox3fa(bounds);
}
}
void add(const Transformations& other) {
for (size_t i = 0; i < other.size(); i++) spaces.push_back(other[i]);
}
static __forceinline bool isIdentity(AffineSpace3ff const& M, bool q) {
if (M.l.vx.x != 1.f) return false;
if (M.l.vx.y != 0.f) return false;
if (M.l.vx.z != 0.f) return false;
if (q && M.l.vx.w != 0.f) return false;
if (M.l.vy.x != 0.f) return false;
if (M.l.vy.y != 1.f) return false;
if (M.l.vy.z != 0.f) return false;
if (q && M.l.vy.w != 0.f) return false;
if (M.l.vz.x != 0.f) return false;
if (M.l.vz.y != 0.f) return false;
if (M.l.vz.z != 1.f) return false;
if (q && M.l.vz.w != 0.f) return false;
if (M.p.x != 0.f) return false;
if (M.p.y != 0.f) return false;
if (M.p.z != 0.f) return false;
if (q && M.p.w != 1.f) return false;
return true;
}
static __forceinline AffineSpace3ff mul(AffineSpace3ff const& M0, AffineSpace3ff const& M1, bool q0,
bool q1, bool& q) {
q = false;
if (isIdentity(M0, q0)) {
q = q1;
return M1;
}
if (isIdentity(M1, q1)) {
q = q0;
return M0;
}
// simple case non of the transformations is a quaternion
if (q0 == false && q1 == false) {
return M0 * M1;
} else if (q0 == true && q1 == true) {
std::cout <<
"warning: cannot multiply two quaternion decompositions. will convert to regular transforms and multiply"
<< std::endl;
return quaternionDecompositionToAffineSpace(M0) * quaternionDecompositionToAffineSpace(M1);
} else if (q0 == true && q1 == false) {
AffineSpace3fa S;
Quaternion3f Q;
Vec3fa T;
quaternionDecomposition(M0, T, Q, S);
S = S * AffineSpace3fa(M1);
if (S.l.vx.y != 0.f || S.l.vx.z != 0 || S.l.vy.z != 0)
std::cout <<
"warning: cannot multiply quaternion and general transformation matrix. will ignore lower diagonal"
<< std::endl;
q = true;
return quaternionDecomposition(T, Q, S);
} else {
if (M0.l.vx.y != 0.f || M0.l.vx.z != 0 || M0.l.vy.z != 0 || M0.l.vy.x != 0.f || M0.l.vz.x != 0 || M0
.l.vz.y != 0)
std::cout <<
"warning: cannot multiply general transformation matrix and quaternion. will only consider translation and diagonal as scale factors"
<< std::endl;
AffineSpace3ff M = M1;
M.l.vx.y += M0.p.x;
M.l.vx.z += M0.p.y;
M.l.vy.z += M0.p.z;
M.l.vx.x *= M0.l.vx.x;
M.l.vy.y *= M0.l.vy.y;
M.l.vz.z *= M0.l.vz.z;
q = true;
return M;
}
}
friend __forceinline Transformations operator*(const Transformations& a, const Transformations& b) {
if (a.size() == 1) {
Transformations c(intersect(a.time_range, b.time_range), b.size());
for (size_t i = 0; i < b.size(); i++)
c[i] = mul(a[0], b[i], a.quaternion, b.quaternion,
c.quaternion);
return c;
} else if (b.size() == 1) {
Transformations c(intersect(a.time_range, b.time_range), a.size());
c.quaternion = a.quaternion || b.quaternion;
for (size_t i = 0; i < a.size(); i++)
c[i] = mul(a[i], b[0], a.quaternion, b.quaternion,
c.quaternion);
return c;
} else if (a.size() == b.size()) {
Transformations c(intersect(a.time_range, b.time_range), a.size());
c.quaternion = a.quaternion || b.quaternion;
for (size_t i = 0; i < a.size(); i++)
c[i] = mul(a[i], b[i], a.quaternion, b.quaternion,
c.quaternion);
return c;
} else
THROW_RUNTIME_ERROR("number of transformations does not match");
}
friend __forceinline std::vector<Transformations> operator*(const std::vector<Transformations>& a,
const Transformations& b) {
std::vector<Transformations> result;
for (size_t i = 0; i < a.size(); ++i) {
result.push_back(a[i] * b);
}
return result;
}
friend __forceinline std::vector<Transformations> operator*(const Transformations& a,
const std::vector<Transformations>& b) {
return b * a;
}
friend __forceinline std::vector<Transformations> operator*(const std::vector<Transformations>& a,
const std::vector<Transformations>& b) {
if (a.size() != b.size())
THROW_RUNTIME_ERROR("number of transformations does not match");
std::vector<Transformations> result;
for (size_t i = 0; i < a.size(); ++i) {
result.push_back(a[i] * b[i]);
}
return result;
}
AffineSpace3ff interpolate(const float gtime) const {
assert(time_range.lower == 0.0f && time_range.upper == 1.0f);
if (spaces.size() == 1) return spaces[0];
/* calculate time segment itime and fractional time ftime */
const int time_segments = int(spaces.size() - 1);
const float time = gtime * float(time_segments);
const int itime = clamp(int(floor(time)), 0, time_segments - 1);
const float ftime = time - float(itime);
return lerp(spaces[itime + 0], spaces[itime + 1], ftime);
}
public:
BBox1f time_range;
avector<AffineSpace3ff> spaces;
bool quaternion = false;
};
inline std::vector<avector<Vec3fa> > transformMSMBlurVec3faBuffer(
const std::vector<avector<Vec3fa> >& positions_in, const Transformations& spaces) {
std::vector<avector<Vec3fa> > positions_out;
const size_t num_time_steps = positions_in.size();
assert(num_time_steps);
const size_t num_vertices = positions_in[0].size();
/* if we have only one set of vertices, use transformation to generate more vertex sets */
if (num_time_steps == 1) {
for (size_t i = 0; i < spaces.size(); i++) {
avector<Vec3fa> verts(num_vertices);
for (size_t j = 0; j < num_vertices; j++) {
verts[j] = xfmPoint((AffineSpace3fa) spaces[i], positions_in[0][j]);
}
positions_out.push_back(std::move(verts));
}
}
/* otherwise transform all vertex sets with interpolated transformation */
else {
for (size_t t = 0; t < num_time_steps; t++) {
float time = num_time_steps > 1 ? float(t) / float(num_time_steps - 1) : 0.0f;
const AffineSpace3ff space = spaces.interpolate(time);
avector<Vec3fa> verts(num_vertices);
for (size_t i = 0; i < num_vertices; i++) {
verts[i] = xfmPoint((AffineSpace3fa) space, positions_in[t][i]);
}
positions_out.push_back(std::move(verts));
}
}
return positions_out;
}
template<typename Vertex>
std::vector<avector<Vertex> > transformMSMBlurNormalBuffer(const std::vector<avector<Vertex> >& normals_in,
const Transformations& spaces) {
if (normals_in.size() == 0)
return normals_in;
std::vector<avector<Vertex> > normals_out;
const size_t num_time_steps = normals_in.size();
const size_t num_vertices = normals_in[0].size();
/* if we have only one set of vertices, use transformation to generate more vertex sets */
if (num_time_steps == 1) {
for (size_t i = 0; i < spaces.size(); i++) {
avector<Vertex> norms(num_vertices);
for (size_t j = 0; j < num_vertices; j++) {
norms[j] = xfmNormal((AffineSpace3fa) spaces[i], normals_in[0][j]);
}
normals_out.push_back(std::move(norms));
}
}
/* otherwise transform all vertex sets with interpolated transformation */
else {
for (size_t t = 0; t < num_time_steps; t++) {
float time = num_time_steps > 1 ? float(t) / float(num_time_steps - 1) : 0.0f;
const AffineSpace3ff space = spaces.interpolate(time);
avector<Vertex> norms(num_vertices);
for (size_t i = 0; i < num_vertices; i++) {
norms[i] = xfmNormal((AffineSpace3fa) space, normals_in[t][i]);
}
normals_out.push_back(std::move(norms));
}
}
return normals_out;
}
struct GroupNode : public Node {
GroupNode(const size_t N = 0) {
children.resize(N);
}
GroupNode(std::vector<Ref<Node> >& children)
: children(children) {
}
size_t size() const {
return children.size();
}
void add(const Ref<Node>& node) {
if (node)
children.push_back(node);
}
void set(const size_t i, const Ref<Node>& node) {
children[i] = node;
}
Ref<Node> child(size_t i) const {
return children[i];
}
virtual BBox3fa bounds() const {
BBox3fa b = empty;
for (auto& c: children)
b.extend(c->bounds());
return b;
}
virtual LBBox3fa lbounds() const {
LBBox3fa b = empty;
for (auto& c: children)
b.extend(c->lbounds());
return b;
}
virtual size_t numPrimitives() const {
size_t n = 0;
for (auto& child: children)
n += child->numPrimitives();
return n;
}
virtual void setMaterial(Ref<MaterialNode> material) {
for (auto& child: children)
child->setMaterial(material);
}
virtual void print(std::ostream& cout, int depth);
virtual void calculateInDegree();
virtual bool calculateClosed(bool group_instancing);
virtual void resetInDegree();
public:
std::vector<Ref<Node> > children;
};
struct MaterialNode : public Node {
ALIGNED_STRUCT_USM_(16)
MaterialNode(const std::string& name = "")
: Node(name) {
}
virtual Material* material() = 0;
virtual void print(std::ostream& cout, int depth);
};
/*! Mesh. */
struct TriangleMeshNode : public Node {
typedef Vec3fa Vertex;
struct Triangle {
public:
Triangle() {
}
Triangle(int v0, int v1, int v2)
: v0(v0), v1(v1), v2(v2) {
}
public:
int v0, v1, v2;
};
public:
TriangleMeshNode(const avector<Vertex>& positions_in,
const avector<Vertex>& normals_in,
const std::vector<Vec2f>& texcoords,
const std::vector<Triangle>& triangles,
Ref<MaterialNode> material)
: Node(true), time_range(0.0f, 1.0f), texcoords(texcoords), triangles(triangles), material(material) {
positions.push_back(positions_in);
normals.push_back(normals_in);
}
TriangleMeshNode(Ref<MaterialNode> material, const BBox1f time_range = BBox1f(0, 1),
size_t numTimeSteps = 0)
: Node(true), time_range(time_range), material(material) {
for (size_t i = 0; i < numTimeSteps; i++)
positions.push_back(avector<Vertex>());
}
TriangleMeshNode(Ref<SceneGraph::TriangleMeshNode> imesh, const Transformations& spaces)
: Node(true),
time_range(imesh->time_range),
positions(transformMSMBlurVec3faBuffer(imesh->positions, spaces)),
normals(transformMSMBlurNormalBuffer(imesh->normals, spaces)),
texcoords(imesh->texcoords), triangles(imesh->triangles), material(imesh->material) {
}
virtual void setMaterial(Ref<MaterialNode> material) {
this->material = material;
}
virtual BBox3fa bounds() const {
BBox3fa b = empty;
for (const auto& p: positions)
for (auto& x: p)
b.extend(x);
return b;
}
virtual LBBox3fa lbounds() const {
avector<BBox3fa> bboxes(positions.size());
for (size_t t = 0; t < positions.size(); t++) {
BBox3fa b = empty;
for (auto& x: positions[t])
b.extend(x);
bboxes[t] = b;
}
return LBBox3fa(bboxes);
}
virtual size_t numPrimitives() const {
return triangles.size();
}
size_t numVertices() const {
assert(positions.size());
return positions[0].size();
}
size_t numTimeSteps() const {
return positions.size();
}
size_t numBytes() const {
return numPrimitives() * sizeof(Triangle) + numVertices() * numTimeSteps() * sizeof(Vertex);
}
void verify() const;
virtual void print(std::ostream& cout, int depth);
virtual void calculateInDegree();
virtual void resetInDegree();
public:
BBox1f time_range;
std::vector<avector<Vertex> > positions;
std::vector<avector<Vertex> > normals;
std::vector<Vec2f> texcoords;
std::vector<Triangle> triangles;
Ref<MaterialNode> material;
};
struct LightNode : public Node {
virtual void print(std::ostream& cout, int depth);
virtual void calculateStatistics(Statistics& stat);
virtual bool calculateClosed(bool group_instancing);
virtual LightType getType() const = 0;
virtual Ref<LightNode> transform(const AffineSpace3fa& space) const = 0;
virtual Ref<LightNode> lerp(const Ref<LightNode>& light1_in, float f) const = 0;
virtual Ref<LightNode> get(float time) const = 0;
};
template<typename Light>
struct LightNodeImpl : public LightNode {
ALIGNED_STRUCT_(16);
LightNodeImpl(const Light& light)
: light(light) {
}
virtual LightType getType() const {
return light.getType();
}
virtual Ref<LightNode> transform(const AffineSpace3fa& space) const {
return new LightNodeImpl(light.transform(space));
}
virtual Ref<LightNode> get(float time) const {
return (LightNode *) this;
}
virtual Ref<LightNode> lerp(const Ref<LightNode>& light1_in, float f) const {
const Ref<LightNodeImpl<Light> > light1 = light1_in.dynamicCast<LightNodeImpl<Light> >();
assert(light1);
return new LightNodeImpl(Light::lerp(light, light1->light, f));
}
Light light;
};
enum InstancingMode {
INSTANCING_NONE, INSTANCING_GEOMETRY, INSTANCING_GROUP, INSTANCING_FLATTENED, INSTANCING_MULTI_LEVEL
};
Ref<Node> flatten(Ref<Node> node, InstancingMode mode);
Ref<GroupNode> flatten(Ref<GroupNode> node, InstancingMode mode);
}
}
#include "materials.h"