paysages3d/src/render/software/VegetationModelRenderer.cpp

131 lines
4.7 KiB
C++
Raw Normal View History

2015-10-18 15:26:19 +00:00
#include "VegetationModelRenderer.h"
#include "Color.h"
#include "SurfaceMaterial.h"
#include "SpaceSegment.h"
#include "InfiniteRay.h"
#include "Disk.h"
#include "SoftwareRenderer.h"
#include "LightComponent.h"
#include "VegetationModelDefinition.h"
#include "VegetationResult.h"
#ifndef NDEBUG
//#define DEBUG_VEGETATION_CONTAINERS 1
#endif
#ifdef DEBUG_VEGETATION_CONTAINERS
SurfaceMaterial DEBUG_MATERIAL1(Color(1.0, 0.0, 0.0));
#endif
VegetationModelRenderer::VegetationModelRenderer(SoftwareRenderer *parent, const VegetationModelDefinition *model)
: parent(parent), model(model) {
2015-10-18 15:26:19 +00:00
}
VegetationModelRenderer::~VegetationModelRenderer() {
2015-10-18 15:26:19 +00:00
}
VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment, bool only_hit) const {
2015-10-18 15:26:19 +00:00
InfiniteRay ray(segment.getStart(), segment.getDirection());
int intersections;
const SurfaceMaterial *material = &SurfaceMaterial::getDefault();
2015-10-18 15:26:19 +00:00
bool hit = false;
Vector3 location, normal;
double distance, nearest, maximal;
maximal = segment.getLength();
nearest = maximal;
for (const auto &branch : model->getSolidVolumes()) {
2015-10-18 15:26:19 +00:00
Vector3 near, far;
if (branch.findRayIntersection(ray, &near, &far)) {
2015-10-18 15:26:19 +00:00
distance = ray.getCursor(near);
if (distance >= 0.0 and distance <= maximal) {
2015-10-18 15:26:19 +00:00
// Got a branch hit
if (only_hit) {
2015-10-18 15:26:19 +00:00
return VegetationResult(true);
}
if (distance < nearest) {
material = &model->getSolidMaterial();
2015-10-18 15:26:19 +00:00
nearest = distance;
hit = true;
location = near;
normal = near.sub(branch.getAxis().getOrigin())
.crossProduct(branch.getAxis().getDirection())
.normalize();
2015-10-18 15:26:19 +00:00
normal = branch.getAxis().getDirection().crossProduct(normal).normalize();
}
}
}
}
for (const auto &foliage : model->getFoliageGroups()) {
intersections = foliage.checkRayIntersection(ray);
if (intersections == 2) {
InfiniteRay subray(ray.getOrigin().sub(foliage.getCenter()).scale(1.0 / foliage.getRadius()),
ray.getDirection());
2015-10-18 15:26:19 +00:00
for (const auto &leaf : model->getFoliageItems()) {
Sphere leafcap(leaf.getPoint(), leaf.getRadius() * leaf.getRadius() / foliage.getRadius());
// TODO Add cap intersection to Sphere class
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 {
near = far;
}
}
Vector3 capnormal = near.sub(leaf.getPoint()).normalize();
near = near.scale(foliage.getRadius()).add(foliage.getCenter());
distance = ray.getCursor(near);
2015-10-18 15:26:19 +00:00
if (distance >= 0.0 and distance <= maximal) {
2015-10-18 15:26:19 +00:00
// Got a foliage hit
if (only_hit) {
2015-10-18 15:26:19 +00:00
return VegetationResult(true);
}
if (distance < nearest) {
material = &model->getFoliageMaterial();
2015-10-18 15:26:19 +00:00
nearest = distance;
hit = true;
location = near;
normal = capnormal;
2015-10-18 15:26:19 +00:00
if (normal.dotProduct(location.sub(segment.getStart())) > 0.0) {
2015-10-18 15:26:19 +00:00
// We look at backside
normal = normal.scale(-1.0);
}
}
}
}
}
#ifdef DEBUG_VEGETATION_CONTAINERS
if (!hit) {
Vector3 near, far;
intersections = foliage.findRayIntersection(ray, &near, &far);
location = near;
normal = VECTOR_ZERO;
material = &DEBUG_MATERIAL1;
hit = true;
}
#endif
2015-10-18 15:26:19 +00:00
}
}
if (hit) {
return VegetationResult(location, normal, *material);
} else {
2015-10-18 15:26:19 +00:00
return VegetationResult();
}
}
bool VegetationModelRenderer::applyLightFilter(LightComponent &light, const Vector3 &at) {
2015-10-18 15:26:19 +00:00
return getResult(SpaceSegment(at, light.direction.scale(-2.0)), true).isHit();
}