shading normal support
parent
a1f61825ad
commit
6d38247551
|
@ -42,24 +42,30 @@ namespace {
|
||||||
|
|
||||||
/// Temporary storage for patch-ray intersections
|
/// Temporary storage for patch-ray intersections
|
||||||
struct PatchIntersectionRecord {
|
struct PatchIntersectionRecord {
|
||||||
Point p; //< Intersection in local coordinates
|
Point p;
|
||||||
int x, y;
|
int x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Stack entry for recursive quadtree traversal
|
||||||
|
struct StackEntry {
|
||||||
|
int level, x, y;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Heightfield : public Shape {
|
class Heightfield : public Shape {
|
||||||
public:
|
public:
|
||||||
Heightfield(const Properties &props) : Shape(props), m_data(NULL) {
|
Heightfield(const Properties &props) : Shape(props), m_data(NULL), m_normals(NULL) {
|
||||||
m_sizeHint = Vector2i(
|
m_sizeHint = Vector2i(
|
||||||
props.getInteger("width", -1),
|
props.getInteger("width", -1),
|
||||||
props.getInteger("height", -1)
|
props.getInteger("height", -1)
|
||||||
);
|
);
|
||||||
|
|
||||||
m_objectToWorld = props.getTransform("toWorld", Transform());
|
m_objectToWorld = props.getTransform("toWorld", Transform());
|
||||||
|
m_shadingNormals = props.getBoolean("shadingNormals", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Heightfield(Stream *stream, InstanceManager *manager)
|
Heightfield(Stream *stream, InstanceManager *manager)
|
||||||
: Shape(stream, manager), m_data(NULL) {
|
: Shape(stream, manager), m_data(NULL), m_normals(NULL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
~Heightfield() {
|
~Heightfield() {
|
||||||
|
@ -72,6 +78,8 @@ public:
|
||||||
delete[] m_numChildren;
|
delete[] m_numChildren;
|
||||||
delete[] m_blockSize;
|
delete[] m_blockSize;
|
||||||
}
|
}
|
||||||
|
if (m_normals)
|
||||||
|
freeAligned(m_normals);
|
||||||
}
|
}
|
||||||
|
|
||||||
void serialize(Stream *stream, InstanceManager *manager) const {
|
void serialize(Stream *stream, InstanceManager *manager) const {
|
||||||
|
@ -98,18 +106,6 @@ public:
|
||||||
return (size_t) m_levelSize[0].x * (size_t) m_levelSize[0].y;
|
return (size_t) m_levelSize[0].x * (size_t) m_levelSize[0].y;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StackEntry {
|
|
||||||
int level;
|
|
||||||
int x, y;
|
|
||||||
|
|
||||||
inline std::string toString() const {
|
|
||||||
std::ostringstream oss;
|
|
||||||
oss << "StackEntry[level=" << level << ", x=" << x << ", y=" << y << "]";
|
|
||||||
return oss.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
bool rayIntersect(const Ray &_ray, Float mint, Float maxt, Float &t, void *tmp) const {
|
bool rayIntersect(const Ray &_ray, Float mint, Float maxt, Float &t, void *tmp) const {
|
||||||
StackEntry stack[MTS_QTREE_MAXDEPTH];
|
StackEntry stack[MTS_QTREE_MAXDEPTH];
|
||||||
|
|
||||||
|
@ -172,7 +168,6 @@ public:
|
||||||
|
|
||||||
while ((uint32_t) x < (uint32_t) numChildren.x &&
|
while ((uint32_t) x < (uint32_t) numChildren.x &&
|
||||||
(uint32_t) y < (uint32_t) numChildren.y && t <= tMax) {
|
(uint32_t) y < (uint32_t) numChildren.y && t <= tMax) {
|
||||||
SAssert(stackIdx+1 < MTS_QTREE_MAXDEPTH);
|
|
||||||
stack[++stackIdx].level = entry.level;
|
stack[++stackIdx].level = entry.level;
|
||||||
stack[stackIdx].x = entry.x + x;
|
stack[stackIdx].x = entry.x + x;
|
||||||
stack[stackIdx].y = entry.y + y;
|
stack[stackIdx].y = entry.y + y;
|
||||||
|
@ -245,11 +240,27 @@ public:
|
||||||
its.uv = Point2(its.p.x / m_levelSize[0].x, its.p.y / m_levelSize[0].y);
|
its.uv = Point2(its.p.x / m_levelSize[0].x, its.p.y / m_levelSize[0].y);
|
||||||
its.dpdu = Vector(1, 0, (1.0f - temp.p.y) * (f10 - f00) + temp.p.y * (f11 - f01)) * m_levelSize[0].x;
|
its.dpdu = Vector(1, 0, (1.0f - temp.p.y) * (f10 - f00) + temp.p.y * (f11 - f01)) * m_levelSize[0].x;
|
||||||
its.dpdv = Vector(0, 1, (1.0f - temp.p.x) * (f01 - f00) + temp.p.x * (f11 - f10)) * m_levelSize[0].y;
|
its.dpdv = Vector(0, 1, (1.0f - temp.p.x) * (f01 - f00) + temp.p.x * (f11 - f10)) * m_levelSize[0].y;
|
||||||
|
|
||||||
its.geoFrame.s = normalize(its.dpdu);
|
its.geoFrame.s = normalize(its.dpdu);
|
||||||
its.geoFrame.t = normalize(its.dpdv - dot(its.dpdv, its.geoFrame.s) * its.geoFrame.s);
|
its.geoFrame.t = normalize(its.dpdv - dot(its.dpdv, its.geoFrame.s) * its.geoFrame.s);
|
||||||
its.geoFrame.n = cross(its.geoFrame.s, its.geoFrame.t);
|
its.geoFrame.n = cross(its.geoFrame.s, its.geoFrame.t);
|
||||||
|
|
||||||
its.shFrame = its.geoFrame;
|
if (m_shadingNormals) {
|
||||||
|
Normal
|
||||||
|
n00 = m_normals[y * width + x],
|
||||||
|
n01 = m_normals[(y+1) * width + x],
|
||||||
|
n10 = m_normals[y * width + x + 1],
|
||||||
|
n11 = m_normals[(y+1) * width + x + 1];
|
||||||
|
|
||||||
|
its.shFrame.n = normalize(
|
||||||
|
(1 - temp.p.x) * ((1-temp.p.y) * n00 + temp.p.y * n01)
|
||||||
|
+ temp.p.x * ((1-temp.p.y) * n10 + temp.p.y * n11));
|
||||||
|
|
||||||
|
its.shFrame.s = normalize(its.geoFrame.s - dot(its.geoFrame.s, its.shFrame.n) * its.shFrame.n);
|
||||||
|
its.shFrame.t = cross(its.shFrame.n, its.shFrame.s);
|
||||||
|
} else {
|
||||||
|
its.shFrame = its.geoFrame;
|
||||||
|
}
|
||||||
its.shape = this;
|
its.shape = this;
|
||||||
|
|
||||||
its.wi = its.toLocal(-ray.d);
|
its.wi = its.toLocal(-ray.d);
|
||||||
|
@ -266,6 +277,9 @@ public:
|
||||||
void addChild(const std::string &name, ConfigurableObject *child) {
|
void addChild(const std::string &name, ConfigurableObject *child) {
|
||||||
const Class *cClass = child->getClass();
|
const Class *cClass = child->getClass();
|
||||||
if (cClass->derivesFrom(Texture::m_theClass)) {
|
if (cClass->derivesFrom(Texture::m_theClass)) {
|
||||||
|
if (m_data != NULL)
|
||||||
|
Log(EError, "Attempted to attach multiple textures to a height field shape!");
|
||||||
|
|
||||||
ref<Bitmap> bitmap = static_cast<Texture *>(child)->getBitmap(m_sizeHint);
|
ref<Bitmap> bitmap = static_cast<Texture *>(child)->getBitmap(m_sizeHint);
|
||||||
|
|
||||||
m_dataSize = bitmap->getSize();
|
m_dataSize = bitmap->getSize();
|
||||||
|
@ -287,6 +301,14 @@ public:
|
||||||
size_t size = (size_t) m_dataSize.x * (size_t) m_dataSize.y * sizeof(Float),
|
size_t size = (size_t) m_dataSize.x * (size_t) m_dataSize.y * sizeof(Float),
|
||||||
storageSize = size;
|
storageSize = size;
|
||||||
m_data = (Float *) allocAligned(size);
|
m_data = (Float *) allocAligned(size);
|
||||||
|
|
||||||
|
if (m_shadingNormals) {
|
||||||
|
size *= 3;
|
||||||
|
m_normals = (Normal *) allocAligned(size);
|
||||||
|
memset(m_normals, 0, size);
|
||||||
|
storageSize += size;
|
||||||
|
}
|
||||||
|
|
||||||
bitmap->convert(m_data, Bitmap::ELuminance, Bitmap::EFloat);
|
bitmap->convert(m_data, Bitmap::ELuminance, Bitmap::EFloat);
|
||||||
|
|
||||||
Log(EInfo, "Building acceleration data structure for %ix%i height field ..", m_dataSize.x, m_dataSize.y);
|
Log(EInfo, "Building acceleration data structure for %ix%i height field ..", m_dataSize.x, m_dataSize.y);
|
||||||
|
@ -310,16 +332,16 @@ public:
|
||||||
Interval *bounds = m_minmax[0];
|
Interval *bounds = m_minmax[0];
|
||||||
for (int y=0; y<m_levelSize[0].y; ++y) {
|
for (int y=0; y<m_levelSize[0].y; ++y) {
|
||||||
for (int x=0; x<m_levelSize[0].x; ++x) {
|
for (int x=0; x<m_levelSize[0].x; ++x) {
|
||||||
Float v00 = m_data[y * m_dataSize.x + x];
|
Float f00 = m_data[y * m_dataSize.x + x];
|
||||||
Float v01 = m_data[y * m_dataSize.x + x + 1];
|
Float f10 = m_data[y * m_dataSize.x + x + 1];
|
||||||
Float v10 = m_data[(y + 1) * m_dataSize.x + x];
|
Float f01 = m_data[(y + 1) * m_dataSize.x + x];
|
||||||
Float v11 = m_data[(y + 1) * m_dataSize.x + x + 1];
|
Float f11 = m_data[(y + 1) * m_dataSize.x + x + 1];
|
||||||
Float vmin = std::min(std::min(v00, v01), std::min(v10, v11));
|
Float fmin = std::min(std::min(f00, f01), std::min(f10, f11));
|
||||||
Float vmax = std::max(std::max(v00, v01), std::max(v10, v11));
|
Float fmax = std::max(std::max(f00, f01), std::max(f10, f11));
|
||||||
*bounds++ = Interval(vmin, vmax);
|
*bounds++ = Interval(fmin, fmax);
|
||||||
|
|
||||||
/* Estimate the total surface area (this is approximate) */
|
/* Estimate the total surface area (this is approximate) */
|
||||||
Float diff0 = v01-v10, diff1 = v00-v11;
|
Float diff0 = f01-f10, diff1 = f00-f11;
|
||||||
m_surfaceArea += std::sqrt(1.0f + .5f * (diff0*diff0 + diff1*diff1));
|
m_surfaceArea += std::sqrt(1.0f + .5f * (diff0*diff0 + diff1*diff1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,17 +375,42 @@ public:
|
||||||
for (int x=0; x<cur.x; ++x) {
|
for (int x=0; x<cur.x; ++x) {
|
||||||
int x0 = std::min(2*x, prev.x-1),
|
int x0 = std::min(2*x, prev.x-1),
|
||||||
x1 = std::min(2*x+1, prev.x-1);
|
x1 = std::min(2*x+1, prev.x-1);
|
||||||
const Interval &v00 = prevBounds[y0 * prev.x + x0], &v01 = prevBounds[y0 * prev.x + x1];
|
const Interval &f00 = prevBounds[y0 * prev.x + x0], &f01 = prevBounds[y0 * prev.x + x1];
|
||||||
const Interval &v10 = prevBounds[y1 * prev.x + x0], &v11 = prevBounds[y1 * prev.x + x1];
|
const Interval &f10 = prevBounds[y1 * prev.x + x0], &f11 = prevBounds[y1 * prev.x + x1];
|
||||||
Interval combined(v00);
|
Interval combined(f00);
|
||||||
combined.expandBy(v01);
|
combined.expandBy(f01);
|
||||||
combined.expandBy(v10);
|
combined.expandBy(f10);
|
||||||
combined.expandBy(v11);
|
combined.expandBy(f11);
|
||||||
*curBounds++ = combined;
|
*curBounds++ = combined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_shadingNormals) {
|
||||||
|
Log(EInfo, "Precomputing shading normals ..");
|
||||||
|
|
||||||
|
for (int y=0; y<m_levelSize[0].y; ++y) {
|
||||||
|
for (int x=0; x<m_levelSize[0].x; ++x) {
|
||||||
|
Float f00 = m_data[y * m_dataSize.x + x];
|
||||||
|
Float f10 = m_data[y * m_dataSize.x + x + 1];
|
||||||
|
Float f01 = m_data[(y + 1) * m_dataSize.x + x];
|
||||||
|
Float f11 = m_data[(y + 1) * m_dataSize.x + x + 1];
|
||||||
|
|
||||||
|
m_normals[y * m_dataSize.x + x] += normalize(Normal(f00 - f10, f00 - f01, 1));
|
||||||
|
m_normals[y * m_dataSize.x + x + 1] += normalize(Normal(f00 - f10, f10 - f11, 1));
|
||||||
|
m_normals[(y + 1) * m_dataSize.x + x] += normalize(Normal(f01 - f11, f00 - f01, 1));
|
||||||
|
m_normals[(y + 1) * m_dataSize.x + x + 1] += normalize(Normal(f01 - f11, f10 - f11, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y=0; y<m_dataSize.y; ++y) {
|
||||||
|
for (int x=0; x<m_dataSize.x; ++x) {
|
||||||
|
Normal &normal = m_normals[x + y * m_dataSize.x];
|
||||||
|
normal /= normal.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log(EInfo, "Done (took %i ms, uses %s of memory)", timer->getMilliseconds(),
|
Log(EInfo, "Done (took %i ms, uses %s of memory)", timer->getMilliseconds(),
|
||||||
memString(storageSize).c_str());
|
memString(storageSize).c_str());
|
||||||
|
|
||||||
|
@ -388,9 +435,11 @@ private:
|
||||||
Transform m_objectToWorld;
|
Transform m_objectToWorld;
|
||||||
Vector2i m_sizeHint;
|
Vector2i m_sizeHint;
|
||||||
AABB m_dataAABB;
|
AABB m_dataAABB;
|
||||||
|
bool m_shadingNormals;
|
||||||
|
|
||||||
/* Height field data */
|
/* Height field data */
|
||||||
Float *m_data;
|
Float *m_data;
|
||||||
|
Normal *m_normals;
|
||||||
Vector2i m_dataSize;
|
Vector2i m_dataSize;
|
||||||
Float m_surfaceArea;
|
Float m_surfaceArea;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue