2015-09-09 22:40:47 +00:00
|
|
|
#include "SoftwareCanvasRenderer.h"
|
2015-09-10 16:16:57 +00:00
|
|
|
#include "TerrainRenderer.h"
|
2015-09-09 22:40:47 +00:00
|
|
|
#include "Scenery.h"
|
|
|
|
#include "CameraDefinition.h"
|
|
|
|
#include "TerrainDefinition.h"
|
|
|
|
#include "AtmosphereDefinition.h"
|
|
|
|
#include "TexturesDefinition.h"
|
2015-09-29 23:08:15 +00:00
|
|
|
#include "GodRaysDefinition.h"
|
2015-09-09 22:40:47 +00:00
|
|
|
#include "TextureLayerDefinition.h"
|
|
|
|
#include "WaterDefinition.h"
|
|
|
|
#include "SurfaceMaterial.h"
|
|
|
|
#include "FloatNode.h"
|
2015-09-13 16:58:11 +00:00
|
|
|
#include "SkyRasterizer.h"
|
2015-09-29 20:31:25 +00:00
|
|
|
#include "CloudsDefinition.h"
|
|
|
|
#include "LightComponent.h"
|
|
|
|
#include "LightingManager.h"
|
|
|
|
#include "LightFilter.h"
|
|
|
|
#include "GodRaysSampler.h"
|
2015-10-08 22:55:36 +00:00
|
|
|
#include "Rasterizer.h"
|
2015-11-02 19:14:35 +00:00
|
|
|
#include "SpaceSegment.h"
|
|
|
|
#include "OverlayRasterizer.h"
|
|
|
|
#include "VegetationModelDefinition.h"
|
|
|
|
#include "VegetationInstance.h"
|
|
|
|
#include "VegetationRenderer.h"
|
|
|
|
#include "RayCastingResult.h"
|
2015-11-25 22:15:58 +00:00
|
|
|
#include "OpenGLVegetationImpostor.h"
|
|
|
|
#include "Texture2D.h"
|
2015-12-10 18:40:39 +00:00
|
|
|
#include "RandomGenerator.h"
|
2015-09-09 22:40:47 +00:00
|
|
|
|
|
|
|
#include <sstream>
|
2015-11-25 22:15:58 +00:00
|
|
|
#include <iostream>
|
2015-09-09 22:40:47 +00:00
|
|
|
|
|
|
|
void startRender(SoftwareCanvasRenderer *renderer, const char *outputpath);
|
|
|
|
|
2015-12-13 16:16:26 +00:00
|
|
|
static string getFileName(const string &name, int iteration = -1) {
|
2015-12-10 23:36:50 +00:00
|
|
|
ostringstream stream;
|
2015-09-09 22:40:47 +00:00
|
|
|
|
2015-10-08 17:20:44 +00:00
|
|
|
stream << "pic_test_" << name;
|
2015-11-09 21:30:46 +00:00
|
|
|
if (iteration >= 0) {
|
2015-10-08 17:20:44 +00:00
|
|
|
stream << "_";
|
|
|
|
stream.width(4);
|
|
|
|
stream.fill('0');
|
|
|
|
stream << iteration;
|
|
|
|
}
|
2015-09-09 22:40:47 +00:00
|
|
|
stream << ".png";
|
|
|
|
|
2015-11-25 22:15:58 +00:00
|
|
|
return stream.str();
|
|
|
|
}
|
|
|
|
|
2015-12-13 16:16:26 +00:00
|
|
|
static void startTestRender(SoftwareCanvasRenderer *renderer, const string &name, int iteration = -1) {
|
2015-11-25 22:15:58 +00:00
|
|
|
startRender(renderer, getFileName(name, iteration).data());
|
2015-09-09 22:40:47 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
static void testGroundShadowQuality() {
|
2015-09-09 22:40:47 +00:00
|
|
|
Scenery scenery;
|
2015-12-10 18:40:39 +00:00
|
|
|
RandomGenerator random(5);
|
|
|
|
scenery.getTerrain()->applyPreset(TerrainDefinition::TERRAIN_PRESET_STANDARD, random);
|
2015-09-09 22:40:47 +00:00
|
|
|
scenery.getTerrain()->propWaterHeight()->setValue(-0.5);
|
|
|
|
scenery.getWater()->propReflection()->setValue(0.0);
|
|
|
|
scenery.getWater()->material->base->r = 0.0;
|
|
|
|
scenery.getWater()->material->base->g = 0.3;
|
|
|
|
scenery.getWater()->material->base->b = 1.0;
|
|
|
|
scenery.getWater()->material->reflection = 0.0;
|
|
|
|
scenery.getWater()->foam_coverage = 0.0;
|
|
|
|
scenery.getWater()->transparency = 0.0;
|
2015-12-10 18:40:39 +00:00
|
|
|
scenery.getAtmosphere()->applyPreset(AtmosphereDefinition::ATMOSPHERE_PRESET_CLEAR_SUNSET, random);
|
2015-09-09 22:40:47 +00:00
|
|
|
scenery.getAtmosphere()->setDayTime(16, 45);
|
|
|
|
scenery.getTextures()->clear();
|
2015-11-20 00:07:31 +00:00
|
|
|
TextureLayerDefinition texture(NULL, "test");
|
|
|
|
texture.displacement_height = 0.3;
|
|
|
|
texture.displacement_scaling = 2.0;
|
|
|
|
texture.displacement_offset = 0.0;
|
|
|
|
texture.material->setColor(0.6, 0.55, 0.57, 1.0);
|
|
|
|
texture.material->reflection = 0.006;
|
|
|
|
texture.material->shininess = 6.0;
|
|
|
|
texture.validate();
|
|
|
|
scenery.getTextures()->addLayer(texture);
|
2015-09-09 22:40:47 +00:00
|
|
|
scenery.getCamera()->setLocation(Vector3(10.0, 10.0, -10.0));
|
|
|
|
scenery.getCamera()->setTarget(VECTOR_ZERO);
|
|
|
|
scenery.validate();
|
|
|
|
|
|
|
|
SoftwareCanvasRenderer renderer(&scenery);
|
|
|
|
renderer.setSize(400, 300);
|
2015-09-10 16:16:57 +00:00
|
|
|
renderer.setQuality(0.2);
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = 0; i < 6; i++) {
|
2015-09-13 16:58:11 +00:00
|
|
|
// TODO keep same rasterization across renders
|
2015-09-10 16:16:57 +00:00
|
|
|
renderer.getTerrainRenderer()->setQuality((double)i / 5.0);
|
2015-09-09 22:40:47 +00:00
|
|
|
startTestRender(&renderer, "ground_shadow_quality", i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
static void testRasterizationQuality() {
|
2015-09-10 17:33:52 +00:00
|
|
|
Scenery scenery;
|
|
|
|
scenery.autoPreset(12);
|
|
|
|
|
|
|
|
SoftwareCanvasRenderer renderer(&scenery);
|
|
|
|
renderer.setSize(800, 600);
|
|
|
|
renderer.enablePostprocess(false);
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = 0; i < 6; i++) {
|
2015-09-10 17:33:52 +00:00
|
|
|
renderer.setQuality((double)i / 5.0);
|
|
|
|
startTestRender(&renderer, "rasterization_quality", i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
static void testCloudQuality() {
|
2015-09-13 16:58:11 +00:00
|
|
|
Scenery scenery;
|
|
|
|
scenery.autoPreset(3);
|
|
|
|
scenery.getCamera()->setLocation(Vector3(5.0, 5.0, 5.0));
|
|
|
|
scenery.getCamera()->setTarget(Vector3(8.0, 7.25, 8.0));
|
|
|
|
scenery.getTerrain()->height = 0.0;
|
|
|
|
scenery.getTerrain()->validate();
|
|
|
|
|
|
|
|
SoftwareCanvasRenderer renderer(&scenery);
|
|
|
|
renderer.setSize(600, 800);
|
2015-11-09 00:07:33 +00:00
|
|
|
SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0);
|
|
|
|
renderer.setSoloRasterizer(&rasterizer);
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = 0; i < 6; i++) {
|
2015-09-13 16:58:11 +00:00
|
|
|
renderer.setQuality((double)i / 5.0);
|
2015-11-09 00:07:33 +00:00
|
|
|
rasterizer.setQuality(0.2);
|
2015-09-13 16:58:11 +00:00
|
|
|
startTestRender(&renderer, "cloud_quality", i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
static void testGodRays() {
|
|
|
|
class TestLightFilter : public LightFilter {
|
|
|
|
virtual bool applyLightFilter(LightComponent &light, const Vector3 &at) override {
|
|
|
|
if (Vector3(0.0, 100.0, 0.0).sub(at).normalize().y > 0.97) {
|
2015-09-29 20:31:25 +00:00
|
|
|
light.color = COLOR_BLACK;
|
|
|
|
return false;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2015-09-29 20:31:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2015-11-09 21:30:46 +00:00
|
|
|
class TestRenderer : public SoftwareCanvasRenderer {
|
|
|
|
public:
|
|
|
|
TestRenderer(Scenery *scenery) : SoftwareCanvasRenderer(scenery) {
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
virtual void prepare() override {
|
2015-09-29 20:31:25 +00:00
|
|
|
SoftwareRenderer::prepare();
|
|
|
|
|
|
|
|
getLightingManager()->clearSources();
|
|
|
|
getLightingManager()->addStaticLight(LightComponent(COLOR_WHITE, VECTOR_DOWN));
|
|
|
|
getGodRaysSampler()->setAltitudes(0.0, 30.0);
|
|
|
|
getGodRaysSampler()->reset();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Scenery scenery;
|
|
|
|
scenery.autoPreset(63);
|
|
|
|
scenery.getAtmosphere()->setDayTime(12);
|
|
|
|
scenery.getCamera()->setLocation(Vector3(0.0, 1.0, -50.0));
|
|
|
|
scenery.getCamera()->setTarget(Vector3(0.0, 15.0, 0.0));
|
|
|
|
scenery.getTerrain()->height = 0.0;
|
|
|
|
scenery.getTerrain()->validate();
|
|
|
|
scenery.getClouds()->clear();
|
|
|
|
|
|
|
|
TestRenderer renderer(&scenery);
|
|
|
|
renderer.setSize(500, 300);
|
2015-11-09 00:07:33 +00:00
|
|
|
SkyRasterizer rasterizer(&renderer, renderer.getProgressHelper(), 0);
|
|
|
|
renderer.setSoloRasterizer(&rasterizer);
|
2015-09-29 20:31:25 +00:00
|
|
|
TestLightFilter filter;
|
|
|
|
renderer.getLightingManager()->clearFilters();
|
|
|
|
renderer.getLightingManager()->registerFilter(&filter);
|
2015-09-29 23:08:15 +00:00
|
|
|
|
|
|
|
// quality
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = 0; i < 6; i++) {
|
2015-09-29 20:31:25 +00:00
|
|
|
renderer.setQuality((double)i / 5.0);
|
2015-11-09 00:07:33 +00:00
|
|
|
rasterizer.setQuality(0.2);
|
2015-09-29 23:08:15 +00:00
|
|
|
startTestRender(&renderer, "god_rays_quality", i);
|
|
|
|
}
|
|
|
|
renderer.setQuality(0.5);
|
|
|
|
|
|
|
|
// penetration
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = 0; i < 3; i++) {
|
2015-09-29 23:08:15 +00:00
|
|
|
scenery.getAtmosphere()->childGodRays()->propPenetration()->setValue(0.01 + 0.02 * (double)i);
|
|
|
|
startTestRender(&renderer, "god_rays_penetration", i);
|
|
|
|
}
|
|
|
|
|
|
|
|
// resistance
|
|
|
|
scenery.getAtmosphere()->childGodRays()->propPenetration()->setValue(0.01);
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = 0; i < 3; i++) {
|
2015-09-29 23:08:15 +00:00
|
|
|
scenery.getAtmosphere()->childGodRays()->propResistance()->setValue(0.1 + 0.1 * (double)i);
|
|
|
|
startTestRender(&renderer, "god_rays_resistance", i);
|
|
|
|
}
|
|
|
|
|
|
|
|
// boost
|
|
|
|
scenery.getAtmosphere()->childGodRays()->propResistance()->setValue(0.3);
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = 0; i < 3; i++) {
|
2015-09-29 23:08:15 +00:00
|
|
|
scenery.getAtmosphere()->childGodRays()->propBoost()->setValue(2.0 + 4.0 * (double)i);
|
|
|
|
startTestRender(&renderer, "god_rays_boost", i);
|
2015-09-29 20:31:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
static void testNearFrustum() {
|
2015-10-08 17:20:44 +00:00
|
|
|
Scenery scenery;
|
|
|
|
scenery.autoPreset(3);
|
|
|
|
scenery.getCamera()->setLocation(Vector3(0.0, 0.0, 0.0));
|
|
|
|
scenery.getCamera()->setTarget(Vector3(1.0, 0.0, 1.0));
|
|
|
|
|
|
|
|
SoftwareCanvasRenderer renderer(&scenery);
|
|
|
|
renderer.setSize(400, 300);
|
|
|
|
renderer.setQuality(0.1);
|
2015-10-08 22:55:36 +00:00
|
|
|
startTestRender(&renderer, "near_frustum_good");
|
|
|
|
|
|
|
|
renderer.getWaterRasterizer()->setAutoCutLimit(1000.0);
|
|
|
|
startTestRender(&renderer, "near_frustum_bad");
|
2015-10-08 17:20:44 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
static void testCloudsNearGround() {
|
2015-10-08 22:43:32 +00:00
|
|
|
Scenery scenery;
|
|
|
|
scenery.autoPreset(8);
|
|
|
|
scenery.getAtmosphere()->setDayTime(6, 20);
|
|
|
|
|
|
|
|
SoftwareCanvasRenderer renderer(&scenery);
|
|
|
|
renderer.setSize(400, 300);
|
|
|
|
renderer.setQuality(0.3);
|
|
|
|
|
|
|
|
startTestRender(&renderer, "clouds_near_ground", 1);
|
|
|
|
|
|
|
|
scenery.getCamera()->strafeUp(6.0);
|
|
|
|
scenery.getCamera()->copy(renderer.render_camera);
|
|
|
|
startTestRender(&renderer, "clouds_near_ground", 2);
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
static void testSunNearHorizon() {
|
2015-10-15 15:52:03 +00:00
|
|
|
Scenery scenery;
|
|
|
|
scenery.autoPreset(28);
|
|
|
|
scenery.getCamera()->setLocation(VECTOR_ZERO);
|
|
|
|
scenery.getCamera()->setTarget(VECTOR_EAST);
|
|
|
|
scenery.getClouds()->clear();
|
|
|
|
scenery.getTextures()->applyPreset(TexturesDefinition::TEXTURES_PRESET_CANYON);
|
|
|
|
scenery.getTerrain()->propWaterHeight()->setValue(-1.0);
|
|
|
|
|
|
|
|
SoftwareCanvasRenderer renderer(&scenery);
|
|
|
|
renderer.setSize(400, 300);
|
|
|
|
renderer.setQuality(0.3);
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int i = 0; i <= 20; i++) {
|
2015-10-15 15:52:03 +00:00
|
|
|
scenery.getAtmosphere()->propDayTime()->setValue(0.24 + 0.001 * (double)i);
|
|
|
|
startTestRender(&renderer, "sun_near_horizon", i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
static void testVegetationModels() {
|
|
|
|
class InstanceRenderer : public SoftwareCanvasRenderer, public OverlayRasterizer, public LightFilter {
|
|
|
|
public:
|
|
|
|
InstanceRenderer(Scenery *scenery, const VegetationModelDefinition &model)
|
|
|
|
: SoftwareCanvasRenderer(scenery), OverlayRasterizer(this, this->getProgressHelper()),
|
|
|
|
instance(model, VECTOR_ZERO), vegetation(renderer->getVegetationRenderer()) {
|
2015-11-02 19:14:35 +00:00
|
|
|
}
|
2015-11-09 21:38:00 +00:00
|
|
|
virtual void prepare() override {
|
2015-11-09 00:07:33 +00:00
|
|
|
SoftwareCanvasRenderer::prepare();
|
2015-11-02 19:14:35 +00:00
|
|
|
|
2015-11-09 00:07:33 +00:00
|
|
|
getLightingManager()->clearFilters();
|
|
|
|
getLightingManager()->registerFilter(this);
|
|
|
|
// TODO Add filter for vegetation instance (for self shadows)
|
|
|
|
}
|
2015-11-09 21:38:00 +00:00
|
|
|
virtual Color applyMediumTraversal(const Vector3 &, const Color &color) override {
|
2015-11-09 00:07:33 +00:00
|
|
|
return color;
|
|
|
|
}
|
2015-11-09 21:38:00 +00:00
|
|
|
virtual Color processPixel(int, int, double relx, double rely) const override {
|
2015-11-02 19:14:35 +00:00
|
|
|
relx *= 0.75;
|
|
|
|
rely *= 0.75;
|
2015-11-09 00:07:33 +00:00
|
|
|
SpaceSegment segment(Vector3(relx, rely + 0.5, 5.0), Vector3(relx, rely + 0.5, -5.0));
|
2015-11-02 19:14:35 +00:00
|
|
|
RayCastingResult result = vegetation->renderInstance(segment, instance, false, true);
|
|
|
|
return result.hit ? result.hit_color : Color(0.6, 0.7, 0.9);
|
|
|
|
}
|
2015-11-09 21:38:00 +00:00
|
|
|
virtual bool applyLightFilter(LightComponent &light, const Vector3 &at) override {
|
2015-11-09 00:07:33 +00:00
|
|
|
SpaceSegment segment(at, at.add(light.direction.scale(-5.0)));
|
|
|
|
RayCastingResult result = vegetation->renderInstance(segment, instance, true, true);
|
|
|
|
return not result.hit;
|
|
|
|
}
|
2015-11-02 19:14:35 +00:00
|
|
|
VegetationInstance instance;
|
|
|
|
VegetationRenderer *vegetation;
|
|
|
|
};
|
|
|
|
|
|
|
|
Scenery scenery;
|
|
|
|
scenery.autoPreset(1);
|
|
|
|
scenery.getClouds()->clear();
|
|
|
|
scenery.getCamera()->setTarget(VECTOR_ZERO);
|
2015-11-09 00:07:33 +00:00
|
|
|
scenery.getCamera()->setLocation(Vector3(0.0, 0.0, 5.0));
|
2015-11-02 19:14:35 +00:00
|
|
|
int width = 800;
|
|
|
|
int height = 800;
|
|
|
|
|
2015-11-09 21:38:00 +00:00
|
|
|
for (int i = 0; i < 10; i++) {
|
2015-11-02 22:00:02 +00:00
|
|
|
// TODO Make random sequence repeatable
|
|
|
|
VegetationModelDefinition model(NULL);
|
2015-11-09 00:07:33 +00:00
|
|
|
InstanceRenderer renderer(&scenery, model);
|
|
|
|
renderer.setSize(width, height);
|
|
|
|
renderer.setSoloRasterizer(&renderer);
|
2015-11-02 19:14:35 +00:00
|
|
|
|
2015-11-02 22:00:02 +00:00
|
|
|
startTestRender(&renderer, "vegetation_model_basic", i);
|
|
|
|
}
|
2015-11-02 19:14:35 +00:00
|
|
|
}
|
|
|
|
|
2015-11-25 22:15:58 +00:00
|
|
|
static void testOpenGLVegetationImpostor() {
|
2015-11-29 18:18:36 +00:00
|
|
|
for (int i = 0; i < 4; i++) {
|
2015-12-13 16:16:26 +00:00
|
|
|
string filename = getFileName("opengl_vegetation_impostor", i);
|
|
|
|
cout << "Rendering " << filename << "..." << endl;
|
2015-11-25 22:15:58 +00:00
|
|
|
|
2015-11-29 18:18:36 +00:00
|
|
|
Scenery scenery;
|
|
|
|
scenery.autoPreset(i);
|
|
|
|
|
|
|
|
OpenGLVegetationImpostor impostor(128);
|
|
|
|
VegetationModelDefinition model(NULL);
|
|
|
|
|
|
|
|
bool interrupted = false;
|
|
|
|
impostor.prepareTexture(model, scenery, &interrupted);
|
|
|
|
|
|
|
|
impostor.getTexture()->saveToFile(filename);
|
|
|
|
}
|
2015-11-25 22:15:58 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void runTestSuite() {
|
2015-09-09 22:40:47 +00:00
|
|
|
testGroundShadowQuality();
|
2015-09-10 17:33:52 +00:00
|
|
|
testRasterizationQuality();
|
2015-09-13 16:58:11 +00:00
|
|
|
testCloudQuality();
|
2015-09-29 20:31:25 +00:00
|
|
|
testGodRays();
|
2015-10-08 17:20:44 +00:00
|
|
|
testNearFrustum();
|
2015-10-08 22:43:32 +00:00
|
|
|
testCloudsNearGround();
|
2015-10-15 15:52:03 +00:00
|
|
|
testSunNearHorizon();
|
2015-11-02 19:14:35 +00:00
|
|
|
testVegetationModels();
|
2015-11-25 22:15:58 +00:00
|
|
|
testOpenGLVegetationImpostor();
|
2015-09-09 22:40:47 +00:00
|
|
|
}
|