From 6d382475514df6969bb5f6c564734fc1e4f87b1f Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Tue, 10 Sep 2013 20:33:24 +0200 Subject: [PATCH] shading normal support --- src/shapes/heightfield.cpp | 111 ++++++++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 31 deletions(-) diff --git a/src/shapes/heightfield.cpp b/src/shapes/heightfield.cpp index c3630566..d159f5be 100644 --- a/src/shapes/heightfield.cpp +++ b/src/shapes/heightfield.cpp @@ -42,24 +42,30 @@ namespace { /// Temporary storage for patch-ray intersections struct PatchIntersectionRecord { - Point p; //< Intersection in local coordinates + Point p; int x, y; }; + + /// Stack entry for recursive quadtree traversal + struct StackEntry { + int level, x, y; + }; }; class Heightfield : public Shape { 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( props.getInteger("width", -1), props.getInteger("height", -1) ); m_objectToWorld = props.getTransform("toWorld", Transform()); + m_shadingNormals = props.getBoolean("shadingNormals", true); } Heightfield(Stream *stream, InstanceManager *manager) - : Shape(stream, manager), m_data(NULL) { + : Shape(stream, manager), m_data(NULL), m_normals(NULL) { } ~Heightfield() { @@ -72,6 +78,8 @@ public: delete[] m_numChildren; delete[] m_blockSize; } + if (m_normals) + freeAligned(m_normals); } 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; } - 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 { StackEntry stack[MTS_QTREE_MAXDEPTH]; @@ -172,7 +168,6 @@ public: while ((uint32_t) x < (uint32_t) numChildren.x && (uint32_t) y < (uint32_t) numChildren.y && t <= tMax) { - SAssert(stackIdx+1 < MTS_QTREE_MAXDEPTH); stack[++stackIdx].level = entry.level; stack[stackIdx].x = entry.x + x; 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.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.geoFrame.s = normalize(its.dpdu); 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.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.wi = its.toLocal(-ray.d); @@ -266,6 +277,9 @@ public: void addChild(const std::string &name, ConfigurableObject *child) { const Class *cClass = child->getClass(); if (cClass->derivesFrom(Texture::m_theClass)) { + if (m_data != NULL) + Log(EError, "Attempted to attach multiple textures to a height field shape!"); + ref bitmap = static_cast(child)->getBitmap(m_sizeHint); m_dataSize = bitmap->getSize(); @@ -287,6 +301,14 @@ public: size_t size = (size_t) m_dataSize.x * (size_t) m_dataSize.y * sizeof(Float), storageSize = 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); 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]; for (int y=0; ygetMilliseconds(), memString(storageSize).c_str()); @@ -388,9 +435,11 @@ private: Transform m_objectToWorld; Vector2i m_sizeHint; AABB m_dataAABB; + bool m_shadingNormals; /* Height field data */ Float *m_data; + Normal *m_normals; Vector2i m_dataSize; Float m_surfaceArea;