Added rasterization quality control

This commit is contained in:
Michaël Lemaire 2015-09-10 19:33:52 +02:00
parent 6a45c5dba7
commit 8d33a11dc5
12 changed files with 128 additions and 24 deletions

View file

@ -66,8 +66,24 @@ static void testGroundShadowQuality()
} }
} }
static void testRasterizationQuality()
{
Scenery scenery;
scenery.autoPreset(12);
SoftwareCanvasRenderer renderer(&scenery);
renderer.setSize(800, 600);
renderer.enablePostprocess(false);
for (int i = 0; i < 6; i++)
{
renderer.setQuality((double)i / 5.0);
startTestRender(&renderer, "rasterization_quality", i);
}
}
void runTestSuite() void runTestSuite()
{ {
testGroundShadowQuality(); testGroundShadowQuality();
testRasterizationQuality();
} }

View file

@ -38,6 +38,8 @@ Rasterizer::Rasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int
this->color = new Color(color); this->color = new Color(color);
interrupted = false; interrupted = false;
setQuality(0.5);
} }
Rasterizer::~Rasterizer() Rasterizer::~Rasterizer()
@ -50,6 +52,10 @@ void Rasterizer::interrupt()
interrupted = true; interrupted = true;
} }
void Rasterizer::setQuality(double)
{
}
void Rasterizer::pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3) void Rasterizer::pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3)
{ {
ScanPoint point1, point2, point3; ScanPoint point1, point2, point3;

View file

@ -23,6 +23,11 @@ public:
virtual Color shadeFragment(const CanvasFragment &fragment) const = 0; virtual Color shadeFragment(const CanvasFragment &fragment) const = 0;
virtual void interrupt(); virtual void interrupt();
/**
* Set the rasterization quality factor.
*/
virtual void setQuality(double factor);
/** /**
* Abstract method to prepare for the rasterization process, and return the estimated progress count. * Abstract method to prepare for the rasterization process, and return the estimated progress count.
*/ */

View file

@ -19,9 +19,6 @@ SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer, RenderProgress *progres
int SkyRasterizer::prepareRasterization() int SkyRasterizer::prepareRasterization()
{ {
res_i = renderer->render_quality * 40;
res_j = renderer->render_quality * 20;
return res_i * res_j; return res_i * res_j;
} }
@ -93,3 +90,14 @@ Color SkyRasterizer::shadeFragment(const CanvasFragment &fragment) const
return result; return result;
} }
void SkyRasterizer::setQuality(int res_i, int res_j)
{
this->res_i = res_i;
this->res_j = res_j;
}
void SkyRasterizer::setQuality(double factor)
{
setQuality(20.0 * (1.0 + factor * 10.0), 10.0 * (1.0 + factor * 10.0));
}

View file

@ -17,6 +17,9 @@ public:
virtual void rasterizeToCanvas(CanvasPortion* canvas) override; virtual void rasterizeToCanvas(CanvasPortion* canvas) override;
virtual Color shadeFragment(const CanvasFragment &fragment) const override; virtual Color shadeFragment(const CanvasFragment &fragment) const override;
void setQuality(int res_i, int res_j);
virtual void setQuality(double factor) override;
private: private:
int res_i; int res_i;
int res_j; int res_j;

View file

@ -25,6 +25,8 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery):
progress = new RenderProgress(); progress = new RenderProgress();
samples = 1; samples = 1;
postprocess_enabled = true;
rasterizers.push_back(new SkyRasterizer(this, progress, 0)); rasterizers.push_back(new SkyRasterizer(this, progress, 0));
rasterizers.push_back(new WaterRasterizer(this, progress, 1)); rasterizers.push_back(new WaterRasterizer(this, progress, 1));
rasterizers.push_back(new TerrainRasterizer(this, progress, 2)); rasterizers.push_back(new TerrainRasterizer(this, progress, 2));
@ -43,6 +45,16 @@ SoftwareCanvasRenderer::~SoftwareCanvasRenderer()
} }
} }
void SoftwareCanvasRenderer::setQuality(double factor)
{
SoftwareRenderer::setQuality(factor);
for (auto &rasterizer:rasterizers)
{
rasterizer->setQuality(factor);
}
}
double SoftwareCanvasRenderer::getProgress() const double SoftwareCanvasRenderer::getProgress() const
{ {
return progress->get(); return progress->get();
@ -53,10 +65,15 @@ void SoftwareCanvasRenderer::setConfig(const RenderConfig &config)
if (not started) if (not started)
{ {
setSize(config.width, config.height, config.antialias); setSize(config.width, config.height, config.antialias);
render_quality = config.quality; setQuality((double)(config.quality - 1) / 9.0);
} }
} }
void SoftwareCanvasRenderer::enablePostprocess(bool enabled)
{
this->postprocess_enabled = enabled;
}
void SoftwareCanvasRenderer::setSize(int width, int height, int samples) void SoftwareCanvasRenderer::setSize(int width, int height, int samples)
{ {
if (not started) if (not started)
@ -94,7 +111,7 @@ void SoftwareCanvasRenderer::render()
rasterize(portion); rasterize(portion);
} }
if (not interrupted) if (not interrupted and postprocess_enabled)
{ {
applyPixelShader(portion); applyPixelShader(portion);
} }

View file

@ -25,6 +25,8 @@ public:
inline const Canvas *getCanvas() const {return canvas;} inline const Canvas *getCanvas() const {return canvas;}
inline bool isFinished() const {return finished;} inline bool isFinished() const {return finished;}
virtual void setQuality(double factor) override;
/** /**
* Get the global rendering progress (0.0-1.0). * Get the global rendering progress (0.0-1.0).
*/ */
@ -35,6 +37,11 @@ public:
*/ */
void setConfig(const RenderConfig &config); void setConfig(const RenderConfig &config);
/**
* Enable or disable the post processing.
*/
void enablePostprocess(bool enabled);
/** /**
* @brief Set the rendering size in pixels. * @brief Set the rendering size in pixels.
* *
@ -85,6 +92,8 @@ private:
bool finished; bool finished;
bool interrupted; bool interrupted;
bool postprocess_enabled;
ParallelWork *current_work; ParallelWork *current_work;
}; };

View file

@ -23,7 +23,6 @@
SoftwareRenderer::SoftwareRenderer(Scenery* scenery): SoftwareRenderer::SoftwareRenderer(Scenery* scenery):
scenery(scenery) scenery(scenery)
{ {
render_quality = 5;
render_camera = new CameraDefinition; render_camera = new CameraDefinition;
scenery->getCamera()->copy(render_camera); scenery->getCamera()->copy(render_camera);
@ -42,6 +41,8 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery):
lighting->registerFilter(water_renderer); lighting->registerFilter(water_renderer);
lighting->registerFilter(terrain_renderer); lighting->registerFilter(terrain_renderer);
lighting->registerFilter(clouds_renderer); lighting->registerFilter(clouds_renderer);
setQuality(0.5);
} }
SoftwareRenderer::~SoftwareRenderer() SoftwareRenderer::~SoftwareRenderer()

View file

@ -16,6 +16,20 @@ TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, RenderProgress
{ {
} }
void TerrainRasterizer::setQuality(double base_chunk_size, double detail_factor, int max_chunk_detail)
{
this->base_chunk_size = base_chunk_size;
this->detail_factor = detail_factor;
this->max_chunk_detail = max_chunk_detail;
}
void TerrainRasterizer::setQuality(double factor)
{
setQuality(5.0 - 4.5 * factor * factor,
1.0 / (25.0 - 20.0 * factor),
1 + 49 * factor * factor);
}
static inline Vector3 _getPoint(SoftwareRenderer* renderer, double x, double z) static inline Vector3 _getPoint(SoftwareRenderer* renderer, double x, double z)
{ {
return Vector3(x, renderer->getTerrainRenderer()->getHeight(x, z, true), z); return Vector3(x, renderer->getTerrainRenderer()->getHeight(x, z, true), z);
@ -69,7 +83,7 @@ void TerrainRasterizer::renderQuad(CanvasPortion *canvas, double x, double z, do
} }
} }
static void _getChunk(SoftwareRenderer* renderer, TerrainRasterizer::TerrainChunkInfo* chunk, double x, double z, double size, bool displaced) void TerrainRasterizer::getChunk(TerrainRasterizer::TerrainChunkInfo* chunk, double x, double z, double size, bool displaced)
{ {
chunk->point_nw = renderer->getTerrainRenderer()->getResult(x, z, true, displaced).location; chunk->point_nw = renderer->getTerrainRenderer()->getResult(x, z, true, displaced).location;
chunk->point_sw = renderer->getTerrainRenderer()->getResult(x, z + size, true, displaced).location; chunk->point_sw = renderer->getTerrainRenderer()->getResult(x, z + size, true, displaced).location;
@ -109,10 +123,10 @@ static void _getChunk(SoftwareRenderer* renderer, TerrainRasterizer::TerrainChun
int coverage = renderer->render_camera->isUnprojectedBoxInView(box); int coverage = renderer->render_camera->isUnprojectedBoxInView(box);
if (coverage > 0) if (coverage > 0)
{ {
chunk->detail_hint = (int)ceil(sqrt((double)coverage) / (double)(25 - 2 * renderer->render_quality)); chunk->detail_hint = (int)ceil(sqrt((double)coverage) * detail_factor);
if (chunk->detail_hint > 5 * renderer->render_quality) if (chunk->detail_hint > max_chunk_detail)
{ {
chunk->detail_hint = 5 * renderer->render_quality; chunk->detail_hint = max_chunk_detail;
} }
} }
else else
@ -128,9 +142,7 @@ int TerrainRasterizer::performTessellation(CanvasPortion* canvas, bool displaced
int chunk_factor, chunk_count, i, result; int chunk_factor, chunk_count, i, result;
Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO); Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO);
double radius_int, radius_ext; double radius_int, radius_ext;
double base_chunk_size, chunk_size; double chunk_size;
base_chunk_size = 5.0 / (double)renderer->render_quality;
chunk_factor = 1; chunk_factor = 1;
chunk_count = 2; chunk_count = 2;
@ -146,7 +158,7 @@ int TerrainRasterizer::performTessellation(CanvasPortion* canvas, bool displaced
{ {
for (i = 0; i < chunk_count - 1; i++) for (i = 0; i < chunk_count - 1; i++)
{ {
_getChunk(renderer, &chunk, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size, displaced); getChunk(&chunk, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size, displaced);
if (chunk.detail_hint > 0) if (chunk.detail_hint > 0)
{ {
result += chunk.detail_hint * chunk.detail_hint; result += chunk.detail_hint * chunk.detail_hint;
@ -160,7 +172,7 @@ int TerrainRasterizer::performTessellation(CanvasPortion* canvas, bool displaced
return result; return result;
} }
_getChunk(renderer, &chunk, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size, displaced); getChunk(&chunk, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size, displaced);
if (chunk.detail_hint > 0) if (chunk.detail_hint > 0)
{ {
result += chunk.detail_hint * chunk.detail_hint; result += chunk.detail_hint * chunk.detail_hint;
@ -174,7 +186,7 @@ int TerrainRasterizer::performTessellation(CanvasPortion* canvas, bool displaced
return result; return result;
} }
_getChunk(renderer, &chunk, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size, displaced); getChunk(&chunk, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size, displaced);
if (chunk.detail_hint > 0) if (chunk.detail_hint > 0)
{ {
result += chunk.detail_hint * chunk.detail_hint; result += chunk.detail_hint * chunk.detail_hint;
@ -188,7 +200,7 @@ int TerrainRasterizer::performTessellation(CanvasPortion* canvas, bool displaced
return result; return result;
} }
_getChunk(renderer, &chunk, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size, displaced); getChunk(&chunk, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size, displaced);
if (chunk.detail_hint > 0) if (chunk.detail_hint > 0)
{ {
result += chunk.detail_hint * chunk.detail_hint; result += chunk.detail_hint * chunk.detail_hint;

View file

@ -24,6 +24,16 @@ public:
public: public:
TerrainRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id); TerrainRasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int client_id);
/**
* Set the rasterization quality.
*
* @param base_chunk_size Size of chunks near the camera
* @param detail_factor Precision factor of a chunk's tessellation, depending on screen coverage
* @param max_chunk_detail Maximal tessellation of chunks
*/
void setQuality(double base_chunk_size, double detail_factor, int max_chunk_detail);
virtual void setQuality(double factor) override;
virtual int prepareRasterization() override; virtual int prepareRasterization() override;
virtual void rasterizeToCanvas(CanvasPortion* canvas) override; virtual void rasterizeToCanvas(CanvasPortion* canvas) override;
virtual Color shadeFragment(const CanvasFragment &fragment) const override; virtual Color shadeFragment(const CanvasFragment &fragment) const override;
@ -51,6 +61,14 @@ private:
void tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail); void tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail);
void renderQuad(CanvasPortion* canvas, double x, double z, double size, double water_height); void renderQuad(CanvasPortion* canvas, double x, double z, double size, double water_height);
void getChunk(TerrainRasterizer::TerrainChunkInfo* chunk, double x, double z, double size, bool displaced);
private:
// Quality control
double base_chunk_size;
double detail_factor;
int max_chunk_detail;
}; };
} }

