Optimized vegetation branches rendering
This commit is contained in:
parent
9a096ec329
commit
159e0f7e81
11 changed files with 91 additions and 95 deletions
|
@ -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) {
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#include "InfiniteRay.h"
|
||||
|
||||
InfiniteRay::InfiniteRay() {
|
||||
}
|
||||
|
||||
InfiniteRay::InfiniteRay(const Vector3 &origin, const Vector3 &direction)
|
||||
: origin(origin), direction(direction.normalize()) {
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@ double VegetationLayerDefinition::getMaxHeight() const {
|
|||
return presence->getMaxHeight();
|
||||
}
|
||||
|
||||
void VegetationLayerDefinition::applyPreset(VegetationLayerPreset preset) {
|
||||
void VegetationLayerDefinition::applyPreset(VegetationLayerPreset) {
|
||||
model->randomize();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue