Tweaked vegetation rendering, and improved render tests

This commit is contained in:
Michaël Lemaire 2015-11-09 01:07:33 +01:00
parent bdb2a3edb8
commit 72877c4361
6 changed files with 76 additions and 51 deletions

View file

@ -4,13 +4,23 @@
#include "RandomGenerator.h" #include "RandomGenerator.h"
#include "Matrix4.h" #include "Matrix4.h"
#include "SurfaceMaterial.h" #include "SurfaceMaterial.h"
#include "Color.h"
#include "PackStream.h" #include "PackStream.h"
VegetationModelDefinition::VegetationModelDefinition(DefinitionNode *parent): VegetationModelDefinition::VegetationModelDefinition(DefinitionNode *parent):
DefinitionNode(parent, "model") DefinitionNode(parent, "model")
{ {
solid_material = new SurfaceMaterial(); solid_material = new SurfaceMaterial(Color(0.2, 0.15, 0.15));
foliage_material = new SurfaceMaterial(); solid_material->reflection = 0.002;
solid_material->shininess = 2.0;
solid_material->hardness = 0.3;
solid_material->validate();
foliage_material = new SurfaceMaterial(Color(0.4, 0.8, 0.45));
foliage_material->reflection = 0.007;
foliage_material->shininess = 12.0;
foliage_material->hardness = 0.2;
foliage_material->validate();
randomize(); randomize();
} }
@ -127,7 +137,10 @@ static void addBranchRecurse(std::vector<CappedCylinder> &branches, const Vector
new_direction = pivot2.multPoint(new_direction); new_direction = pivot2.multPoint(new_direction);
Vector3 new_base = base.add(direction.scale(randomizeValue(length, 0.4, 1.0))); Vector3 new_base = base.add(direction.scale(randomizeValue(length, 0.4, 1.0)));
addBranchRecurse(branches, new_base, new_direction, randomizeValue(radius, 0.45, 0.6), randomizeValue(length, 0.55, 0.85)); if (new_base.add(new_direction).y > 0.1)
{
addBranchRecurse(branches, new_base, new_direction, randomizeValue(radius, 0.45, 0.6), randomizeValue(length, 0.55, 0.85));
}
} }
} }
} }
@ -140,7 +153,7 @@ void VegetationModelDefinition::randomize()
foliage_items.clear(); foliage_items.clear();
// Add trunk and branches // Add trunk and branches
addBranchRecurse(solid_volumes, VECTOR_ZERO, VECTOR_UP, 0.04, 0.5); addBranchRecurse(solid_volumes, VECTOR_ZERO, VECTOR_UP, randomizeValue(0.05, 0.6, 1.0), randomizeValue(0.5, 0.8, 1.0));
// Add foliage groups // Add foliage groups
for (const auto &branch: solid_volumes) for (const auto &branch: solid_volumes)
@ -155,7 +168,7 @@ void VegetationModelDefinition::randomize()
} }
// Add foliage items // Add foliage items
for (int i = 0; i < 50; i++) for (int i = 0; i < 30; i++)
{ {
double radius = 0.15; double radius = 0.15;
double scale = randomizeValue(radius, 0.5, 1.0); double scale = randomizeValue(radius, 0.5, 1.0);

View file

@ -21,6 +21,9 @@ public:
VegetationModelDefinition(DefinitionNode *parent); VegetationModelDefinition(DefinitionNode *parent);
virtual ~VegetationModelDefinition(); virtual ~VegetationModelDefinition();
inline const SurfaceMaterial &getSolidMaterial() const {return *solid_material;}
inline const SurfaceMaterial &getFoliageMaterial() const {return *foliage_material;}
inline const std::vector<CappedCylinder> &getSolidVolumes() const {return solid_volumes;} inline const std::vector<CappedCylinder> &getSolidVolumes() const {return solid_volumes;}
inline const std::vector<Sphere> &getFoliageGroups() const {return foliage_groups;} inline const std::vector<Sphere> &getFoliageGroups() const {return foliage_groups;}
inline const std::vector<Disk> &getFoliageItems() const {return foliage_items;} inline const std::vector<Disk> &getFoliageItems() const {return foliage_items;}

View file

@ -110,12 +110,12 @@ static void testCloudQuality()
SoftwareCanvasRenderer renderer(&scenery); SoftwareCanvasRenderer renderer(&scenery);
renderer.setSize(600, 800); renderer.setSize(600, 800);
SkyRasterizer *rasterizer = new SkyRasterizer(&renderer, renderer.getProgressHelper(), 0); SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0);
renderer.setSoloRasterizer(rasterizer); renderer.setSoloRasterizer(&rasterizer);
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
renderer.setQuality((double)i / 5.0); renderer.setQuality((double)i / 5.0);
rasterizer->setQuality(0.2); rasterizer.setQuality(0.2);
startTestRender(&renderer, "cloud_quality", i); startTestRender(&renderer, "cloud_quality", i);
} }
} }
@ -164,8 +164,8 @@ static void testGodRays()
TestRenderer renderer(&scenery); TestRenderer renderer(&scenery);
renderer.setSize(500, 300); renderer.setSize(500, 300);
SkyRasterizer *rasterizer = new SkyRasterizer(&renderer, renderer.getProgressHelper(), 0); SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0);
renderer.setSoloRasterizer(rasterizer); renderer.setSoloRasterizer(&rasterizer);
TestLightFilter filter; TestLightFilter filter;
renderer.getLightingManager()->clearFilters(); renderer.getLightingManager()->clearFilters();
renderer.getLightingManager()->registerFilter(&filter); renderer.getLightingManager()->registerFilter(&filter);
@ -174,7 +174,7 @@ static void testGodRays()
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
renderer.setQuality((double)i / 5.0); renderer.setQuality((double)i / 5.0);
rasterizer->setQuality(0.2); rasterizer.setQuality(0.2);
startTestRender(&renderer, "god_rays_quality", i); startTestRender(&renderer, "god_rays_quality", i);
} }
renderer.setQuality(0.5); renderer.setQuality(0.5);
@ -259,25 +259,42 @@ static void testSunNearHorizon()
static void testVegetationModels() static void testVegetationModels()
{ {
class TestRasterizer: public OverlayRasterizer class InstanceRenderer: public SoftwareCanvasRenderer, public OverlayRasterizer, public LightFilter
{ {
public: public:
TestRasterizer(SoftwareCanvasRenderer *renderer, const VegetationModelDefinition &model): InstanceRenderer(Scenery *scenery, const VegetationModelDefinition &model):
OverlayRasterizer(renderer, renderer->getProgressHelper()), SoftwareCanvasRenderer(scenery),
OverlayRasterizer(this, this->getProgressHelper()),
instance(model, VECTOR_ZERO), instance(model, VECTOR_ZERO),
vegetation(renderer->getVegetationRenderer()) vegetation(renderer->getVegetationRenderer())
{ {
} }
virtual void prepare() override
{
SoftwareCanvasRenderer::prepare();
getLightingManager()->clearFilters();
getLightingManager()->registerFilter(this);
// TODO Add filter for vegetation instance (for self shadows)
}
virtual Color applyMediumTraversal(const Vector3&, const Color &color) override
{
return color;
}
virtual Color processPixel(int, int, double relx, double rely) const override virtual Color processPixel(int, int, double relx, double rely) const override
{ {
relx *= 0.75; relx *= 0.75;
rely *= 0.75; rely *= 0.75;
SpaceSegment segment(Vector3(relx, rely + 0.5, -5.0), Vector3(relx, rely + 0.5, 5.0)); SpaceSegment segment(Vector3(relx, rely + 0.5, 5.0), Vector3(relx, rely + 0.5, -5.0));
RayCastingResult result = vegetation->renderInstance(segment, instance, false, true); RayCastingResult result = vegetation->renderInstance(segment, instance, false, true);
return result.hit ? result.hit_color : Color(0.6, 0.7, 0.9); return result.hit ? result.hit_color : Color(0.6, 0.7, 0.9);
} }
virtual bool applyLightFilter(LightComponent &light, const Vector3 &at) override
{
SpaceSegment segment(at, at.add(light.direction.scale(-5.0)));
RayCastingResult result = vegetation->renderInstance(segment, instance, true, true);
return not result.hit;
}
VegetationInstance instance; VegetationInstance instance;
VegetationRenderer *vegetation; VegetationRenderer *vegetation;
}; };
@ -285,21 +302,18 @@ static void testVegetationModels()
Scenery scenery; Scenery scenery;
scenery.autoPreset(1); scenery.autoPreset(1);
scenery.getClouds()->clear(); scenery.getClouds()->clear();
scenery.getTerrain()->propWaterHeight()->setValue(1.0);
scenery.getCamera()->setTarget(VECTOR_ZERO); scenery.getCamera()->setTarget(VECTOR_ZERO);
scenery.getCamera()->setLocation(Vector3(0.0, 0.0, -5.0)); scenery.getCamera()->setLocation(Vector3(0.0, 0.0, 5.0));
int width = 800; int width = 800;
int height = 800; int height = 800;
SoftwareCanvasRenderer renderer(&scenery);
renderer.setSize(width, height);
renderer.setQuality(0.5);
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
// TODO Make random sequence repeatable // TODO Make random sequence repeatable
VegetationModelDefinition model(NULL); VegetationModelDefinition model(NULL);
renderer.setSoloRasterizer(new TestRasterizer(&renderer, model)); InstanceRenderer renderer(&scenery, model);
renderer.setSize(width, height);
renderer.setSoloRasterizer(&renderer);
startTestRender(&renderer, "vegetation_model_basic", i); startTestRender(&renderer, "vegetation_model_basic", i);
} }

