From b6555f822ce34ae19ca8f077a9fe3198e7361f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Sun, 24 Jun 2012 16:04:01 +0000 Subject: [PATCH] paysages : Preetham approximation for sky (WIP) - New indirect lighting by skydome. git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@360 b1fd45b6-86a6-48da-8261-f70d1f35bdcc --- TODO | 2 +- gui_qt/formclouds.cpp | 1 - gui_qt/formrender.cpp | 10 +++ gui_qt/formsky.cpp | 1 + gui_qt/formterrain.cpp | 2 - gui_qt/formtextures.cpp | 1 - gui_qt/formwater.cpp | 1 - gui_qt/previewmaterial.cpp | 1 - gui_qt/widgetexplorer.cpp | 7 ++ i18n/paysages_fr.ts | 139 +++++++++++++++++++------------------ lib_paysages/auto.c | 8 +-- lib_paysages/euclid.c | 6 ++ lib_paysages/euclid.h | 6 ++ lib_paysages/lighting.c | 70 +++---------------- lib_paysages/lighting.h | 6 +- lib_paysages/rayleigh.c | 72 ++++++++++++++++--- lib_paysages/renderer.c | 6 ++ lib_paysages/renderer.h | 1 + lib_paysages/scenery.c | 6 ++ lib_paysages/sky.c | 75 +++++++++++++++----- lib_paysages/sky.h | 3 +- 21 files changed, 247 insertions(+), 177 deletions(-) diff --git a/TODO b/TODO index 7d1cf07..cd31cc5 100644 --- a/TODO +++ b/TODO @@ -1,10 +1,10 @@ Technology Preview 2 : - Finalize Preetham's model usage => Update all fields when "auto from daytime" is selected - => Apply the skydome lighting by directly sampling it (no more amplitude in lights) => Apply model to atmosphere (aerial perspective) => Find a proper model for night sky (maybe Shirley) - InputInt doesn't honor small_step. +- Keep skydome lights in cache for a render. - Disable form fields when no layer is selected. - Add buttons to restore "auto" default values in tabs and dialogs. - Remove color gradations (replace with automatic boolean and simple colors). diff --git a/gui_qt/formclouds.cpp b/gui_qt/formclouds.cpp index 12dead1..9301f29 100644 --- a/gui_qt/formclouds.cpp +++ b/gui_qt/formclouds.cpp @@ -68,7 +68,6 @@ public: _lighting = lightingCreateDefinition(); light.color = COLOR_WHITE; - light.amplitude = 0.0; light.direction.x = -1.0; light.direction.y = -1.0; light.direction.z = 1.0; diff --git a/gui_qt/formrender.cpp b/gui_qt/formrender.cpp index 738b6db..5bffb3d 100644 --- a/gui_qt/formrender.cpp +++ b/gui_qt/formrender.cpp @@ -19,6 +19,7 @@ public: _renderer.getTerrainHeight = _getTerrainHeight; _renderer.alterLight = _alterLight; _renderer.getLightStatus = _getLightStatus; + _renderer.getSkyDomeLights = _getSkyDomeLights; _renderer.camera_location.x = 0.0; _renderer.camera_location.y = 50.0; _renderer.camera_location.z = 0.0; @@ -27,11 +28,13 @@ public: _textures = texturesCreateDefinition(); _lighting = lightingCreateDefinition(); _water = waterCreateDefinition(); + _sky = skyCreateDefinition(); _renderer.customData[0] = &_terrain; _renderer.customData[1] = &_textures; _renderer.customData[2] = &_lighting; _renderer.customData[3] = &_water; + _renderer.customData[4] = &_sky; configScaling(0.5, 200.0, 3.0, 50.0); configScrolling(-1000.0, 1000.0, 0.0, -1000.0, 1000.0, 0.0); @@ -61,6 +64,7 @@ protected: sceneryGetLighting(&_lighting); sceneryGetTextures(&_textures); sceneryGetWater(&_water); + sceneryGetSky(&_sky); } private: Renderer _renderer; @@ -68,6 +72,7 @@ private: WaterDefinition _water; TexturesDefinition _textures; LightingDefinition _lighting; + SkyDefinition _sky; static double _getTerrainHeight(Renderer* renderer, double x, double z) { @@ -78,6 +83,11 @@ private: { return texturesGetColor((TexturesDefinition*)(renderer->customData[1]), renderer, location.x, location.z, precision); } + + static int _getSkyDomeLights(Renderer* renderer, LightDefinition* array, int max_lights) + { + return skyGetLights((SkyDefinition*)(renderer->customData[4]), renderer, array, max_lights); + } static void _alterLight(Renderer* renderer, LightDefinition* light, Vector3 location) { diff --git a/gui_qt/formsky.cpp b/gui_qt/formsky.cpp index 0632337..6556767 100644 --- a/gui_qt/formsky.cpp +++ b/gui_qt/formsky.cpp @@ -112,6 +112,7 @@ FormSky::FormSky(QWidget *parent): addInputDouble(tr("Sun radius"), &_definition.sun_radius, 0.0, 0.4, 0.004, 0.04); addInputDouble(tr("Sun halo radius"), &_definition.sun_halo_size, 0.0, 0.4, 0.004, 0.04); addInputCurve(tr("Sun halo profile"), _definition.sun_halo_profile, 0.0, 1.0, 0.0, 1.0); + addInputDouble(tr("Influence of skydome on lighting"), &_definition.dome_lighting, 0.0, 2.0, 0.01, 0.1); input = addInputBoolean(tr("Auto colors from daytime"), &_definition.model_custom.auto_from_daytime); input->setVisibilityCondition((int*)&_definition.model, SKY_MODEL_CUSTOM); input = addInputColor(tr("Zenith color"), &_definition.model_custom.zenith_color); diff --git a/gui_qt/formterrain.cpp b/gui_qt/formterrain.cpp index c780432..a31f7ce 100644 --- a/gui_qt/formterrain.cpp +++ b/gui_qt/formterrain.cpp @@ -60,7 +60,6 @@ public: light.color.r = 0.6; light.color.g = 0.6; light.color.b = 0.6; - light.amplitude = 0.0; light.direction.x = -1.0; light.direction.y = -0.5; light.direction.z = 1.0; @@ -72,7 +71,6 @@ public: light.color.r = 0.3; light.color.g = 0.3; light.color.b = 0.3; - light.amplitude = 0.0; light.direction.x = 0.5; light.direction.y = 0.7071; light.direction.z = -0.5; diff --git a/gui_qt/formtextures.cpp b/gui_qt/formtextures.cpp index d4215f7..78b8a14 100644 --- a/gui_qt/formtextures.cpp +++ b/gui_qt/formtextures.cpp @@ -77,7 +77,6 @@ public: _lighting = lightingCreateDefinition(); light.color = COLOR_WHITE; - light.amplitude = 0.0; light.direction.x = 0.0; light.direction.y = -0.4794; light.direction.z = 0.8776; diff --git a/gui_qt/formwater.cpp b/gui_qt/formwater.cpp index 30969bd..f2ec825 100644 --- a/gui_qt/formwater.cpp +++ b/gui_qt/formwater.cpp @@ -64,7 +64,6 @@ public: _lighting = lightingCreateDefinition(); light.color = COLOR_WHITE; - light.amplitude = 0.0; light.direction.x = 0.0; light.direction.y = -0.4794; light.direction.z = 0.8776; diff --git a/gui_qt/previewmaterial.cpp b/gui_qt/previewmaterial.cpp index 863a642..f85d0fc 100644 --- a/gui_qt/previewmaterial.cpp +++ b/gui_qt/previewmaterial.cpp @@ -15,7 +15,6 @@ SmallMaterialPreview::SmallMaterialPreview(QWidget* parent, SurfaceMaterial* mat _lighting = lightingCreateDefinition(); light.color = COLOR_WHITE; - light.amplitude = 0.0; light.direction.x = -0.5; light.direction.y = -0.5; light.direction.z = -0.5; diff --git a/gui_qt/widgetexplorer.cpp b/gui_qt/widgetexplorer.cpp index e9db5cf..fb6dbd6 100644 --- a/gui_qt/widgetexplorer.cpp +++ b/gui_qt/widgetexplorer.cpp @@ -58,6 +58,11 @@ static Color _applyTextures(Renderer* renderer, Vector3 location, double precisi return texturesGetColor((TexturesDefinition*)(renderer->customData[1]), renderer, location.x, location.z, precision); } +static int _getSkyDomeLights(Renderer* renderer, LightDefinition* array, int max_lights) +{ + return skyGetLights((SkyDefinition*)(renderer->customData[4]), renderer, array, max_lights); +} + static void _alterLight(Renderer* renderer, LightDefinition* light, Vector3 location) { light->color = terrainLightFilter((TerrainDefinition*)(renderer->customData[0]), renderer, light->color, location, v3Scale(light->direction, -1000.0), v3Scale(light->direction, -1.0)); @@ -94,8 +99,10 @@ WidgetExplorer::WidgetExplorer(QWidget *parent, CameraDefinition* camera): _renderer.customData[1] = &_textures; _renderer.customData[2] = &_lighting; _renderer.customData[3] = &_water; + _renderer.customData[4] = &_sky; _renderer.applyTextures = _applyTextures; _renderer.getTerrainHeight = _getTerrainHeight; + _renderer.getSkyDomeLights = _getSkyDomeLights; _renderer.alterLight = _alterLight; _renderer.getLightStatus = _getLightStatus; diff --git a/i18n/paysages_fr.ts b/i18n/paysages_fr.ts index 2b232f6..4c7b4c8 100644 --- a/i18n/paysages_fr.ts +++ b/i18n/paysages_fr.ts @@ -351,12 +351,12 @@ Maintenir Ctrl : Plus rapide FormClouds - + Layer coverage (no lighting) Couverture de la couche (sans éclairage) - + Color and lighting Echantillon éclairé @@ -373,12 +373,12 @@ Maintenir Ctrl : Plus rapide Altitude de fin - + Lower altitude - + Upper altitude @@ -395,7 +395,7 @@ Maintenir Ctrl : Plus rapide Echelle - + Material @@ -412,57 +412,57 @@ Maintenir Ctrl : Plus rapide Concentration de la réflexion de lumière - + Max coverage - + Coverage by altitude - + Shape noise - + Shape scaling - + Edge noise - + Edge scaling - + Edge length - + Hardness to light - + Transparency depth Distance de transparence - + Light traversal depth Distance de traversée de la lumière - + Minimum lighting Eclairage minimal @@ -520,62 +520,62 @@ Maintenir Ctrl : Plus rapide FormRender - + Top-down preview Aperçu plongeant - + Camera Caméra - + Quality Qualité de rendu - + Image width Largeur de l'image - + Image height Hauteur de l'image - + Anti aliasing - + Start new render Démarrer un rendu - + Show last render Voir le dernier rendu - + Save last render Sauvegarder le dernier rendu - + Paysages 3D - Choose a filename to save the last render Paysages 3D - Choisissez un nom de fichier pour le rendu - + Images (*.png *.jpg) Images (*.png *.jpg) - + Can't write to file : %1 @@ -588,7 +588,7 @@ Maintenir Ctrl : Plus rapide Choisissez un nom de fichier pour le rendu - + The picture %1 has been saved. L'image %1 a été sauvegardée. @@ -651,32 +651,37 @@ Maintenir Ctrl : Plus rapide - + + Influence of skydome on lighting + + + + Turbidity - + Zenith color Couleur du ciel au zénith - + Auto colors from daytime - + Haze color Couleur de la brume - + Haze height Hauteur apparente de la brume - + Haze smoothing Facteur de lissage de la brume @@ -684,7 +689,7 @@ Maintenir Ctrl : Plus rapide FormTerrain - + Height preview (normalized) Aperçu de la hauteur (normalisée) @@ -693,27 +698,27 @@ Maintenir Ctrl : Plus rapide Aperçu du rendu (sans ombres) - + Lighted preview (no texture) Aperçu éclairé (sans texture) - + Noise Bruit - + Height Hauteur - + Scaling Echelle - + Shadow smoothing @@ -721,7 +726,7 @@ Maintenir Ctrl : Plus rapide FormTextures - + Coverage preview Aperçu de la couverture @@ -730,22 +735,22 @@ Maintenir Ctrl : Plus rapide Rendu en couleur - + Lighted sample Echantillon éclairé - + Surface noise Bruit de surface - + Surface noise height Hauteur du bruit - + Surface noise scaling Echelle du bruit @@ -762,47 +767,47 @@ Maintenir Ctrl : Plus rapide Concentration de la lumière réfléchie - + Soft minimal height Altitude minimal (adoucie) - + Hard minimal height Altitude minimale - + Material - + Hard maximal height Altitude maximale - + Soft maximal height Altitude maximale (adoucie) - + Soft minimal slope Pente minimale (adoucie) - + Hard minimal slope Pente minimale - + Hard maximal slope Pente maximale - + Soft maximal slope Pente maximale (adoucie) @@ -810,7 +815,7 @@ Maintenir Ctrl : Plus rapide FormWater - + Coverage preview Aperçu de la couverture @@ -819,7 +824,7 @@ Maintenir Ctrl : Plus rapide Aperçu du rendu (sans/avec éclairage) - + Height Hauteur @@ -836,52 +841,52 @@ Maintenir Ctrl : Plus rapide Concentration de la lumière réfléchie - + Surface material - + Transparency Transparence - + Reflection Reflets - + Transparency distance Distance maximale de transparence - + Depth color Couleur en profondeur - + Rendered preview - + Light-through distance Distance de filtrage de la lumière - + Waves noise Bruit des vagues - + Waves height Hauteur des vagues - + Waves scaling Echelle des vagues diff --git a/lib_paysages/auto.c b/lib_paysages/auto.c index 97cb77a..43996ce 100644 --- a/lib_paysages/auto.c +++ b/lib_paysages/auto.c @@ -64,7 +64,6 @@ void autoGenRealisticLandscape(int seed) SkyDefinition sky; TexturesDefinition textures; TextureLayerDefinition* texture; - LightingDefinition lighting; if (!seed) { @@ -114,6 +113,7 @@ void autoGenRealisticLandscape(int seed) sky.sun_color.a = 1.0; sky.sun_radius = 0.02; sky.sun_halo_size = 0.3; + sky.dome_lighting = 0.6; curveClear(sky.sun_halo_profile); curveQuickAddPoint(sky.sun_halo_profile, 0.0, 1.0); curveQuickAddPoint(sky.sun_halo_profile, 0.1, 0.2); @@ -133,12 +133,6 @@ void autoGenRealisticLandscape(int seed) scenerySetSky(&sky); skyDeleteDefinition(&sky); - /* Lighting */ - lighting = lightingCreateDefinition(); - lighting.autosetfromsky = 1; - scenerySetLighting(&lighting); - lightingDeleteDefinition(&lighting); - /* Terrain */ terrain = terrainCreateDefinition(); noiseGenerateBaseNoise(terrain.height_noise, 1048576); diff --git a/lib_paysages/euclid.c b/lib_paysages/euclid.c index e3e121c..9faac7e 100644 --- a/lib_paysages/euclid.c +++ b/lib_paysages/euclid.c @@ -5,6 +5,12 @@ #include "tools.h" Vector3 VECTOR_ZERO = {0.0, 0.0, 0.0}; +Vector3 VECTOR_DOWN = {0.0, -1.0, 0.0}; +Vector3 VECTOR_UP = {0.0, 1.0, 0.0}; +Vector3 VECTOR_NORTH = {0.0, 0.0, -1.0}; +Vector3 VECTOR_SOUTH = {0.0, 0.0, 1.0}; +Vector3 VECTOR_WEST = {-1.0, 0.0, 0.0}; +Vector3 VECTOR_EAST = {1.0, 0.0, 0.0}; void v3Save(PackStream* stream, Vector3* v) { diff --git a/lib_paysages/euclid.h b/lib_paysages/euclid.h index 9875483..a28fc64 100644 --- a/lib_paysages/euclid.h +++ b/lib_paysages/euclid.h @@ -35,6 +35,12 @@ typedef struct } Matrix4; extern Vector3 VECTOR_ZERO; +extern Vector3 VECTOR_DOWN; +extern Vector3 VECTOR_UP; +extern Vector3 VECTOR_NORTH; +extern Vector3 VECTOR_SOUTH; +extern Vector3 VECTOR_EAST; +extern Vector3 VECTOR_WEST; void v3Save(PackStream* stream, Vector3* v); void v3Load(PackStream* stream, Vector3* v); diff --git a/lib_paysages/lighting.c b/lib_paysages/lighting.c index 5396cfb..f5bb5f3 100644 --- a/lib_paysages/lighting.c +++ b/lib_paysages/lighting.c @@ -26,7 +26,6 @@ void lightingInit() _LIGHT_NULL.reflection = 0.0; _LIGHT_NULL.filtered = 0; _LIGHT_NULL.masked = 0; - _LIGHT_NULL.amplitude = 0.0; } void lightingQuit() @@ -37,7 +36,6 @@ void lightingSave(PackStream* stream, LightingDefinition* definition) { int i; - packWriteInt(stream, &definition->autosetfromsky); packWriteInt(stream, &definition->nblights); for (i = 0; i < definition->nblights; i++) { @@ -46,7 +44,6 @@ void lightingSave(PackStream* stream, LightingDefinition* definition) packWriteDouble(stream, &definition->lights[i].reflection); packWriteInt(stream, &definition->lights[i].filtered); packWriteInt(stream, &definition->lights[i].masked); - packWriteDouble(stream, &definition->lights[i].amplitude); } } @@ -54,7 +51,6 @@ void lightingLoad(PackStream* stream, LightingDefinition* definition) { int i; - packReadInt(stream, &definition->autosetfromsky); packReadInt(stream, &definition->nblights); for (i = 0; i < definition->nblights; i++) { @@ -63,7 +59,6 @@ void lightingLoad(PackStream* stream, LightingDefinition* definition) packReadDouble(stream, &definition->lights[i].reflection); packReadInt(stream, &definition->lights[i].filtered); packReadInt(stream, &definition->lights[i].masked); - packReadDouble(stream, &definition->lights[i].amplitude); } lightingValidateDefinition(definition); @@ -73,9 +68,7 @@ LightingDefinition lightingCreateDefinition() { LightingDefinition definition; - definition.autosetfromsky = 0; definition.nblights = 0; - definition._nbautolights = 0; return definition; } @@ -91,19 +84,6 @@ void lightingCopyDefinition(LightingDefinition* source, LightingDefinition* dest void lightingValidateDefinition(LightingDefinition* definition) { - if (definition->autosetfromsky) - { - SkyDefinition sky; - - sky = skyCreateDefinition(); - sceneryGetSky(&sky); - definition->_nbautolights = skyGetLights(&sky, definition->_autolights, LIGHTING_MAX_LIGHTS); - skyDeleteDefinition(&sky); - } - else - { - definition->_nbautolights = 0; - } } int lightingGetLightCount(LightingDefinition* definition) @@ -176,44 +156,6 @@ static Color _applyDirectLight(LightDefinition* definition, Renderer* renderer, light = definition->color; direction_inv = v3Scale(definition->direction, -1.0); - if (definition->amplitude > 0.0) - { - /* TODO Sampling around light direction */ - int xsamples, ysamples, samples, x, y; - double xstep, ystep, factor; - LightDefinition sublight; - - ysamples = renderer->render_quality / 4 + 1; - xsamples = renderer->render_quality / 2 + 1; - samples = xsamples * ysamples + 1; - factor = 1.0 / (double)samples; - - xstep = M_PI * 2.0 / (double)xsamples; - ystep = M_PI * 0.5 / (double)(ysamples - 1); - - sublight = *definition; - sublight.amplitude = 0.0; - sublight.color.r *= factor; - sublight.color.g *= factor; - sublight.color.b *= factor; - - result = _applyDirectLight(&sublight, renderer, location, normal, material); - for (x = 0; x < xsamples; x++) - { - for (y = 0; y < ysamples; y++) - { - sublight.direction.x = cos(x * xstep) * cos(y * ystep); - sublight.direction.y = -sin(y * ystep); - sublight.direction.z = sin(x * xstep) * cos(y * ystep); - light = _applyDirectLight(&sublight, renderer, location, normal, material); - result.r += light.r; - result.g += light.g; - result.b += light.b; - } - } - return result; - } - normal_norm = v3Norm(normal); if (normal_norm > 1.0) { @@ -266,10 +208,12 @@ static Color _applyDirectLight(LightDefinition* definition, Renderer* renderer, void lightingGetStatus(LightingDefinition* definition, Renderer* renderer, Vector3 location, LightStatus* result) { - int i; + int i, skydome_lights_count; + LightDefinition skydome_lights[LIGHTING_MAX_LIGHTS]; result->nblights = 0; + /* Apply static lights */ for (i = 0; i < definition->nblights; i++) { if (_getLightStatus(definition->lights + i, renderer, location, result->lights + result->nblights)) @@ -277,9 +221,13 @@ void lightingGetStatus(LightingDefinition* definition, Renderer* renderer, Vecto result->nblights++; } } - for (i = 0; i < definition->_nbautolights; i++) + + /* Apply skydome lights */ + /* TODO Cache skydome lights for same render */ + skydome_lights_count = renderer->getSkyDomeLights(renderer, skydome_lights, LIGHTING_MAX_LIGHTS); + for (i = 0; i < skydome_lights_count; i++) { - if (_getLightStatus(definition->_autolights + i, renderer, location, result->lights + result->nblights)) + if (_getLightStatus(skydome_lights + i, renderer, location, result->lights + result->nblights)) { result->nblights++; } diff --git a/lib_paysages/lighting.h b/lib_paysages/lighting.h index cb5cae7..c753301 100644 --- a/lib_paysages/lighting.h +++ b/lib_paysages/lighting.h @@ -9,7 +9,7 @@ extern "C" { #endif -#define LIGHTING_MAX_LIGHTS 10 +#define LIGHTING_MAX_LIGHTS 30 struct LightDefinition { @@ -18,16 +18,12 @@ struct LightDefinition double reflection; /* Reflected factor of the light (for specular lighting) */ int filtered; /* Should the light be filtered (by atmosphere, water...) */ int masked; /* Should the light be masked (cast shadows..) */ - double amplitude; /* Angle amplitude of the light source (for multi-sampling, pi / 2.0 for skydome) */ }; typedef struct { - int autosetfromsky; int nblights; LightDefinition lights[LIGHTING_MAX_LIGHTS]; - int _nbautolights; - LightDefinition _autolights[LIGHTING_MAX_LIGHTS]; } LightingDefinition; struct LightStatus diff --git a/lib_paysages/rayleigh.c b/lib_paysages/rayleigh.c index 969418d..5932510 100644 --- a/lib_paysages/rayleigh.c +++ b/lib_paysages/rayleigh.c @@ -2,21 +2,71 @@ #include -/*static double _phase(double g, double theta) -{ - double g2 = g * g; - double costheta = cos(theta); - return ((3.0 * (1.0 - g2)) / (2.0 * (2.0 + g2))) * ((1.0 + costheta * costheta) / exp(1.0 + g2 - 2.0 * g * costheta, 1.5)); -} +static Vector3 _betaR = {5.5e-6, 13.0e-6, 22.4e-6}; /* Rayleigh scattering coefficients at sea level */ +static Vector3 _betaM = {21e-6, 0.0, 0.0}; /* Mie scattering coefficients at sea level */ +static double _Hr = 7994; /* Rayleigh scale height */ +static double _Hm = 1200; /* Mie scale height */ +static double _radiusEarth = 6360e3; /* Earth radius */ +static double _radiusAtmosphere = 6420e3; /* Atmosphere radius */ +static double _sunIntensity = 20.0; /* Sun intensity */ +static double _g = 0.76; /* Mean cosine */ -static double _intOpticalDepthCallback(double h, double* h0) +/*typedef struct { - return -h / *h0; -} + double tmin; + double tmax; +} Ray; -static double _opticalDepth(double h0, double lambda, double k, Vector3 start, Vector3 end) +static Vector3 _computeIncidentLight(Ray r) { - return 4.0 * M_PI * k * toolsIntegrate(_intOpticalDepthCallback); + double t0, t1; + int numSamples = 16; + int numSamplesLight = 8; + int i, j; + + if (!intersect(r, radiusAtmosphere, t0, t1) || t1 < 0) return Vec3(0); + if (t0 > r.tmin && t0 > 0) r.tmin = t0; + if (t1 < r.tmax) r.tmax = t1; + double segmentLength = (r.tmax - r.tmin) / (double)numSamples; + double tCurrent = r.tmin; + Vector3 sumR = VECTOR_ZERO; + Vector3 sumM = VECTOR_ZERO; + double opticalDepthR = 0.0; + double opticalDepthM = 0.0; + double mu = r.direction.dot(sunDirection); + double phaseR = 3.0 / (16.0 * M_PI) * (1.0 + mu * mu); + double phaseM = 3.0 / (8.0 * M_PI) * ((1.0 - _g * _g) * (1 + mu * mu)) / ((2 + _g * _g) * pow(1 + _g * _g - 2 * _g * mu, 1.5)); + for (i = 0; i < numSamples; ++i) + { + Vector3 samplePosition = r(tCurrent + T(0.5) * segmentLength); + double height = samplePosition.magnitude() - radiusEarth; + double hr = exp(-height / _Hr) * segmentLength; + double hm = exp(-height / _Hm) * segmentLength; + opticalDepthR += hr; + opticalDepthM += hm; + Ray lightRay(samplePosition, sunDirection); + intersect(lightRay, radiusAtmosphere, lightRay.tmin, lightRay.tmax); + double segmentLengthLight = lightRay.tmax / numSamplesLight; + double tCurrentLight = 0.0; + double opticalDepthLightR = 0.0; + double opticalDepthLightM = 0.0; + for (j = 0; j < numSamplesLight; ++j) { + Vector3 samplePositionLight = lightRay(tCurrentLight + T(0.5) * segmentLengthLight); + T heightLight = samplePositionLight.magnitude() - radiusEarth; + if (heightLight < 0) break; + opticalDepthLightR += exp(-heightLight / Hr) * segmentLengthLight; + opticalDepthLightM += exp(-heightLight / Hm) * segmentLengthLight; + tCurrentLight += segmentLengthLight; + } + if (j == numSamplesLight) { + Vec3 tau = betaR * (opticalDepthR + opticalDepthLightR) + betaM * 1.1 * (opticalDepthM + opticalDepthLightM); + Vec3 attenuation(exp(-tau.x), exp(-tau.y), exp(-tau.z)); + sumR += hr * attenuation; + sumM += hm * attenuation; + } + tCurrent += segmentLength; + } + return 20 * (sumR * phaseR * _betaR + sumM * phaseM * _betaM); }*/ Color rayleighGetSkyColor(Vector3 viewer, Vector3 direction, Vector3 sun_direction) diff --git a/lib_paysages/renderer.c b/lib_paysages/renderer.c index a82a1b5..3adaf14 100644 --- a/lib_paysages/renderer.c +++ b/lib_paysages/renderer.c @@ -54,6 +54,11 @@ static void _pushQuad(Renderer* renderer, Vector3 v1, Vector3 v2, Vector3 v3, Ve renderer->pushTriangle(renderer, v4, v1, v3, callback, callback_data); } +static int _getSkyDomeLights(Renderer* renderer, LightDefinition* array, int max_lights) +{ + return 0; +} + static void _alterLight(Renderer* renderer, LightDefinition* light, Vector3 location) { } @@ -129,6 +134,7 @@ Renderer rendererCreate() result.applyAtmosphere = _applyAtmosphere; result.applyClouds = _applyClouds; + result.getSkyDomeLights = _getSkyDomeLights; result.alterLight = _alterLight; result.getLightStatus = _getLightStatus; result.applyLightStatus = _applyLightStatus; diff --git a/lib_paysages/renderer.h b/lib_paysages/renderer.h index 3528d37..c9a672d 100644 --- a/lib_paysages/renderer.h +++ b/lib_paysages/renderer.h @@ -39,6 +39,7 @@ struct Renderer Color (*applyClouds)(Renderer* renderer, Color base, Vector3 start, Vector3 end); /* Lighting related */ + int (*getSkyDomeLights)(Renderer* renderer, LightDefinition* array, int max_lights); void (*alterLight)(Renderer* renderer, LightDefinition* light, Vector3 location); void (*getLightStatus)(Renderer* renderer, LightStatus* status, Vector3 location); Color (*applyLightStatus)(Renderer* renderer, LightStatus* status, Vector3 location, Vector3 normal, SurfaceMaterial material); diff --git a/lib_paysages/scenery.c b/lib_paysages/scenery.c index 567f261..e31681e 100644 --- a/lib_paysages/scenery.c +++ b/lib_paysages/scenery.c @@ -224,6 +224,11 @@ void sceneryRenderFirstPass(Renderer* renderer) /******* Standard renderer *********/ +static int _getSkyDomeLights(Renderer* renderer, LightDefinition* array, int max_lights) +{ + return skyGetLights(&_sky, renderer, array, max_lights); +} + static void _alterLight(Renderer* renderer, LightDefinition* light, Vector3 location) { Vector3 light_location; @@ -330,6 +335,7 @@ Renderer sceneryCreateStandardRenderer() cameraCopyDefinition(&_camera, &result.render_camera); result.camera_location = _camera.location; + result.getSkyDomeLights = _getSkyDomeLights; result.alterLight = _alterLight; result.getLightStatus = _getLightStatus; result.applyLightStatus = _applyLightStatus; diff --git a/lib_paysages/sky.c b/lib_paysages/sky.c index ba987e2..54a8489 100644 --- a/lib_paysages/sky.c +++ b/lib_paysages/sky.c @@ -32,6 +32,7 @@ void skySave(PackStream* stream, SkyDefinition* definition) packWriteDouble(stream, &definition->sun_radius); packWriteDouble(stream, &definition->sun_halo_size); curveSave(stream, definition->sun_halo_profile); + packWriteDouble(stream, &definition->dome_lighting); packWriteInt(stream, &definition->model_custom.auto_from_daytime); colorSave(stream, &definition->model_custom.zenith_color); @@ -50,6 +51,7 @@ void skyLoad(PackStream* stream, SkyDefinition* definition) packReadDouble(stream, &definition->sun_radius); packReadDouble(stream, &definition->sun_halo_size); curveLoad(stream, definition->sun_halo_profile); + packReadDouble(stream, &definition->dome_lighting); packReadInt(stream, &definition->model_custom.auto_from_daytime); colorLoad(stream, &definition->model_custom.zenith_color); @@ -72,6 +74,7 @@ SkyDefinition skyCreateDefinition() def.sun_radius = 1.0; def.sun_halo_size = 0.0; def.sun_halo_profile = curveCreate(); + def.dome_lighting = 0.0; def.model_custom.auto_from_daytime = 0; def.model_custom.zenith_color = COLOR_BLACK; def.model_custom.haze_color = COLOR_BLACK; @@ -98,6 +101,7 @@ void skyCopyDefinition(SkyDefinition* source, SkyDefinition* destination) destination->sun_color = source->sun_color; destination->sun_radius = source->sun_radius; destination->sun_halo_size = source->sun_halo_size; + destination->dome_lighting = source->dome_lighting; destination->model_custom.auto_from_daytime = source->model_custom.auto_from_daytime; destination->model_custom.zenith_color = source->model_custom.zenith_color; destination->model_custom.haze_color = source->model_custom.haze_color; @@ -156,7 +160,19 @@ void skyValidateDefinition(SkyDefinition* definition) } } -int skyGetLights(SkyDefinition* sky, LightDefinition* lights, int max_lights) +static inline void _addDomeLight(SkyDefinition* sky, Renderer* renderer, LightDefinition* light, Vector3 direction, double factor) +{ + light->direction = v3Scale(direction, -1.0); + light->color = skyGetColor(sky, renderer, VECTOR_ZERO, direction); + light->color.r *= factor; + light->color.g *= factor; + light->color.b *= factor; + light->reflection = 0.0; + light->filtered = 0; + light->masked = 0; +} + +int skyGetLights(SkyDefinition* sky, Renderer* renderer, LightDefinition* lights, int max_lights) { double sun_angle; Vector3 sun_direction; @@ -167,33 +183,56 @@ int skyGetLights(SkyDefinition* sky, LightDefinition* lights, int max_lights) sun_direction.y = sin(sun_angle); sun_direction.z = 0.0; - /* TODO Night lights */ + /* TODO Moon light */ if (max_lights > 0) { - /* Light from the sun */ + /* Direct light from the sun */ lights[0].direction = v3Scale(sun_direction, -1.0); lights[0].color = sky->sun_color; lights[0].reflection = 1.0; lights[0].filtered = 1; lights[0].masked = 1; - lights[0].amplitude = 0.0; nblights = 1; - if (max_lights > 1) + max_lights--; + } + + if (max_lights > 0) + { + /* Indirect lighting by skydome scattering */ + int xsamples, ysamples, samples, x, y; + double xstep, ystep, factor; + Vector3 direction; + + samples = (renderer->render_quality < 5) ? 9 : (renderer->render_quality * 4 + 1); + samples = samples > max_lights ? max_lights : samples; + + factor = sky->dome_lighting / (double)samples; + + _addDomeLight(sky, renderer, lights + nblights, VECTOR_UP, factor); + nblights++; + samples--; + + if (samples >= 2) { - /* Skydome lighting */ - lights[1].direction.x = 0.0; - lights[1].direction.y = -1.0; - lights[1].direction.z = 0.0; - lights[1].color = skyGetZenithColor(sky); - lights[1].color.r *= 0.6; - lights[1].color.g *= 0.6; - lights[1].color.b *= 0.6; - lights[1].reflection = 0.0; - lights[1].filtered = 1; - lights[1].masked = 0; - lights[1].amplitude = M_PI / 2.0; - nblights = 2; + xsamples = samples / 2; + ysamples = samples / xsamples; + + xstep = M_PI * 2.0 / (double)xsamples; + ystep = M_PI * 0.5 / (double)ysamples; + + for (x = 0; x < xsamples; x++) + { + for (y = 0; y < ysamples; y++) + { + direction.x = cos(x * xstep) * cos(y * ystep); + direction.y = -sin(y * ystep); + direction.z = sin(x * xstep) * cos(y * ystep); + + _addDomeLight(sky, renderer, lights + nblights, direction, factor); + nblights++; + } + } } } diff --git a/lib_paysages/sky.h b/lib_paysages/sky.h index 4912e1b..ac6af65 100644 --- a/lib_paysages/sky.h +++ b/lib_paysages/sky.h @@ -25,6 +25,7 @@ typedef struct double sun_radius; double sun_halo_size; Curve* sun_halo_profile; + double dome_lighting; struct { int auto_from_daytime; Color zenith_color; @@ -48,7 +49,7 @@ void skyDeleteDefinition(SkyDefinition* definition); void skyCopyDefinition(SkyDefinition* source, SkyDefinition* destination); void skyValidateDefinition(SkyDefinition* definition); -int skyGetLights(SkyDefinition* sky, LightDefinition* lights, int max_lights); +int skyGetLights(SkyDefinition* sky, Renderer* renderer, LightDefinition* lights, int max_lights); Color skyGetColor(SkyDefinition* definition, Renderer* renderer, Vector3 eye, Vector3 look); void skyRender(SkyDefinition* definition, Renderer* renderer); Vector3 skyGetSunDirection(SkyDefinition* definition);