From 159e0f7e817c6b639bbbef026600524f339a2b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 10 Nov 2015 00:15:30 +0100 Subject: [PATCH] Optimized vegetation branches rendering --- src/basics/CappedCylinder.cpp | 3 - src/basics/CappedCylinder.h | 2 +- src/basics/InfiniteCylinder.cpp | 145 +++++++++---------- src/basics/InfiniteCylinder.h | 14 +- src/basics/InfiniteRay.cpp | 3 - src/basics/InfiniteRay.h | 2 +- src/basics/SpaceSegment.cpp | 8 +- src/basics/Sphere.cpp | 3 - src/basics/Sphere.h | 2 +- src/definition/VegetationInstance.cpp | 2 +- src/definition/VegetationLayerDefinition.cpp | 2 +- 11 files changed, 91 insertions(+), 95 deletions(-) diff --git a/src/basics/CappedCylinder.cpp b/src/basics/CappedCylinder.cpp index 8997e97..d508284 100644 --- a/src/basics/CappedCylinder.cpp +++ b/src/basics/CappedCylinder.cpp @@ -3,9 +3,6 @@ #include "Vector3.h" #include "PackStream.h" -CappedCylinder::CappedCylinder() { -} - CappedCylinder::CappedCylinder(const Vector3 &base, const Vector3 &direction, double radius, double length) : InfiniteCylinder(InfiniteRay(base, direction), radius), length(length) { } diff --git a/src/basics/CappedCylinder.h b/src/basics/CappedCylinder.h index 0b92956..dddf1b5 100644 --- a/src/basics/CappedCylinder.h +++ b/src/basics/CappedCylinder.h @@ -13,7 +13,7 @@ namespace basics { */ class BASICSSHARED_EXPORT CappedCylinder : public InfiniteCylinder { public: - CappedCylinder(); + CappedCylinder() = default; CappedCylinder(const Vector3 &base, const Vector3 &direction, double radius, double length); inline double getLength() const { diff --git a/src/basics/InfiniteCylinder.cpp b/src/basics/InfiniteCylinder.cpp index 4a7ae64..d13e230 100644 --- a/src/basics/InfiniteCylinder.cpp +++ b/src/basics/InfiniteCylinder.cpp @@ -4,10 +4,8 @@ #define EPS 1E-8 -InfiniteCylinder::InfiniteCylinder() { -} - InfiniteCylinder::InfiniteCylinder(const InfiniteRay &axis, double radius) : axis(axis), radius(radius) { + validate(); } int InfiniteCylinder::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, @@ -16,11 +14,75 @@ int InfiniteCylinder::checkRayIntersection(const InfiniteRay &ray, Vector3 *firs * Original algorithm has been altered, because it didn't work with non-(0,0,0) axis origin. * Maybe some optimizations could be made from this. */ + Vector3 Q, G, AG, AQ; + double c0, c1, c2, discr, invC2, root0, root1, root; - Vector3 U, V, F = axis.getDirection(), P, B, Q, G, AG, AQ; + /* line */ + Q = ray.getOrigin().sub(axis.getOrigin()); + G = ray.getDirection(); + + /* compute A*G */ + AG.x = A[0][0] * G.x + A[0][1] * G.y + A[0][2] * G.z; + AG.y = A[1][0] * G.x + A[1][1] * G.y + A[1][2] * G.z; + AG.z = A[2][0] * G.x + A[2][1] * G.y + A[2][2] * G.z; + + /* compute A*Q */ + AQ.x = A[0][0] * Q.x + A[0][1] * Q.y + A[0][2] * Q.z; + AQ.y = A[1][0] * Q.x + A[1][1] * Q.y + A[1][2] * Q.z; + AQ.z = A[2][0] * Q.x + A[2][1] * Q.y + A[2][2] * Q.z; + + /* compute quadratic equation c0+c1*t+c2*t^2 = 0 */ + c2 = G.x * AG.x + G.y * AG.y + G.z * AG.z; + c1 = 2.0f * (Q.x * AG.x + Q.y * AG.y + Q.z * AG.z); + c0 = Q.x * AQ.x + Q.y * AQ.y + Q.z * AQ.z + C; + + /* solve for intersections */ + int numIntersections; + discr = c1 * c1 - 4.0 * c0 * c2; + if (discr > EPS) { + numIntersections = 2; + discr = sqrt(discr); + invC2 = 1.0 / c2; + root0 = -0.5 * (c1 + discr) * invC2; + root1 = -0.5 * (c1 - discr) * invC2; + first_intersection->x = Q.x + root0 * G.x + ox; + first_intersection->y = Q.y + root0 * G.y + oy; + first_intersection->z = Q.z + root0 * G.z + oz; + second_intersection->x = Q.x + root1 * G.x + ox; + second_intersection->y = Q.y + root1 * G.y + oy; + second_intersection->z = Q.z + root1 * G.z + oz; + } else if (discr < -EPS) { + numIntersections = 0; + } else { + numIntersections = 1; + root = -0.5 * c1 / c2; + first_intersection->x = Q.x + root * G.x + ox; + first_intersection->y = Q.y + root * G.y + oy; + first_intersection->z = Q.z + root * G.z + oz; + } + + return numIntersections; +} + +void InfiniteCylinder::save(PackStream *stream) const { + axis.save(stream); + stream->write(&radius); +} + +void InfiniteCylinder::load(PackStream *stream) { + axis.load(stream); + stream->read(&radius); + + validate(); +} + +void InfiniteCylinder::validate() { + Vector3 U, V, F = axis.getDirection(); double length, invLength, prod; - double R[3][3], A[3][3]; - double e0, e1, C, c0, c1, c2, discr, invC2, root0, root1, root; + + ox = axis.getOrigin().x; + oy = axis.getOrigin().y; + oz = axis.getOrigin().z; /* choose U, V so that U,V,F is orthonormal set */ @@ -70,75 +132,6 @@ int InfiniteCylinder::checkRayIntersection(const InfiniteRay &ray, Vector3 *firs A[2][1] = R[0][2] * R[0][1] + R[1][2] * R[1][1]; A[2][2] = R[0][2] * R[0][2] + R[1][2] * R[1][2]; - /* vector B */ - P = Vector3(0.0, 0.0, 0.0); - B.x = -2.0 * P.x; - B.y = -2.0 * P.y; - B.z = -2.0 * P.z; - /* constant C */ - e0 = -2.0 * (R[0][0] * P.x + R[0][1] * P.y + R[0][2] * P.z); - e1 = -2.0 * (R[1][0] * P.x + R[1][1] * P.y + R[1][2] * P.z); - C = 0.25 * (e0 * e0 + e1 * e1) - radius * radius; - - /* line */ - Q = ray.getOrigin().sub(axis.getOrigin()); - G = ray.getDirection(); - - /* compute A*G */ - AG.x = A[0][0] * G.x + A[0][1] * G.y + A[0][2] * G.z; - AG.y = A[1][0] * G.x + A[1][1] * G.y + A[1][2] * G.z; - AG.z = A[2][0] * G.x + A[2][1] * G.y + A[2][2] * G.z; - - /* compute A*Q */ - AQ.x = A[0][0] * Q.x + A[0][1] * Q.y + A[0][2] * Q.z; - AQ.y = A[1][0] * Q.x + A[1][1] * Q.y + A[1][2] * Q.z; - AQ.z = A[2][0] * Q.x + A[2][1] * Q.y + A[2][2] * Q.z; - - /* compute quadratic equation c0+c1*t+c2*t^2 = 0 */ - c2 = G.x * AG.x + G.y * AG.y + G.z * AG.z; - c1 = B.x * G.x + B.y * G.y + B.z * G.z + 2.0f * (Q.x * AG.x + Q.y * AG.y + Q.z * AG.z); - c0 = Q.x * AQ.x + Q.y * AQ.y + Q.z * AQ.z + B.x * Q.x + B.y * Q.y + B.z * Q.z + C; - - /* solve for intersections */ - int numIntersections; - discr = c1 * c1 - 4.0 * c0 * c2; - if (discr > EPS) { - numIntersections = 2; - discr = sqrt(discr); - invC2 = 1.0 / c2; - root0 = -0.5 * (c1 + discr) * invC2; - root1 = -0.5 * (c1 - discr) * invC2; - first_intersection->x = Q.x + root0 * G.x; - first_intersection->y = Q.y + root0 * G.y; - first_intersection->z = Q.z + root0 * G.z; - second_intersection->x = Q.x + root1 * G.x; - second_intersection->y = Q.y + root1 * G.y; - second_intersection->z = Q.z + root1 * G.z; - - *first_intersection = first_intersection->add(axis.getOrigin()); - *second_intersection = second_intersection->add(axis.getOrigin()); - } else if (discr < -EPS) { - numIntersections = 0; - } else { - numIntersections = 1; - root = -0.5 * c1 / c2; - first_intersection->x = Q.x + root * G.x; - first_intersection->y = Q.y + root * G.y; - first_intersection->z = Q.z + root * G.z; - - *first_intersection = first_intersection->add(axis.getOrigin()); - } - - return numIntersections; -} - -void InfiniteCylinder::save(PackStream *stream) const { - axis.save(stream); - stream->write(&radius); -} - -void InfiniteCylinder::load(PackStream *stream) { - axis.load(stream); - stream->read(&radius); + C = -radius * radius; } diff --git a/src/basics/InfiniteCylinder.h b/src/basics/InfiniteCylinder.h index dcb053a..affbeca 100644 --- a/src/basics/InfiniteCylinder.h +++ b/src/basics/InfiniteCylinder.h @@ -13,7 +13,7 @@ namespace basics { */ class BASICSSHARED_EXPORT InfiniteCylinder { public: - InfiniteCylinder(); + InfiniteCylinder() = default; InfiniteCylinder(const InfiniteRay &axis, double radius); inline const InfiniteRay &getAxis() const { @@ -33,9 +33,21 @@ class BASICSSHARED_EXPORT InfiniteCylinder { virtual void save(PackStream *stream) const; virtual void load(PackStream *stream); + private: + void validate(); + protected: InfiniteRay axis; double radius; + + private: + // Stored equation factors, to speed up ray intersection + double R[3][3]; + double A[3][3]; + double C; + double ox; + double oy; + double oz; }; } } diff --git a/src/basics/InfiniteRay.cpp b/src/basics/InfiniteRay.cpp index 8bf68b8..0797076 100644 --- a/src/basics/InfiniteRay.cpp +++ b/src/basics/InfiniteRay.cpp @@ -1,8 +1,5 @@ #include "InfiniteRay.h" -InfiniteRay::InfiniteRay() { -} - InfiniteRay::InfiniteRay(const Vector3 &origin, const Vector3 &direction) : origin(origin), direction(direction.normalize()) { } diff --git a/src/basics/InfiniteRay.h b/src/basics/InfiniteRay.h index cbae484..dce5bed 100644 --- a/src/basics/InfiniteRay.h +++ b/src/basics/InfiniteRay.h @@ -13,7 +13,7 @@ namespace basics { */ class BASICSSHARED_EXPORT InfiniteRay { public: - InfiniteRay(); + InfiniteRay() = default; InfiniteRay(const Vector3 &origin, const Vector3 &direction); static InfiniteRay fromPoints(const Vector3 &point1, const Vector3 &point2); diff --git a/src/basics/SpaceSegment.cpp b/src/basics/SpaceSegment.cpp index ea1fd0b..aeebfb6 100644 --- a/src/basics/SpaceSegment.cpp +++ b/src/basics/SpaceSegment.cpp @@ -60,19 +60,19 @@ bool SpaceSegment::intersectBoundingBox(const SpaceSegment &bbox) const { double tmax = min(min(max(t1, t2), max(t3, t4)), max(t5, t6)); // if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us - double t; + //double t; if (tmax < 0.0) { - t = tmax; + //t = tmax; return false; } // if tmin > tmax, ray doesn't intersect AABB if (tmin > tmax) { - t = tmax; + //t = tmax; return false; } - t = tmin; + //t = tmin; return true; } diff --git a/src/basics/Sphere.cpp b/src/basics/Sphere.cpp index b1cda67..5a1a035 100644 --- a/src/basics/Sphere.cpp +++ b/src/basics/Sphere.cpp @@ -3,9 +3,6 @@ #include "PackStream.h" #include "InfiniteRay.h" -Sphere::Sphere() { -} - Sphere::Sphere(const Vector3 ¢er, double radius) : center(center), radius(radius) { radius2 = radius * radius; } diff --git a/src/basics/Sphere.h b/src/basics/Sphere.h index c1d0954..a9961ca 100644 --- a/src/basics/Sphere.h +++ b/src/basics/Sphere.h @@ -13,7 +13,7 @@ namespace basics { */ class BASICSSHARED_EXPORT Sphere { public: - Sphere(); + Sphere() = default; Sphere(const Vector3 ¢er, double radius); inline const Vector3 &getCenter() const { diff --git a/src/definition/VegetationInstance.cpp b/src/definition/VegetationInstance.cpp index ef68454..6e90ac7 100644 --- a/src/definition/VegetationInstance.cpp +++ b/src/definition/VegetationInstance.cpp @@ -5,6 +5,6 @@ VegetationInstance::VegetationInstance(const VegetationModelDefinition &model, c : model(model), base(base), size(size), angle(angle) { } -VegetationInstance VegetationInstance::displace(const Vector3 &location, const Vector3 &normal) const { +VegetationInstance VegetationInstance::displace(const Vector3 &location, const Vector3 &) const { return VegetationInstance(model, location, size, angle); } diff --git a/src/definition/VegetationLayerDefinition.cpp b/src/definition/VegetationLayerDefinition.cpp index bd932ec..ba60f46 100644 --- a/src/definition/VegetationLayerDefinition.cpp +++ b/src/definition/VegetationLayerDefinition.cpp @@ -12,6 +12,6 @@ double VegetationLayerDefinition::getMaxHeight() const { return presence->getMaxHeight(); } -void VegetationLayerDefinition::applyPreset(VegetationLayerPreset preset) { +void VegetationLayerDefinition::applyPreset(VegetationLayerPreset) { model->randomize(); }