View file

@ -28,10 +28,10 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery):
postprocess_enabled = true; postprocess_enabled = true;
rasterizers.push_back(new SkyRasterizer(this, progress, RASTERIZER_CLIENT_SKY)); rasterizers.push_back(rasterizer_sky = new SkyRasterizer(this, progress, RASTERIZER_CLIENT_SKY));
rasterizers.push_back(new WaterRasterizer(this, progress, RASTERIZER_CLIENT_WATER)); rasterizers.push_back(rasterizer_water = new WaterRasterizer(this, progress, RASTERIZER_CLIENT_WATER));
rasterizers.push_back(new TerrainRasterizer(this, progress, RASTERIZER_CLIENT_TERRAIN)); rasterizers.push_back(rasterizer_terrain = new TerrainRasterizer(this, progress, RASTERIZER_CLIENT_TERRAIN));
rasterizers.push_back(new VegetationRasterizer(this, progress, RASTERIZER_CLIENT_VEGETATION)); rasterizers.push_back(rasterizer_vegetation = new VegetationRasterizer(this, progress, RASTERIZER_CLIENT_VEGETATION));
current_work = NULL; current_work = NULL;
} }
@ -41,10 +41,10 @@ SoftwareCanvasRenderer::~SoftwareCanvasRenderer()
delete canvas; delete canvas;
delete progress; delete progress;
for (auto &rasterizer: rasterizers) delete rasterizer_sky;
{ delete rasterizer_water;
delete rasterizer; delete rasterizer_terrain;
} delete rasterizer_vegetation;
} }
void SoftwareCanvasRenderer::setQuality(double factor) void SoftwareCanvasRenderer::setQuality(double factor)
@ -59,10 +59,6 @@ void SoftwareCanvasRenderer::setQuality(double factor)
void SoftwareCanvasRenderer::setSoloRasterizer(Rasterizer *rasterizer) void SoftwareCanvasRenderer::setSoloRasterizer(Rasterizer *rasterizer)
{ {
for (auto &rast: rasterizers)
{
delete rast;
}
rasterizers.clear(); rasterizers.clear();
rasterizers.push_back(rasterizer); rasterizers.push_back(rasterizer);
} }

View file

@ -26,16 +26,15 @@ public:
inline RenderProgress *getProgressHelper() const {return progress;} inline RenderProgress *getProgressHelper() const {return progress;}
inline bool isFinished() const {return finished;} inline bool isFinished() const {return finished;}
inline Rasterizer *getSkyRasterizer() const {return rasterizers[0];} inline Rasterizer *getSkyRasterizer() const {return rasterizer_sky;}
inline Rasterizer *getWaterRasterizer() const {return rasterizers[1];} inline Rasterizer *getWaterRasterizer() const {return rasterizer_water;}
inline Rasterizer *getTerrainRasterizer() const {return rasterizers[2];} inline Rasterizer *getTerrainRasterizer() const {return rasterizer_terrain;}
inline Rasterizer *getVegetationRasterizer() const {return rasterizer_vegetation;}
virtual void setQuality(double factor) override; virtual void setQuality(double factor) override;
/** /**
* Clear the rasterizers list, and put a single one. * Clear the rasterizers list, and put a single one.
*
* The renderer takes ownership of the rasterizer.
*/ */
void setSoloRasterizer(Rasterizer *rasterizer); void setSoloRasterizer(Rasterizer *rasterizer);
@ -99,7 +98,13 @@ private:
Canvas *canvas; Canvas *canvas;
int samples; int samples;
std::vector<Rasterizer*> rasterizers;
std::vector<Rasterizer *> rasterizers;
Rasterizer *rasterizer_sky;
Rasterizer *rasterizer_water;
Rasterizer *rasterizer_terrain;
Rasterizer *rasterizer_vegetation;
bool started; bool started;
bool finished; bool finished;
bool interrupted; bool interrupted;

