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()
|
||||
{
|
||||
testGroundShadowQuality();
|
||||
testRasterizationQuality();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue