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,38 +4,44 @@
#include "PackStream.h"
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 {
// TODO Apply the caps
int count = InfiniteCylinder::checkRayIntersection(ray, first_intersection, second_intersection);
if (count == 0) {
if (not container.checkRayIntersection(ray)) {
// We don't hit the containing sphere at all
return 0;
} else if (count == 2) {
if (checkPointProjection(first_intersection)) {
if (checkPointProjection(second_intersection)) {
return 2;
} else {
// TODO Apply the caps
int count = InfiniteCylinder::findRayIntersection(ray, first_intersection, second_intersection);
if (count == 0) {
return 0;
} else if (count == 2) {
if (checkPointProjection(first_intersection)) {
if (checkPointProjection(second_intersection)) {
return 2;
} else {
return 1;
}
} else {
return 1;
if (checkPointProjection(second_intersection)) {
*first_intersection = *second_intersection;
return 1;
} else {
return 0;
}
}
} else {
if (checkPointProjection(second_intersection)) {
*first_intersection = *second_intersection;
} else // count == 1
{
if (checkPointProjection(first_intersection)) {
return 1;
} else {
return 0;
}
}
} else // count == 1
{
if (checkPointProjection(first_intersection)) {
return 1;
} else {
return 0;
}
}
}

View file

@ -4,6 +4,7 @@
#include "basics_global.h"
#include "InfiniteCylinder.h"
#include "Sphere.h"
namespace paysages {
namespace basics {
@ -22,8 +23,10 @@ class BASICSSHARED_EXPORT CappedCylinder : public InfiniteCylinder {
/**
* 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.
@ -35,6 +38,7 @@ class BASICSSHARED_EXPORT CappedCylinder : public InfiniteCylinder {
private:
double length;
Sphere container;
};
}
}

View file

@ -8,7 +8,7 @@ InfiniteCylinder::InfiniteCylinder(const InfiniteRay &axis, double radius) : axi
validate();
}
int InfiniteCylinder::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection,
int InfiniteCylinder::findRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection,
Vector3 *second_intersection) const {
/*
* 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.
*/
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 load(PackStream *stream);

View file

@ -7,8 +7,23 @@ Sphere::Sphere(const Vector3 &center, double radius) : center(center), radius(ra
radius2 = radius * radius;
}
int Sphere::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_intersection,
Vector3 *second_intersection) const {
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 L = ray.getOrigin().sub(center);
double b = 2.0 * ray.getDirection().dotProduct(L);
double c = L.dotProduct(L) - radius2;

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.
*/
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 load(PackStream *stream);

View file

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

View file

@ -2,43 +2,43 @@
#include "CappedCylinder.h"
TEST(CappedCylinder, checkRayIntersection) {
TEST(CappedCylinder, findRayIntersection) {
CappedCylinder cylinder(VECTOR_DOWN, VECTOR_UP, 1.0, 2.0);
int intersect_count;
Vector3 p1, p2;
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);
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_VECTOR3_COORDS(p1, 1.0, 0.0, 0.0);
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_VECTOR3_COORDS(p1, 0.5, 0.0, -cos(asin(0.5)));
EXPECT_VECTOR3_COORDS(p2, 0.5, 0.0, cos(asin(0.5)));
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);
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);
// diagonal cases (through a cap)
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_VECTOR3_COORDS(p1, -1.0, 0.0, 0.0);
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_VECTOR3_COORDS(p1, 1.0, 0.0, 0.0);
}

View file

@ -4,7 +4,7 @@
#include "InfiniteCylinder.h"
#include <cmath>
TEST(InfiniteCylinder, checkRayIntersection) {
TEST(InfiniteCylinder, findRayIntersection) {
InfiniteRay ray(VECTOR_ZERO, VECTOR_UP);
InfiniteCylinder cylinder(ray, 1.0);
@ -12,29 +12,29 @@ TEST(InfiniteCylinder, checkRayIntersection) {
Vector3 p1, p2;
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);
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_VECTOR3_COORDS(p1, 1.0, 0.0, 0.0);
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_VECTOR3_COORDS(p1, 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));
InfiniteCylinder cylinder(ray, 0.5);
int intersect_count;
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);
EXPECT_EQ(2, intersect_count);
EXPECT_VECTOR3_COORDS(p1, 0.0, 1.5, 0.5);

View file

@ -3,20 +3,26 @@
#include "InfiniteRay.h"
#include "Sphere.h"
TEST(Sphere, checkRayIntersection) {
TEST(Sphere, findRayIntersection) {
Sphere sphere(Vector3(2.0, 1.0, 1.0), 0.5);
int intersect_count;
Vector3 p1, p2;
intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(0.0, 0.0, 0.0), VECTOR_SOUTH), &p1, &p2);
ASSERT_EQ(0, intersect_count);
intersect_count = sphere.checkRayIntersection(InfiniteRay(Vector3(0.0, 0.0, 0.0), VECTOR_SOUTH));
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);
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);
EXPECT_VECTOR3_COORDS(p1, 2.0, 1.0, 0.5);
EXPECT_VECTOR3_COORDS(p2, 2.0, 1.0, 1.5);