View file

@ -23,7 +23,7 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment,
{ {
InfiniteRay ray(segment.getStart(), segment.getDirection()); InfiniteRay ray(segment.getStart(), segment.getDirection());
int intersections; int intersections;
Color result = COLOR_TRANSPARENT; const SurfaceMaterial *material = &SurfaceMaterial::getDefault();
bool hit = false; bool hit = false;
Vector3 location, normal; Vector3 location, normal;
double distance, nearest, maximal; double distance, nearest, maximal;
@ -47,7 +47,7 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment,
if (distance < nearest) if (distance < nearest)
{ {
result = Color(0.2, 0.15, 0.15); material = &model->getSolidMaterial();
nearest = distance; nearest = distance;
hit = true; hit = true;
@ -100,7 +100,7 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment,
if (distance < nearest) if (distance < nearest)
{ {
result = Color(0.3, 0.5, 0.3); material = &model->getFoliageMaterial();
nearest = distance; nearest = distance;
hit = true; hit = true;
@ -110,7 +110,6 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment,
if (normal.dotProduct(location.sub(segment.getStart())) > 0.0) if (normal.dotProduct(location.sub(segment.getStart())) > 0.0)
{ {
// We look at backside // We look at backside
result = Color(0.3, 0.4, 0.3);
normal = normal.scale(-1.0); normal = normal.scale(-1.0);
} }
} }
@ -123,12 +122,7 @@ VegetationResult VegetationModelRenderer::getResult(const SpaceSegment &segment,
if (hit) if (hit)
{ {
SurfaceMaterial material(result); return VegetationResult(location, normal, *material);
material.reflection = 0.001;
material.shininess = 2.0;
material.hardness = 0.1;
material.validate();
return VegetationResult(location, normal, material);
} }
else else
{ {