Optimized vegetation branches rendering

This commit is contained in:
Michaël Lemaire 2015-11-10 00:15:30 +01:00
parent 9a096ec329
commit 159e0f7e81
11 changed files with 91 additions and 95 deletions

View file

@ -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) {
}

View file

@ -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 {

View file

@ -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;
}

View file

@ -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;
};
}
}

View file

@ -1,8 +1,5 @@
#include "InfiniteRay.h"
InfiniteRay::InfiniteRay() {
}
InfiniteRay::InfiniteRay(const Vector3 &origin, const Vector3 &direction)
: origin(origin), direction(direction.normalize()) {
}

View file

@ -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);

View file

@ -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;
}

View file

@ -3,9 +3,6 @@
#include "PackStream.h"
#include "InfiniteRay.h"
Sphere::Sphere() {
}
Sphere::Sphere(const Vector3 &center, double radius) : center(center), radius(radius) {
radius2 = radius * radius;
}

View file

@ -13,7 +13,7 @@ namespace basics {
*/
class BASICSSHARED_EXPORT Sphere {
public:
Sphere();
Sphere() = default;
Sphere(const Vector3 &center, double radius);
inline const Vector3 &getCenter() const {

View file

@ -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);
}

View file

@ -12,6 +12,6 @@ double VegetationLayerDefinition::getMaxHeight() const {
return presence->getMaxHeight();
}
void VegetationLayerDefinition::applyPreset(VegetationLayerPreset preset) {
void VegetationLayerDefinition::applyPreset(VegetationLayerPreset) {
model->randomize();
}