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 "Matrix4.h"
#include "SurfaceMaterial.h"
#include "Color.h"
#include "PackStream.h"
VegetationModelDefinition::VegetationModelDefinition(DefinitionNode *parent):
DefinitionNode(parent, "model")
{
solid_material = new SurfaceMaterial();
foliage_material = new SurfaceMaterial();
solid_material = new SurfaceMaterial(Color(0.2, 0.15, 0.15));
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();
}
@ -127,7 +137,10 @@ static void addBranchRecurse(std::vector<CappedCylinder> &branches, const Vector
new_direction = pivot2.multPoint(new_direction);
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();
// 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
for (const auto &branch: solid_volumes)
@ -155,7 +168,7 @@ void VegetationModelDefinition::randomize()
}
// Add foliage items
for (int i = 0; i < 50; i++)
for (int i = 0; i < 30; i++)
{
double radius = 0.15;
double scale = randomizeValue(radius, 0.5, 1.0);

View file

@ -21,6 +21,9 @@ public:
VegetationModelDefinition(DefinitionNode *parent);
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<Sphere> &getFoliageGroups() const {return foliage_groups;}
inline const std::vector<Disk> &getFoliageItems() const {return foliage_items;}

View file

@ -110,12 +110,12 @@ static void testCloudQuality()
SoftwareCanvasRenderer renderer(&scenery);
renderer.setSize(600, 800);
SkyRasterizer *rasterizer = new SkyRasterizer(&renderer, renderer.getProgressHelper(), 0);
renderer.setSoloRasterizer(rasterizer);
SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0);
renderer.setSoloRasterizer(&rasterizer);
for (int i = 0; i < 6; i++)
{
renderer.setQuality((double)i / 5.0);
rasterizer->setQuality(0.2);
rasterizer.setQuality(0.2);
startTestRender(&renderer, "cloud_quality", i);
}
}
@ -164,8 +164,8 @@ static void testGodRays()
TestRenderer renderer(&scenery);
renderer.setSize(500, 300);
SkyRasterizer *rasterizer = new SkyRasterizer(&renderer, renderer.getProgressHelper(), 0);
renderer.setSoloRasterizer(rasterizer);
SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0);
renderer.setSoloRasterizer(&rasterizer);
TestLightFilter filter;
renderer.getLightingManager()->clearFilters();
renderer.getLightingManager()->registerFilter(&filter);
@ -174,7 +174,7 @@ static void testGodRays()
for (int i = 0; i < 6; i++)
{
renderer.setQuality((double)i / 5.0);
rasterizer->setQuality(0.2);
rasterizer.setQuality(0.2);
startTestRender(&renderer, "god_rays_quality", i);
}
renderer.setQuality(0.5);
@ -259,25 +259,42 @@ static void testSunNearHorizon()
static void testVegetationModels()
{
class TestRasterizer: public OverlayRasterizer
class InstanceRenderer: public SoftwareCanvasRenderer, public OverlayRasterizer, public LightFilter
{
public:
TestRasterizer(SoftwareCanvasRenderer *renderer, const VegetationModelDefinition &model):
OverlayRasterizer(renderer, renderer->getProgressHelper()),
InstanceRenderer(Scenery *scenery, const VegetationModelDefinition &model):
SoftwareCanvasRenderer(scenery),
OverlayRasterizer(this, this->getProgressHelper()),
instance(model, VECTOR_ZERO),
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
{
relx *= 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);
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;
VegetationRenderer *vegetation;
};
@ -285,21 +302,18 @@ static void testVegetationModels()
Scenery scenery;
scenery.autoPreset(1);
scenery.getClouds()->clear();
scenery.getTerrain()->propWaterHeight()->setValue(1.0);
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 height = 800;
SoftwareCanvasRenderer renderer(&scenery);
renderer.setSize(width, height);
renderer.setQuality(0.5);
for (int i = 0; i < 10; i++)
{
// TODO Make random sequence repeatable
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);
}

View file

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

View file

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

View file

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