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 "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,9 +137,12 @@ 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)));
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VegetationModelDefinition::randomize()
|
||||
|
@ -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);
|
||||
|
|
|
@ -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;}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue