Initial commit.
This commit is contained in:
commit
d3bb49b3f5
1073 changed files with 484757 additions and 0 deletions
190
Framework/scenegraph/lights.h
Normal file
190
Framework/scenegraph/lights.h
Normal 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;
|
||||
};
|
||||
}
|
||||
}
|
||||
263
Framework/scenegraph/materials.h
Normal file
263
Framework/scenegraph/materials.h
Normal 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
|
||||
715
Framework/scenegraph/obj_loader.cpp
Normal file
715
Framework/scenegraph/obj_loader.cpp
Normal 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>();
|
||||
}
|
||||
}
|
||||
12
Framework/scenegraph/obj_loader.h
Normal file
12
Framework/scenegraph/obj_loader.h
Normal 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);
|
||||
}
|
||||
411
Framework/scenegraph/scenegraph.cpp
Normal file
411
Framework/scenegraph/scenegraph.cpp
Normal 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>();
|
||||
}
|
||||
}
|
||||
663
Framework/scenegraph/scenegraph.h
Normal file
663
Framework/scenegraph/scenegraph.h
Normal 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"
|
||||
Loading…
Add table
Add a link
Reference in a new issue