717 lines
26 KiB
C++
717 lines
26 KiB
C++
// 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);
|
|
};
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
/*! 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,
|
|
Ref<LightNode> lightnode = 0
|
|
)
|
|
: Node(true), time_range(0.0f, 1.0f), texcoords(texcoords), triangles(triangles), material(material), light(lightnode){
|
|
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), light(imesh->light) {
|
|
}
|
|
|
|
virtual void setMaterial(Ref<MaterialNode> material) {
|
|
this->material = material;
|
|
}
|
|
|
|
virtual void setLight(Ref<LightNode> light) {
|
|
this->light = light;
|
|
}
|
|
|
|
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();
|
|
|
|
protected:
|
|
TriangleMeshNode() {
|
|
|
|
}
|
|
|
|
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;
|
|
Ref<LightNode> light;
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
// QuadLightMesh is responsible for creating a mesh that represents the light and the light itself. latter the light is added automatically to the scenegraph
|
|
struct QuadLightMesh : public TriangleMeshNode {
|
|
// Constructor that takes parameters to set up the quad light mesh and its light node
|
|
QuadLightMesh(const Vec3fa& vertex0, const Vec3fa& vertex1, const Vec3fa& vertex2, const Vec3fa& vertex3,
|
|
const Vec3fa& radiance)
|
|
: TriangleMeshNode() { // Initialize the base class
|
|
|
|
|
|
material = 0;
|
|
// Initialize positions vector for vertices
|
|
positions.resize(1); // Resize to handle one timestep by default
|
|
positions[0].push_back(vertex0);
|
|
positions[0].push_back(vertex1);
|
|
positions[0].push_back(vertex2);
|
|
positions[0].push_back(vertex3);
|
|
|
|
// Initialize normals vector for vertices
|
|
normals.resize(1); // Assuming one normal per vertex for one timestep
|
|
normals[0].push_back(Vec3fa(0, -1, 0)); // Assuming the normal pointing downwards
|
|
normals[0].push_back(Vec3fa(0, -1, 0));
|
|
normals[0].push_back(Vec3fa(0, -1, 0));
|
|
normals[0].push_back(Vec3fa(0, -1, 0));
|
|
|
|
// Define triangles for the quad
|
|
triangles.push_back(Triangle(0, 1, 2));
|
|
triangles.push_back(Triangle(0, 3, 1));
|
|
|
|
// Initialize light node with the quad light
|
|
light = new SceneGraph::LightNodeImpl<SceneGraph::QuadLight>(
|
|
SceneGraph::QuadLight(vertex0, vertex1, vertex2, vertex3, radiance));
|
|
|
|
// Set texture coordinates if necessary (can be omitted if not used)
|
|
texcoords = std::vector<Vec2f>();
|
|
|
|
// This class only manages a single timestep by default
|
|
time_range = BBox1f(0, 1);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
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"
|