Added rasterization quality control
This commit is contained in:
parent
6a45c5dba7
commit
8d33a11dc5
12 changed files with 128 additions and 24 deletions
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue