Added some vegetation rendering optimizations
This commit is contained in:
parent
f990ec4032
commit
e2d03642f4
10 changed files with 96 additions and 59 deletions
|
@ -4,13 +4,18 @@
|
|||
#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 {
|
||||
if (not container.checkRayIntersection(ray)) {
|
||||
// We don't hit the containing sphere at all
|
||||
return 0;
|
||||
} else {
|
||||
// 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) {
|
||||
return 0;
|
||||
|
@ -38,6 +43,7 @@ int CappedCylinder::checkRayIntersection(const InfiniteRay &ray, Vector3 *first_
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CappedCylinder::checkPointProjection(Vector3 *point) const {
|
||||
double proj_length = axis.getDirection().dotProduct(point->sub(axis.getOrigin()));
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -7,7 +7,22 @@ Sphere::Sphere(const Vector3 ¢er, double radius) : center(center), radius(ra
|
|||
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 L = ray.getOrigin().sub(center);
|
||||
double b = 2.0 * ray.getDirection().dotProduct(L);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue