Tweaked vegetation rendering, and improved render tests
This commit is contained in:
parent
bdb2a3edb8
commit
72877c4361
6 changed files with 76 additions and 51 deletions
|
@ -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);
|
||||||
|
|
|
@ -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;}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue