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()
{
testGroundShadowQuality();
testRasterizationQuality();
}

View file

@ -38,6 +38,8 @@ Rasterizer::Rasterizer(SoftwareRenderer* renderer, RenderProgress *progress, int
this->color = new Color(color);
interrupted = false;
setQuality(0.5);
}
Rasterizer::~Rasterizer()
@ -50,6 +52,10 @@ void Rasterizer::interrupt()
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)
{
ScanPoint point1, point2, point3;

View file

@ -23,6 +23,11 @@ public:
virtual Color shadeFragment(const CanvasFragment &fragment) const = 0;
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.
*/

View file

@ -19,9 +19,6 @@ SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer, RenderProgress *progres
int SkyRasterizer::prepareRasterization()
{
res_i = renderer->render_quality * 40;
res_j = renderer->render_quality * 20;
return res_i * res_j;
}
@ -93,3 +90,14 @@ Color SkyRasterizer::shadeFragment(const CanvasFragment &fragment) const
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 Color shadeFragment(const CanvasFragment &fragment) const override;
void setQuality(int res_i, int res_j);
virtual void setQuality(double factor) override;
private:
int res_i;
int res_j;

View file

@ -25,6 +25,8 @@ SoftwareCanvasRenderer::SoftwareCanvasRenderer(Scenery *scenery):
progress = new RenderProgress();
samples = 1;
postprocess_enabled = true;
rasterizers.push_back(new SkyRasterizer(this, progress, 0));
rasterizers.push_back(new WaterRasterizer(this, progress, 1));
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
{
return progress->get();
@ -53,10 +65,15 @@ void SoftwareCanvasRenderer::setConfig(const RenderConfig &config)
if (not started)
{
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)
{
if (not started)
@ -94,7 +111,7 @@ void SoftwareCanvasRenderer::render()
rasterize(portion);
}
if (not interrupted)
if (not interrupted and postprocess_enabled)
{
applyPixelShader(portion);
}

View file

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

View file

@ -23,7 +23,6 @@
SoftwareRenderer::SoftwareRenderer(Scenery* scenery):
scenery(scenery)
{
render_quality = 5;
render_camera = new CameraDefinition;
scenery->getCamera()->copy(render_camera);
@ -42,6 +41,8 @@ SoftwareRenderer::SoftwareRenderer(Scenery* scenery):
lighting->registerFilter(water_renderer);
lighting->registerFilter(terrain_renderer);
lighting->registerFilter(clouds_renderer);
setQuality(0.5);
}
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)
{
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_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);
if (coverage > 0)
{
chunk->detail_hint = (int)ceil(sqrt((double)coverage) / (double)(25 - 2 * renderer->render_quality));
if (chunk->detail_hint > 5 * renderer->render_quality)
chunk->detail_hint = (int)ceil(sqrt((double)coverage) * detail_factor);
if (chunk->detail_hint > max_chunk_detail)
{
chunk->detail_hint = 5 * renderer->render_quality;
chunk->detail_hint = max_chunk_detail;
}
}
else
@ -128,9 +142,7 @@ int TerrainRasterizer::performTessellation(CanvasPortion* canvas, bool displaced
int chunk_factor, chunk_count, i, result;
Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO);
double radius_int, radius_ext;
double base_chunk_size, chunk_size;
base_chunk_size = 5.0 / (double)renderer->render_quality;
double chunk_size;
chunk_factor = 1;
chunk_count = 2;
@ -146,7 +158,7 @@ int TerrainRasterizer::performTessellation(CanvasPortion* canvas, bool displaced
{
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)
{
result += chunk.detail_hint * chunk.detail_hint;
@ -160,7 +172,7 @@ int TerrainRasterizer::performTessellation(CanvasPortion* canvas, bool displaced
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)
{
result += chunk.detail_hint * chunk.detail_hint;
@ -174,7 +186,7 @@ int TerrainRasterizer::performTessellation(CanvasPortion* canvas, bool displaced
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)
{
result += chunk.detail_hint * chunk.detail_hint;
@ -188,7 +200,7 @@ int TerrainRasterizer::performTessellation(CanvasPortion* canvas, bool displaced
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)
{
result += chunk.detail_hint * chunk.detail_hint;

View file

@ -24,6 +24,16 @@ public:
public:
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 void rasterizeToCanvas(CanvasPortion* canvas) override;
virtual Color shadeFragment(const CanvasFragment &fragment) const override;
@ -51,6 +61,14 @@ private:
void tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail);
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;
}
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 chunk_factor, chunk_count, i, result;
Vector3 cam = renderer->getCameraLocation(VECTOR_ZERO);
double radius_int, radius_ext, base_chunk_size, chunk_size;
base_chunk_size = 2.0 / (double)renderer->render_quality;
if (renderer->render_quality > 7)
{
base_chunk_size *= 0.5;
}
double radius_int, radius_ext, chunk_size;
result = 0;
chunk_factor = 1;

View file

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