View file

@ -49,17 +49,20 @@ Color WaterRasterizer::shadeFragment(const CanvasFragment &fragment) const
return renderer->getWaterRenderer()->getResult(location.x, location.z).final; return renderer->getWaterRenderer()->getResult(location.x, location.z).final;
} }
void WaterRasterizer::setQuality(double factor)
{
base_chunk_size = 10.0 / (1.0 + factor * 7.0);
if (factor > 0.6)
{
base_chunk_size *= 0.5;
}
}
int WaterRasterizer::performTessellation(CanvasPortion *canvas) int WaterRasterizer::performTessellation(CanvasPortion *canvas)
{ {
int chunk_factor, chunk_count, i, result; int chunk_factor, chunk_count, i, result;
Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO); Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO);
double radius_int, radius_ext, base_chunk_size, chunk_size; double radius_int, radius_ext, chunk_size;
base_chunk_size = 2.0 / (double)renderer->render_quality;
if (renderer->render_quality > 7)
{
base_chunk_size *= 0.5;
}
result = 0; result = 0;
chunk_factor = 1; chunk_factor = 1;

View file

@ -19,8 +19,14 @@ public:
virtual void rasterizeToCanvas(CanvasPortion* canvas) override; virtual void rasterizeToCanvas(CanvasPortion* canvas) override;
virtual Color shadeFragment(const CanvasFragment &fragment) const override; virtual Color shadeFragment(const CanvasFragment &fragment) const override;
virtual void setQuality(double factor) override;
private: private:
int performTessellation(CanvasPortion* canvas); int performTessellation(CanvasPortion* canvas);
private:
// Quality control
double base_chunk_size;
}; };
} }