Added some vegetation rendering optimizations

This commit is contained in:
Michaël Lemaire 2015-11-10 01:12:14 +01:00
parent f990ec4032
commit e2d03642f4
10 changed files with 96 additions and 59 deletions

View file

@ -4,13 +4,18 @@
#include "PackStream.h" #include "PackStream.h"
CappedCylinder::CappedCylinder(const Vector3 &base, const Vector3 &direction, double radius, double length) CappedCylinder::CappedCylinder(const Vector3 &base, const Vector3 &direction, double radius, double length)
: InfiniteCylinder(InfiniteRay(base, direction), radius), length(length) { : InfiniteCylinder(InfiniteRay(base, direction), radius), length(length),
container(base.add(direction.scale(length * 0.5)), length * 0.5) {
} }
int CappedCylinder::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, int CappedCylinder::findRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection,
Vector3 *second_intersection) const { Vector3 *second_intersection) const {
if (not container.checkRayIntersection(ray)) {
// We don't hit the containing sphere at all
return 0;
} else {
// TODO Apply the caps // TODO Apply the caps
int count = InfiniteCylinder::checkRayIntersection(ray, first_intersection, second_intersection); int count = InfiniteCylinder::findRayIntersection(ray, first_intersection, second_intersection);
if (count == 0) { if (count == 0) {
return 0; return 0;
@ -37,6 +42,7 @@ int CappedCylinder::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_
return 0; return 0;
} }
} }
}
} }
bool CappedCylinder::checkPointProjection(Vector3 *point) const { bool CappedCylinder::checkPointProjection(Vector3 *point) const {

View file

@ -4,6 +4,7 @@
#include "basics_global.h" #include "basics_global.h"
#include "InfiniteCylinder.h" #include "InfiniteCylinder.h"
#include "Sphere.h"
namespace paysages { namespace paysages {
namespace basics { namespace basics {
@ -22,8 +23,10 @@ class BASICSSHARED_EXPORT CappedCylinder : public InfiniteCylinder {
/** /**
* Check the intersection between the cylinder and an infinite ray. * Check the intersection between the cylinder and an infinite ray.
*
* Returns the number of intersections (0, 1 or 2) and fill the intersection points.
*/ */
int checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const; int findRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const;
/** /**
* Check if a point projects in the length of the finite cylinder. * Check if a point projects in the length of the finite cylinder.
@ -35,6 +38,7 @@ class BASICSSHARED_EXPORT CappedCylinder : public InfiniteCylinder {
private: private:
double length; double length;
Sphere container;
}; };
} }
} }

View file

@ -8,7 +8,7 @@ InfiniteCylinder::InfiniteCylinder(const InfiniteRay &axis, double radius) : axi
validate(); validate();
} }
int InfiniteCylinder::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, int InfiniteCylinder::findRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection,
Vector3 *second_intersection) const { Vector3 *second_intersection) const {
/* /*
* Original algorithm has been altered, because it didn't work with non-(0,0,0) axis origin. * Original algorithm has been altered, because it didn't work with non-(0,0,0) axis origin.

View file

@ -28,7 +28,7 @@ class BASICSSHARED_EXPORT InfiniteCylinder {
* *
* Returns the number of intersections (0, 1 or 2) and fill the intersection points. * Returns the number of intersections (0, 1 or 2) and fill the intersection points.
*/ */
int checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const; int findRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const;
virtual void save(PackStream *stream) const; virtual void save(PackStream *stream) const;
virtual void load(PackStream *stream); virtual void load(PackStream *stream);

View file

@ -7,7 +7,22 @@ Sphere::Sphere(const Vector3 &center, double radius) : center(center), radius(ra
radius2 = radius * radius; radius2 = radius * radius;
} }
int Sphere::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, int Sphere::checkRayIntersection(const InfiniteRay &ray) const {
Vector3 L = ray.getOrigin().sub(center);
double b = 2.0 * ray.getDirection().dotProduct(L);
double c = L.dotProduct(L) - radius2;
double discr = b * b - 4.0 * c;
if (discr < 0) {
return 0;
} else if (discr == 0) {
return 1;
} else {
return 2;
}
}
int Sphere::findRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection,
Vector3 *second_intersection) const { Vector3 *second_intersection) const {
Vector3 L = ray.getOrigin().sub(center); Vector3 L = ray.getOrigin().sub(center);
double b = 2.0 * ray.getDirection().dotProduct(L); double b = 2.0 * ray.getDirection().dotProduct(L);

View file

@ -24,11 +24,18 @@ class BASICSSHARED_EXPORT Sphere {
} }
/** /**
* Check the intersection between the sphere and an infinite ray. * Check for intersections between the sphere and an infinite ray.
*
* Returns the number of intersections (0, 1 or 2).
*/
int checkRayIntersection(const InfiniteRay &ray) const;
/**
* Get the intersections between the sphere and an infinite ray.
* *
* Returns the number of intersections (0, 1 or 2) and fill the intersection points. * Returns the number of intersections (0, 1 or 2) and fill the intersection points.
*/ */
int checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const; int findRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection, Vector3 *second_intersection) const;
void save(PackStream *stream) const; void save(PackStream *stream) const;
void load(PackStream *stream); void load(PackStream *stream);

View file

@ -30,7 +30,7 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment,
for (const auto &branch : model->getSolidVolumes()) { for (const auto &branch : model->getSolidVolumes()) {
Vector3 near, far; Vector3 near, far;
if (branch.checkRayIntersection(ray, &near, &far)) { if (branch.findRayIntersection(ray, &near, &far)) {
distance = ray.getCursor(near); distance = ray.getCursor(near);
if (distance >= 0.0 and distance <= maximal) { if (distance >= 0.0 and distance <= maximal) {
// Got a branch hit // Got a branch hit
@ -54,8 +54,7 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment,
} }
for (const auto &foliage : model->getFoliageGroups()) { for (const auto &foliage : model->getFoliageGroups()) {
Vector3 near, far; intersections = foliage.checkRayIntersection(ray);
intersections = foliage.checkRayIntersection(ray, &near, &far);
if (intersections == 2) { if (intersections == 2) {
InfiniteRay subray(ray.getOrigin().sub(foliage.getCenter()).scale(1.0 / foliage.getRadius()), InfiniteRay subray(ray.getOrigin().sub(foliage.getCenter()).scale(1.0 / foliage.getRadius()),
ray.getDirection()); ray.getDirection());
@ -63,19 +62,19 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment,
for (const auto &leaf : model->getFoliageItems()) { for (const auto &leaf : model->getFoliageItems()) {
Sphere leafcap(leaf.getPoint(), leaf.getRadius() * leaf.getRadius() / foliage.getRadius()); Sphere leafcap(leaf.getPoint(), leaf.getRadius() * leaf.getRadius() / foliage.getRadius());
// TODO Add cap intersection to Sphere class // TODO Add cap intersection to Sphere class
Vector3 capnear, capfar; Vector3 near, far;
if (leafcap.checkRayIntersection(subray, &capnear, &capfar) == 2) { if (leafcap.findRayIntersection(subray, &near, &far) == 2) {
if (capnear.sub(leaf.getPoint()).normalize().dotProduct(leaf.getNormal()) < 0.5) { if (near.sub(leaf.getPoint()).normalize().dotProduct(leaf.getNormal()) < 0.5) {
if (capfar.sub(leaf.getPoint()).normalize().dotProduct(leaf.getNormal()) < 0.5) { if (far.sub(leaf.getPoint()).normalize().dotProduct(leaf.getNormal()) < 0.5) {
continue; continue;
} else { } else {
capnear = capfar; near = far;
} }
} }
Vector3 capnormal = capnear.sub(leaf.getPoint()).normalize(); Vector3 capnormal = near.sub(leaf.getPoint()).normalize();
capnear = capnear.scale(foliage.getRadius()).add(foliage.getCenter()); near = near.scale(foliage.getRadius()).add(foliage.getCenter());
distance = ray.getCursor(capnear); distance = ray.getCursor(near);
if (distance >= 0.0 and distance <= maximal) { if (distance >= 0.0 and distance <= maximal) {
// Got a foliage hit // Got a foliage hit
@ -88,7 +87,7 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment,
nearest = distance; nearest = distance;
hit = true; hit = true;
location = capnear; location = near;
normal = capnormal; normal = capnormal;
if (normal.dotProduct(location.sub(segment.getStart())) > 0.0) { if (normal.dotProduct(location.sub(segment.getStart())) > 0.0) {

View file

@ -2,43 +2,43 @@
#include "CappedCylinder.h" #include "CappedCylinder.h"
TEST(CappedCylinder, checkRayIntersection) { TEST(CappedCylinder, findRayIntersection) {
CappedCylinder cylinder(VECTOR_DOWN, VECTOR_UP, 1.0, 2.0); CappedCylinder cylinder(VECTOR_DOWN, VECTOR_UP, 1.0, 2.0);
int intersect_count; int intersect_count;
Vector3 p1, p2; Vector3 p1, p2;
intersect_count = intersect_count =
cylinder.checkRayIntersection(InfiniteRay(Vector3(1.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2); cylinder.findRayIntersection(InfiniteRay(Vector3(1.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
EXPECT_EQ(0, intersect_count); EXPECT_EQ(0, intersect_count);
intersect_count = intersect_count =
cylinder.checkRayIntersection(InfiniteRay(Vector3(1.0, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2); cylinder.findRayIntersection(InfiniteRay(Vector3(1.0, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
EXPECT_EQ(1, intersect_count); EXPECT_EQ(1, intersect_count);
EXPECT_VECTOR3_COORDS(p1, 1.0, 0.0, 0.0); EXPECT_VECTOR3_COORDS(p1, 1.0, 0.0, 0.0);
intersect_count = intersect_count =
cylinder.checkRayIntersection(InfiniteRay(Vector3(0.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2); cylinder.findRayIntersection(InfiniteRay(Vector3(0.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
EXPECT_EQ(2, intersect_count); EXPECT_EQ(2, intersect_count);
EXPECT_VECTOR3_COORDS(p1, 0.5, 0.0, -cos(asin(0.5))); EXPECT_VECTOR3_COORDS(p1, 0.5, 0.0, -cos(asin(0.5)));
EXPECT_VECTOR3_COORDS(p2, 0.5, 0.0, cos(asin(0.5))); EXPECT_VECTOR3_COORDS(p2, 0.5, 0.0, cos(asin(0.5)));
intersect_count = intersect_count =
cylinder.checkRayIntersection(InfiniteRay(Vector3(0.5, -2.1, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2); cylinder.findRayIntersection(InfiniteRay(Vector3(0.5, -2.1, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
EXPECT_EQ(0, intersect_count); EXPECT_EQ(0, intersect_count);
intersect_count = intersect_count =
cylinder.checkRayIntersection(InfiniteRay(Vector3(0.5, 2.1, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2); cylinder.findRayIntersection(InfiniteRay(Vector3(0.5, 2.1, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
EXPECT_EQ(0, intersect_count); EXPECT_EQ(0, intersect_count);
// diagonal cases (through a cap) // diagonal cases (through a cap)
intersect_count = intersect_count =
cylinder.checkRayIntersection(InfiniteRay(Vector3(-2.0, -1.0, 0.0), Vector3(1.0, 1.0, 0.0)), &p1, &p2); cylinder.findRayIntersection(InfiniteRay(Vector3(-2.0, -1.0, 0.0), Vector3(1.0, 1.0, 0.0)), &p1, &p2);
EXPECT_EQ(1, intersect_count); EXPECT_EQ(1, intersect_count);
EXPECT_VECTOR3_COORDS(p1, -1.0, 0.0, 0.0); EXPECT_VECTOR3_COORDS(p1, -1.0, 0.0, 0.0);
intersect_count = intersect_count =
cylinder.checkRayIntersection(InfiniteRay(Vector3(-2.0, 3.0, 0.0), Vector3(1.0, -1.0, 0.0)), &p1, &p2); cylinder.findRayIntersection(InfiniteRay(Vector3(-2.0, 3.0, 0.0), Vector3(1.0, -1.0, 0.0)), &p1, &p2);
EXPECT_EQ(1, intersect_count); EXPECT_EQ(1, intersect_count);
EXPECT_VECTOR3_COORDS(p1, 1.0, 0.0, 0.0); EXPECT_VECTOR3_COORDS(p1, 1.0, 0.0, 0.0);
} }

View file

@ -4,7 +4,7 @@
#include "InfiniteCylinder.h" #include "InfiniteCylinder.h"
#include <cmath> #include <cmath>
TEST(InfiniteCylinder, checkRayIntersection) { TEST(InfiniteCylinder, findRayIntersection) {
InfiniteRay ray(VECTOR_ZERO, VECTOR_UP); InfiniteRay ray(VECTOR_ZERO, VECTOR_UP);
InfiniteCylinder cylinder(ray, 1.0); InfiniteCylinder cylinder(ray, 1.0);
@ -12,29 +12,29 @@ TEST(InfiniteCylinder, checkRayIntersection) {
Vector3 p1, p2; Vector3 p1, p2;
intersect_count = intersect_count =
cylinder.checkRayIntersection(InfiniteRay(Vector3(1.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2); cylinder.findRayIntersection(InfiniteRay(Vector3(1.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
EXPECT_EQ(0, intersect_count); EXPECT_EQ(0, intersect_count);
intersect_count = intersect_count =
cylinder.checkRayIntersection(InfiniteRay(Vector3(1.0, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2); cylinder.findRayIntersection(InfiniteRay(Vector3(1.0, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
EXPECT_EQ(1, intersect_count); EXPECT_EQ(1, intersect_count);
EXPECT_VECTOR3_COORDS(p1, 1.0, 0.0, 0.0); EXPECT_VECTOR3_COORDS(p1, 1.0, 0.0, 0.0);
intersect_count = intersect_count =
cylinder.checkRayIntersection(InfiniteRay(Vector3(0.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2); cylinder.findRayIntersection(InfiniteRay(Vector3(0.5, 0.0, 0.0), Vector3(0.0, 0.0, 1.0)), &p1, &p2);
EXPECT_EQ(2, intersect_count); EXPECT_EQ(2, intersect_count);
EXPECT_VECTOR3_COORDS(p1, 0.5, 0.0, -cos(asin(0.5))); EXPECT_VECTOR3_COORDS(p1, 0.5, 0.0, -cos(asin(0.5)));
EXPECT_VECTOR3_COORDS(p2, 0.5, 0.0, cos(asin(0.5))); EXPECT_VECTOR3_COORDS(p2, 0.5, 0.0, cos(asin(0.5)));
} }
TEST(InfiniteCylinder, checkRayIntersection2) { TEST(InfiniteCylinder, getRayIntersection2) {
InfiniteRay ray(Vector3(-1.4, 1.5, 1.0), Vector3(1.0, 0.0, 0.0)); InfiniteRay ray(Vector3(-1.4, 1.5, 1.0), Vector3(1.0, 0.0, 0.0));
InfiniteCylinder cylinder(ray, 0.5); InfiniteCylinder cylinder(ray, 0.5);
int intersect_count; int intersect_count;
Vector3 p1, p2; Vector3 p1, p2;
intersect_count = cylinder.checkRayIntersection( intersect_count = cylinder.findRayIntersection(
InfiniteRay::fromPoints(Vector3(0.0, 1.5, 0.0), Vector3(0.0, 1.5, 2.0)), &p1, &p2); InfiniteRay::fromPoints(Vector3(0.0, 1.5, 0.0), Vector3(0.0, 1.5, 2.0)), &p1, &p2);
EXPECT_EQ(2, intersect_count); EXPECT_EQ(2, intersect_count);
EXPECT_VECTOR3_COORDS(p1, 0.0, 1.5, 0.5); EXPECT_VECTOR3_COORDS(p1, 0.0, 1.5, 0.5);

View file

@ -3,20 +3,26 @@
#include "InfiniteRay.h" #include "InfiniteRay.h"
#include "Sphere.h" #include "Sphere.h"
TEST(Sphere, checkRayIntersection) { TEST(Sphere, findRayIntersection) {
Sphere sphere(Vector3(2.0, 1.0, 1.0), 0.5); Sphere sphere(Vector3(2.0, 1.0, 1.0), 0.5);
int intersect_count; int intersect_count;
Vector3 p1, p2; Vector3 p1, p2;
intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(0.0, 0.0, 0.0), VECTOR_SOUTH), &p1, &p2); intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(0.0, 0.0, 0.0), VECTOR_SOUTH));
ASSERT_EQ(0, intersect_count); EXPECT_EQ(0, intersect_count);
intersect_count = sphere.findRayIntersection(InfiniteRay(Vector3(0.0, 0.0, 0.0), VECTOR_SOUTH), &p1, &p2);
EXPECT_EQ(0, intersect_count);
intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(1.5, 1.0, 0.0), VECTOR_SOUTH), &p1, &p2); intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(1.5, 1.0, 0.0), VECTOR_SOUTH));
EXPECT_EQ(1, intersect_count);
intersect_count = sphere.findRayIntersection(InfiniteRay(Vector3(1.5, 1.0, 0.0), VECTOR_SOUTH), &p1, &p2);
ASSERT_EQ(1, intersect_count); ASSERT_EQ(1, intersect_count);
EXPECT_VECTOR3_COORDS(p1, 1.5, 1.0, 1.0); EXPECT_VECTOR3_COORDS(p1, 1.5, 1.0, 1.0);
intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(2.0, 1.0, 0.0), VECTOR_SOUTH), &p1, &p2); intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(2.0, 1.0, 0.0), VECTOR_SOUTH));
EXPECT_EQ(2, intersect_count);
intersect_count = sphere.findRayIntersection(InfiniteRay(Vector3(2.0, 1.0, 0.0), VECTOR_SOUTH), &p1, &p2);
ASSERT_EQ(2, intersect_count); ASSERT_EQ(2, intersect_count);
EXPECT_VECTOR3_COORDS(p1, 2.0, 1.0, 0.5); EXPECT_VECTOR3_COORDS(p1, 2.0, 1.0, 0.5);
EXPECT_VECTOR3_COORDS(p2, 2.0, 1.0, 1.5); EXPECT_VECTOR3_COORDS(p2, 2.0, 1.0, 1.5);