Added TimeManager with basic wind control for videos
This commit is contained in:
parent
c62cf3a0a4
commit
cd144b886c
16 changed files with 178 additions and 27 deletions
1
TODO
1
TODO
|
@ -6,6 +6,7 @@ Technlology Preview 2 :
|
|||
- Refactor medium traversal to unify clouds, atmosphere and god rays.
|
||||
- Fix potential holes in land rendering (OpenGL and software).
|
||||
- Fix sun size not being consistent between opengl and software
|
||||
- Fix CanvasPortion saves colliding on disk when running several instances
|
||||
|
||||
Technology Preview 3 :
|
||||
- Alter aerial perspective using estimation of the amount of light left after cloud layers traversal.
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "NoiseGenerator.h"
|
||||
#include "SurfaceMaterial.h"
|
||||
#include "PackStream.h"
|
||||
#include "FloatNode.h"
|
||||
|
||||
CloudLayerDefinition::CloudLayerDefinition(DefinitionNode* parent):
|
||||
DefinitionNode(parent, "layer", "cloudlayer")
|
||||
|
@ -12,6 +13,9 @@ CloudLayerDefinition::CloudLayerDefinition(DefinitionNode* parent):
|
|||
altitude = 0.5;
|
||||
scaling = 0.5;
|
||||
coverage = 0.5;
|
||||
|
||||
xoffset = new FloatNode(this, "xoffset");
|
||||
zoffset = new FloatNode(this, "zoffset");
|
||||
}
|
||||
|
||||
CloudLayerDefinition::~CloudLayerDefinition()
|
||||
|
@ -79,6 +83,8 @@ void CloudLayerDefinition::copy(DefinitionNode* _destination) const
|
|||
|
||||
void CloudLayerDefinition::validate()
|
||||
{
|
||||
DefinitionNode::validate();
|
||||
|
||||
if (scaling < 0.1)
|
||||
{
|
||||
scaling = 0.1;
|
||||
|
|
|
@ -17,6 +17,8 @@ public:
|
|||
virtual ~CloudLayerDefinition();
|
||||
|
||||
inline const NoiseState &getNoiseState() const {return noise_state;}
|
||||
inline FloatNode *propXOffset() const {return xoffset;}
|
||||
inline FloatNode *propZOffset() const {return zoffset;}
|
||||
|
||||
static CloudLayerDefinition* newCopy(const CloudLayerDefinition& other, DefinitionNode* parent);
|
||||
CloudLayerDefinition* newCopy(DefinitionNode* parent) const;
|
||||
|
@ -48,6 +50,10 @@ public:
|
|||
double altitude;
|
||||
double scaling;
|
||||
double coverage;
|
||||
|
||||
private:
|
||||
FloatNode *xoffset;
|
||||
FloatNode *zoffset;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -81,3 +81,8 @@ bool FloatNode::applyDiff(const DefinitionDiff *diff, bool backward)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FloatNode::addValue(double added)
|
||||
{
|
||||
setValue(value + added);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ public:
|
|||
const FloatDiff *produceDiff(double new_value) const;
|
||||
void generateInitDiffs(std::vector<const DefinitionDiff *> *diffs) const;
|
||||
virtual bool applyDiff(const DefinitionDiff *diff, bool backward=false) override;
|
||||
|
||||
void addValue(double added);
|
||||
private:
|
||||
double value;
|
||||
};
|
||||
|
|
42
src/definition/TimeManager.cpp
Normal file
42
src/definition/TimeManager.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "TimeManager.h"
|
||||
|
||||
#include "Scenery.h"
|
||||
#include "AtmosphereDefinition.h"
|
||||
#include "FloatNode.h"
|
||||
#include "CloudsDefinition.h"
|
||||
#include "CloudLayerDefinition.h"
|
||||
#include "WaterDefinition.h"
|
||||
|
||||
TimeManager::TimeManager()
|
||||
{
|
||||
wind_x = 0.0;
|
||||
wind_z = 0.0;
|
||||
}
|
||||
|
||||
void TimeManager::moveForward(Scenery *scenery, double amount)
|
||||
{
|
||||
// Move the sun
|
||||
scenery->getAtmosphere()->setDayTime(scenery->getAtmosphere()->propDayTime()->getValue() + amount);
|
||||
|
||||
// Move the clouds
|
||||
int n = scenery->getClouds()->count();
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
CloudLayerDefinition *cloud = scenery->getClouds()->getCloudLayer(i);
|
||||
cloud->propXOffset()->addValue(-wind_x * amount * 100.0);
|
||||
cloud->propZOffset()->addValue(-wind_z * amount * 100.0);
|
||||
// TODO Alter noise offsets
|
||||
}
|
||||
|
||||
// Move the water
|
||||
WaterDefinition *water = scenery->getWater();
|
||||
water->propXOffset()->addValue(-wind_x * amount * 10.0);
|
||||
water->propZOffset()->addValue(-wind_z * amount * 10.0);
|
||||
// TODO Alter noise offsets
|
||||
}
|
||||
|
||||
void TimeManager::setWind(double wind_x, double wind_z)
|
||||
{
|
||||
this->wind_x = wind_x;
|
||||
this->wind_z = wind_z;
|
||||
}
|
37
src/definition/TimeManager.h
Normal file
37
src/definition/TimeManager.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef TIMEMANAGER_H
|
||||
#define TIMEMANAGER_H
|
||||
|
||||
#include "definition_global.h"
|
||||
|
||||
namespace paysages {
|
||||
namespace definition {
|
||||
|
||||
/**
|
||||
* Time manager, handling the inexorable passing of time.
|
||||
*/
|
||||
class DEFINITIONSHARED_EXPORT TimeManager
|
||||
{
|
||||
public:
|
||||
TimeManager();
|
||||
|
||||
/**
|
||||
* Alter a scenery to simulate the passing of *amount* of time.
|
||||
*
|
||||
* A 1.0 amount is a full day.
|
||||
*/
|
||||
void moveForward(Scenery *scenery, double amount);
|
||||
|
||||
/**
|
||||
* Set the wind factor in each direction.
|
||||
*/
|
||||
void setWind(double wind_x, double wind_z);
|
||||
|
||||
private:
|
||||
double wind_x;
|
||||
double wind_z;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TIMEMANAGER_H
|
|
@ -12,6 +12,8 @@ WaterDefinition::WaterDefinition(DefinitionNode* parent):
|
|||
{
|
||||
model = new IntNode(this, "model", -1);
|
||||
reflection = new FloatNode(this, "reflection");
|
||||
xoffset = new FloatNode(this, "xoffset");
|
||||
zoffset = new FloatNode(this, "zoffset");
|
||||
|
||||
material = new SurfaceMaterial;
|
||||
depth_color = new Color;
|
||||
|
|
|
@ -23,6 +23,8 @@ public:
|
|||
|
||||
inline IntNode *propModel() const {return model;}
|
||||
inline FloatNode *propReflection() const {return reflection;}
|
||||
inline FloatNode *propXOffset() const {return xoffset;}
|
||||
inline FloatNode *propZOffset() const {return zoffset;}
|
||||
|
||||
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff);
|
||||
|
||||
|
@ -53,6 +55,8 @@ public:
|
|||
private:
|
||||
IntNode *model;
|
||||
FloatNode *reflection;
|
||||
FloatNode *xoffset;
|
||||
FloatNode *zoffset;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ SOURCES += \
|
|||
DefinitionWatcher.cpp \
|
||||
IntNode.cpp \
|
||||
IntDiff.cpp \
|
||||
GodRaysDefinition.cpp
|
||||
GodRaysDefinition.cpp \
|
||||
TimeManager.cpp
|
||||
|
||||
HEADERS +=\
|
||||
definition_global.h \
|
||||
|
@ -66,7 +67,8 @@ HEADERS +=\
|
|||
DefinitionWatcher.h \
|
||||
IntNode.h \
|
||||
IntDiff.h \
|
||||
GodRaysDefinition.h
|
||||
GodRaysDefinition.h \
|
||||
TimeManager.h
|
||||
|
||||
unix:!symbian {
|
||||
maemo5 {
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace definition {
|
|||
class PaintedGridBrushAddNoise;
|
||||
class PaintedGridBrushReset;
|
||||
class PaintedGridBrushFlatten;
|
||||
class TimeManager;
|
||||
}
|
||||
}
|
||||
using namespace paysages::definition;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "Scenery.h"
|
||||
#include "AtmosphereDefinition.h"
|
||||
#include "CameraDefinition.h"
|
||||
#include "TimeManager.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
@ -21,6 +22,8 @@ static void displayHelp()
|
|||
printf(" -rh x Render height (int)\n");
|
||||
printf(" -rq x Render quality (int, 1 to 10)\n");
|
||||
printf(" -ra x Render anti-aliasing (int, 1 to 4)\n");
|
||||
printf(" -wx x Wind power in X direction (double)\n");
|
||||
printf(" -wz z Wind power in Z direction (double)\n");
|
||||
printf(" -di x Day start time (double, 0.0 to 1.0)\n");
|
||||
printf(" -ds x Day step time (double)\n");
|
||||
printf(" -cx x Camera X step (double)\n");
|
||||
|
@ -40,6 +43,8 @@ int main(int argc, char** argv)
|
|||
double conf_camera_step_x = 0.0;
|
||||
double conf_camera_step_y = 0.0;
|
||||
double conf_camera_step_z = 0.0;
|
||||
double conf_wind_x = 0.0;
|
||||
double conf_wind_z = 0.0;
|
||||
int outputcount;
|
||||
char outputpath[500];
|
||||
|
||||
|
@ -107,6 +112,20 @@ int main(int argc, char** argv)
|
|||
conf_render_params.antialias = atoi(*(++argv));
|
||||
}
|
||||
}
|
||||
else if (strcmp(*argv, "-wx") == 0 || strcmp(*argv, "--windx") == 0)
|
||||
{
|
||||
if (argc--)
|
||||
{
|
||||
conf_wind_x = atof(*(++argv));
|
||||
}
|
||||
}
|
||||
else if (strcmp(*argv, "-wz") == 0 || strcmp(*argv, "--windz") == 0)
|
||||
{
|
||||
if (argc--)
|
||||
{
|
||||
conf_wind_z = atof(*(++argv));
|
||||
}
|
||||
}
|
||||
else if (strcmp(*argv, "-di") == 0 || strcmp(*argv, "--daystart") == 0)
|
||||
{
|
||||
if (argc--)
|
||||
|
@ -158,15 +177,15 @@ int main(int argc, char** argv)
|
|||
scenery->autoPreset();
|
||||
}
|
||||
|
||||
TimeManager time;
|
||||
time.setWind(conf_wind_x, conf_wind_z);
|
||||
if (conf_daytime_start >= 0.0)
|
||||
{
|
||||
scenery->getAtmosphere()->setDayTime(conf_daytime_start);
|
||||
}
|
||||
|
||||
for (outputcount = 0; outputcount < conf_first_picture + conf_nb_pictures; outputcount++)
|
||||
{
|
||||
if (conf_daytime_start >= 0.0)
|
||||
{
|
||||
AtmosphereDefinition* atmo = scenery->getAtmosphere();
|
||||
atmo->setDayTime(conf_daytime_start);
|
||||
atmo->validate();
|
||||
}
|
||||
|
||||
CameraDefinition* camera = scenery->getCamera();
|
||||
Vector3 step = {conf_camera_step_x, conf_camera_step_y, conf_camera_step_z};
|
||||
camera->setLocation(camera->getLocation().add(step));
|
||||
|
@ -182,7 +201,7 @@ int main(int argc, char** argv)
|
|||
|
||||
delete renderer;
|
||||
|
||||
conf_daytime_start += conf_daytime_step;
|
||||
time.moveForward(scenery, conf_daytime_step);
|
||||
}
|
||||
|
||||
printf("Cleaning up ...\n");
|
||||
|
|
|
@ -203,7 +203,6 @@ static void testNearFrustum()
|
|||
scenery.autoPreset(3);
|
||||
scenery.getCamera()->setLocation(Vector3(0.0, 0.0, 0.0));
|
||||
scenery.getCamera()->setTarget(Vector3(1.0, 0.0, 1.0));
|
||||
scenery.keepCameraAboveGround(scenery.getCamera());
|
||||
|
||||
SoftwareCanvasRenderer renderer(&scenery);
|
||||
renderer.setSize(400, 300);
|
||||
|
@ -231,6 +230,27 @@ static void testCloudsNearGround()
|
|||
startTestRender(&renderer, "clouds_near_ground", 2);
|
||||
}
|
||||
|
||||
static void testSunNearHorizon()
|
||||
{
|
||||
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);
|
||||
|
||||
for (int i = 0; i <= 20; i++)
|
||||
{
|
||||
scenery.getAtmosphere()->propDayTime()->setValue(0.24 + 0.001 * (double)i);
|
||||
startTestRender(&renderer, "sun_near_horizon", i);
|
||||
}
|
||||
}
|
||||
|
||||
void runTestSuite()
|
||||
{
|
||||
testGroundShadowQuality();
|
||||
|
@ -239,4 +259,5 @@ void runTestSuite()
|
|||
testGodRays();
|
||||
testNearFrustum();
|
||||
testCloudsNearGround();
|
||||
testSunNearHorizon();
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "clouds/BaseCloudsModel.h"
|
||||
#include "SurfaceMaterial.h"
|
||||
#include "Logs.h"
|
||||
#include "FloatNode.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
@ -25,7 +26,7 @@ CloudBasicLayerRenderer::CloudBasicLayerRenderer(SoftwareRenderer* parent):
|
|||
{
|
||||
}
|
||||
|
||||
static inline double _getDistanceToBorder(BaseCloudsModel* model, Vector3 position)
|
||||
static inline double _getDistanceToBorder(BaseCloudsModel* model, const Vector3 &position)
|
||||
{
|
||||
return model->getDensity(position);
|
||||
}
|
||||
|
@ -54,7 +55,7 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
|
|||
double step_length, segment_length;
|
||||
double min_step, max_step;
|
||||
double noise_distance;
|
||||
Vector3 walker, step, segment_start;
|
||||
Vector3 walker, step, segment_start, offset;
|
||||
double render_precision;
|
||||
|
||||
if (max_segments <= 0)
|
||||
|
@ -80,7 +81,8 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
|
|||
current_inside_length = 0.0;
|
||||
segment_length = 0.0;
|
||||
walker = start;
|
||||
noise_distance = _getDistanceToBorder(model, start) * render_precision;
|
||||
offset = Vector3(model->getLayer()->propXOffset()->getValue(), 0.0, model->getLayer()->propZOffset()->getValue());
|
||||
noise_distance = _getDistanceToBorder(model, start.add(offset)) * render_precision;
|
||||
inside = 0;
|
||||
step = direction.scale(render_precision);
|
||||
|
||||
|
@ -88,7 +90,7 @@ int CloudBasicLayerRenderer::findSegments(BaseCloudsModel *model, const Vector3
|
|||
{
|
||||
walker = walker.add(step);
|
||||
step_length = step.getNorm();
|
||||
noise_distance = _getDistanceToBorder(model, walker) * render_precision;
|
||||
noise_distance = _getDistanceToBorder(model, walker.add(offset)) * render_precision;
|
||||
current_total_length += step_length;
|
||||
|
||||
if (noise_distance > 0.0)
|
||||
|
|
|
@ -69,6 +69,7 @@ SoftwareRenderer::~SoftwareRenderer()
|
|||
void SoftwareRenderer::prepare()
|
||||
{
|
||||
scenery->validate();
|
||||
scenery->getCamera()->copy(render_camera);
|
||||
|
||||
// Prepare sub renderers
|
||||
// TODO Don't recreate the renderer each time, only when it changes
|
||||
|
|
|
@ -29,12 +29,12 @@ void WaterRenderer::update()
|
|||
noise->setStep(0.3);
|
||||
}
|
||||
|
||||
static inline double _getHeight(FractalNoise* noise, double x, double z)
|
||||
static inline double _getHeight(WaterDefinition* definition, FractalNoise* noise, double x, double z)
|
||||
{
|
||||
return noise->get2d(0.00001, x, z);
|
||||
return noise->get2d(0.00001, x + definition->propXOffset()->getValue(), z + definition->propZOffset()->getValue());
|
||||
}
|
||||
|
||||
static inline Vector3 _getNormal(FractalNoise* noise, Vector3 base, double detail)
|
||||
static inline Vector3 _getNormal(WaterDefinition* definition, FractalNoise* noise, Vector3 base, double detail)
|
||||
{
|
||||
Vector3 back, right;
|
||||
double x, z;
|
||||
|
@ -43,12 +43,12 @@ static inline Vector3 _getNormal(FractalNoise* noise, Vector3 base, double detai
|
|||
z = base.z;
|
||||
|
||||
back.x = x;
|
||||
back.y = _getHeight(noise, x, z + detail);
|
||||
back.y = _getHeight(definition, noise, x, z + detail);
|
||||
back.z = z + detail;
|
||||
back = back.sub(base);
|
||||
|
||||
right.x = x + detail;
|
||||
right.y = _getHeight(noise, x + detail, z);
|
||||
right.y = _getHeight(definition, noise, x + detail, z);
|
||||
right.z = z;
|
||||
right = right.sub(base);
|
||||
|
||||
|
@ -89,26 +89,26 @@ static inline Color _getFoamMask(SoftwareRenderer* renderer, WaterDefinition* de
|
|||
|
||||
foam_factor = 0.0;
|
||||
location.x += location_offset;
|
||||
normal_diff = 1.0 - normal.dotProduct(_getNormal(noise, location, detail));
|
||||
normal_diff = 1.0 - normal.dotProduct(_getNormal(definition, noise, location, detail));
|
||||
if (normal_diff > foam_factor)
|
||||
{
|
||||
foam_factor = normal_diff;
|
||||
}
|
||||
location.x -= location_offset * 2.0;
|
||||
normal_diff = 1.0 - normal.dotProduct(_getNormal(noise, location, detail));
|
||||
normal_diff = 1.0 - normal.dotProduct(_getNormal(definition, noise, location, detail));
|
||||
if (normal_diff > foam_factor)
|
||||
{
|
||||
foam_factor = normal_diff;
|
||||
}
|
||||
location.x += location_offset;
|
||||
location.z -= location_offset;
|
||||
normal_diff = 1.0 - normal.dotProduct(_getNormal(noise, location, detail));
|
||||
normal_diff = 1.0 - normal.dotProduct(_getNormal(definition, noise, location, detail));
|
||||
if (normal_diff > foam_factor)
|
||||
{
|
||||
foam_factor = normal_diff;
|
||||
}
|
||||
location.z += location_offset * 2.0;
|
||||
normal_diff = 1.0 - normal.dotProduct(_getNormal(noise, location, detail));
|
||||
normal_diff = 1.0 - normal.dotProduct(_getNormal(definition, noise, location, detail));
|
||||
if (normal_diff > foam_factor)
|
||||
{
|
||||
foam_factor = normal_diff;
|
||||
|
@ -162,7 +162,7 @@ HeightInfo WaterRenderer::getHeightInfo()
|
|||
|
||||
double WaterRenderer::getHeight(double x, double z)
|
||||
{
|
||||
return _getHeight(noise, x, z);
|
||||
return _getHeight(parent->getScenery()->getWater(), noise, x, z);
|
||||
}
|
||||
|
||||
WaterRenderer::WaterResult WaterRenderer::getResult(double x, double z)
|
||||
|
@ -176,7 +176,7 @@ WaterRenderer::WaterResult WaterRenderer::getResult(double x, double z)
|
|||
double reflection = definition->propReflection()->getValue();
|
||||
|
||||
location.x = x;
|
||||
location.y = _getHeight(noise, x, z);
|
||||
location.y = _getHeight(definition, noise, x, z);
|
||||
location.z = z;
|
||||
result.location = location;
|
||||
|
||||
|
@ -186,7 +186,7 @@ WaterRenderer::WaterResult WaterRenderer::getResult(double x, double z)
|
|||
detail = 0.00001;
|
||||
}
|
||||
|
||||
normal = _getNormal(noise, location, detail);
|
||||
normal = _getNormal(definition, noise, location, detail);
|
||||
look_direction = location.sub(parent->getCameraLocation(location)).normalize();
|
||||
|
||||
/* Reflection */
|
||||
|
|
Loading…
Reference in a new issue