diff --git a/TODO b/TODO index 434c9f2..e3a360e 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,5 @@ Technology Preview 2 : +- Implement High Dynamic Range (with OpenEXR or Radiance file format support ?). - Fully move layer management from BaseForm to BaseFormLayer. - Replace terrain canvas editor by full sculpting editor. => Add a generation dialog, with fixed resolution. @@ -43,7 +44,6 @@ Technlogy Preview 3 : Technology Preview 4 : - Restore render progress. - Store the terrain canvases in a tree to allow "multi-res" edition. -- Implement High Dynamic Range. - Implement Sub Surface Scattering for water. - Use bicubic interpolation for antialiasing. - Allow for larger renders/antialias (will need several two-pass chunks). diff --git a/gui_qt/dialogrender.cpp b/gui_qt/dialogrender.cpp index c17bfbe..b809f54 100644 --- a/gui_qt/dialogrender.cpp +++ b/gui_qt/dialogrender.cpp @@ -26,6 +26,7 @@ static void _renderStart(int width, int height, Color background) static void _renderDraw(int x, int y, Color col) { + col = colorProfileApply(_current_dialog->_hdr_profile, col); _current_dialog->pixbuf->setPixel(x, _current_dialog->pixbuf->height() - 1 - y, colorToQColor(col).rgb()); } @@ -79,6 +80,8 @@ DialogRender::DialogRender(QWidget *parent, Renderer* renderer): _render_thread = NULL; _renderer = renderer; + _hdr_profile = colorProfileCreate(); + setModal(true); setWindowTitle(tr("Paysages 3D - Render")); setLayout(new QVBoxLayout()); @@ -116,6 +119,7 @@ DialogRender::~DialogRender() delete _render_thread; } + colorProfileDelete(_hdr_profile); delete pixbuf; delete pixbuf_lock; } diff --git a/gui_qt/dialogrender.h b/gui_qt/dialogrender.h index ad0d49b..f33edf6 100644 --- a/gui_qt/dialogrender.h +++ b/gui_qt/dialogrender.h @@ -9,6 +9,7 @@ #include #include #include "../lib_paysages/renderer.h" +#include "../lib_paysages/color.h" class DialogRender : public QDialog { @@ -25,6 +26,7 @@ public: QImage* pixbuf; QMutex* pixbuf_lock; QWidget* area; + ColorProfile* _hdr_profile; private slots: void applyRenderSize(int width, int height); diff --git a/lib_paysages/atmosphere/bruneton.c b/lib_paysages/atmosphere/bruneton.c index 885992d..074f900 100644 --- a/lib_paysages/atmosphere/bruneton.c +++ b/lib_paysages/atmosphere/bruneton.c @@ -302,22 +302,6 @@ static Color _transmittanceWithShadow(double r, double mu) return mu < -sqrt(1.0 - (Rg / r) * (Rg / r)) ? COLOR_BLACK : _transmittance(r, mu); } -static Color _hdr(Color c1, Color c2, Color c3) -{ - Color L = {c1.r + c2.r + c3.r, c1.g + c2.g + c3.g, c1.b + c2.b + c3.b, 1.0}; - - L.r *= exposure; - L.g *= exposure; - L.b *= exposure; - L.a = 1.0; - - L.r = L.r < 1.413 ? pow(L.r * 0.38317, 1.0 / 2.2) : 1.0 - exp(-L.r); - L.g = L.g < 1.413 ? pow(L.g * 0.38317, 1.0 / 2.2) : 1.0 - exp(-L.g); - L.b = L.b < 1.413 ? pow(L.b * 0.38317, 1.0 / 2.2) : 1.0 - exp(-L.b); - - return L; -} - static void _getMuMuSNu(double x, double y, double r, Color dhdH, double* mu, double* muS, double* nu) { double d; @@ -1252,9 +1236,12 @@ Color brunetonGetSkyColor(AtmosphereDefinition* definition, Vector3 eye, Vector3 Vector3 attenuation; Color inscatterColor = _getInscatterColor(&x, &t, v, s, &r, &mu, &attenuation); /* S[L]-T(x,xs)S[l]|xs */ - Color groundColor = COLOR_BLACK; Color sunColor = _sunColor(x, 0.0, v, s, r, mu); /* L0 */ - return _hdr(sunColor, groundColor, inscatterColor); /* Eq (16) */ + + inscatterColor.r += sunColor.r; + inscatterColor.g += sunColor.g; + inscatterColor.b += sunColor.b; + return inscatterColor; /* Eq (16) */ } Color brunetonApplyAerialPerspective(Renderer* renderer, Vector3 location, Color base) @@ -1297,6 +1284,9 @@ Color brunetonApplyAerialPerspective(Renderer* renderer, Vector3 location, Color Vector3 attenuation; Color inscatterColor = _getInscatterColor(&x, &t, v, s, &r, &mu, &attenuation); /* S[L]-T(x,xs)S[l]|xs */ Color groundColor = _groundColor(base, x, t, v, s, r, mu, attenuation); //R[L0]+R[L*]*/ - Color sunColor = COLOR_BLACK; - return _hdr(sunColor, groundColor, inscatterColor); /* Eq (16) */ + + groundColor.r += inscatterColor.r; + groundColor.g += inscatterColor.g; + groundColor.b += inscatterColor.b; + return groundColor; /* Eq (16) */ } diff --git a/lib_paysages/atmosphere/presets.c b/lib_paysages/atmosphere/presets.c index eccdb04..4a5e81c 100644 --- a/lib_paysages/atmosphere/presets.c +++ b/lib_paysages/atmosphere/presets.c @@ -24,34 +24,34 @@ void atmosphereAutoPreset(AtmosphereDefinition* definition, AtmospherePreset pre definition->model = ATMOSPHERE_MODEL_BRUNETON; definition->hour = 15; definition->minute = 0; - definition->dome_lighting = 0.6; + definition->dome_lighting = 0.2; break; case ATMOSPHERE_PRESET_CLEAR_SUNSET: definition->model = ATMOSPHERE_MODEL_BRUNETON; definition->hour = 17; definition->minute = 45; - definition->dome_lighting = 0.8; + definition->dome_lighting = 0.3; definition->sun_radius = 0.03; break; case ATMOSPHERE_PRESET_HAZY_MORNING: definition->model = ATMOSPHERE_MODEL_PREETHAM; definition->hour = 8; definition->minute = 30; - definition->dome_lighting = 0.5; + definition->dome_lighting = 0.25; definition->humidity = 0.3; break; case ATMOSPHERE_PRESET_FOGGY: definition->model = ATMOSPHERE_MODEL_PREETHAM; definition->hour = 15; definition->minute = 0; - definition->dome_lighting = 0.7; + definition->dome_lighting = 0.1; definition->humidity = 0.6; break; case ATMOSPHERE_PRESET_STORMY: definition->model = ATMOSPHERE_MODEL_PREETHAM; definition->hour = 15; definition->minute = 0; - definition->dome_lighting = 0.3; + definition->dome_lighting = 0.05; definition->humidity = 0.9; break; default: diff --git a/lib_paysages/color.c b/lib_paysages/color.c index 227907c..553f12b 100644 --- a/lib_paysages/color.c +++ b/lib_paysages/color.c @@ -3,9 +3,12 @@ #include #include #include +#include #include "tools.h" #include "curve.h" +/******************************** Color ********************************/ + Color COLOR_TRANSPARENT = {0.0, 0.0, 0.0, 0.0}; Color COLOR_BLACK = {0.0, 0.0, 0.0, 1.0}; Color COLOR_RED = {1.0, 0.0, 0.0, 1.0}; @@ -14,13 +17,6 @@ Color COLOR_BLUE = {0.0, 0.0, 1.0, 1.0}; Color COLOR_WHITE = {1.0, 1.0, 1.0, 1.0}; Color COLOR_GREY = {0.5, 0.5, 0.5, 1.0}; -struct ColorGradation -{ - Curve* red; - Curve* green; - Curve* blue; -}; - void colorSave(PackStream* stream, Color* col) { packWriteDouble(stream, &col->r); @@ -60,48 +56,48 @@ unsigned int colorTo32BitABGR(Color* col) Color colorFrom32BitRGBA(unsigned int col) { Color result; - + result.r = ((double)(col & 0x000000FF)) / 255.0; result.g = ((double)((col & 0x0000FF00) >> 8)) / 255.0; result.b = ((double)((col & 0x00FF0000) >> 16)) / 255.0; result.a = ((double)((col & 0xFF000000) >> 24)) / 255.0; - + return result; } Color colorFrom32BitBGRA(unsigned int col) { Color result; - + result.b = ((double)(col & 0x000000FF)) / 255.0; result.g = ((double)((col & 0x0000FF00) >> 8)) / 255.0; result.r = ((double)((col & 0x00FF0000) >> 16)) / 255.0; result.a = ((double)((col & 0xFF000000) >> 24)) / 255.0; - + return result; } Color colorFrom32BitARGB(unsigned int col) { Color result; - + result.a = ((double)(col & 0x000000FF)) / 255.0; result.r = ((double)((col & 0x0000FF00) >> 8)) / 255.0; result.g = ((double)((col & 0x00FF0000) >> 16)) / 255.0; result.b = ((double)((col & 0xFF000000) >> 24)) / 255.0; - + return result; } Color colorFrom32BitABGR(unsigned int col) { Color result; - + result.a = ((double)(col & 0x000000FF)) / 255.0; result.b = ((double)((col & 0x0000FF00) >> 8)) / 255.0; result.g = ((double)((col & 0x00FF0000) >> 16)) / 255.0; result.r = ((double)((col & 0xFF000000) >> 24)) / 255.0; - + return result; } @@ -125,7 +121,20 @@ void colorMask(Color* base, Color* mask) double colorNormalize(Color* col) { - double max = colorGetValue(col); + if (col->r > 1.0) + { + col->r = 1.0; + } + if (col->g > 1.0) + { + col->g = 1.0; + } + if (col->b > 1.0) + { + col->b = 1.0; + } + return 1.0; + /*double max = colorGetValue(col); assert(max >= 0.0); assert(col->r >= 0.0); @@ -139,7 +148,7 @@ double colorNormalize(Color* col) col->g /= max; col->b /= max; } - return max; + return max;*/ } double colorGetValue(Color* col) @@ -158,6 +167,96 @@ double colorGetValue(Color* col) return max; } +/******************************** ColorProfile ********************************/ +struct ColorProfile +{ + double minvalue; + double maxvalue; +}; + +ColorProfile* colorProfileCreate() +{ + ColorProfile* profile; + + profile = malloc(sizeof(ColorProfile)); + + colorProfileClear(profile); + + return profile; +} + +void colorProfileDelete(ColorProfile* profile) +{ + free(profile); +} + +void colorProfileSave(PackStream* stream, ColorProfile* profile) +{ + /* TODO */ +} + +void colorProfileLoad(PackStream* stream, ColorProfile* profile) +{ + /* TODO */ +} + +void colorProfileClear(ColorProfile* profile) +{ + profile->minvalue = 0.0; + profile->maxvalue = 3.0; +} + +int colorProfileCollect(ColorProfile* profile, Color pixel) +{ + int changed = 0; + double value = pixel.r + pixel.g + pixel.b; + + if (value < profile->minvalue) + { + profile->minvalue = value; + changed = 1; + } + if (value > profile->maxvalue) + { + profile->maxvalue = value; + changed = 1; + } + return changed; +} + +float A = 0.15; +float B = 0.50; +float C = 0.10; +float D = 0.20; +float E = 0.02; +float F = 0.30; +float W = 11.2; + +static double _uncharted2Tonemap(double x) +{ + return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F; +} + +Color colorProfileApply(ColorProfile* profile, Color pixel) +{ + double exposure_bias = 2.0; + double white_scale = 1.0 / _uncharted2Tonemap(W); + + pixel.r = pow(_uncharted2Tonemap(pixel.r * exposure_bias) * white_scale, 1.0 / 2.2); + pixel.g = pow(_uncharted2Tonemap(pixel.g * exposure_bias) * white_scale, 1.0 / 2.2); + pixel.b = pow(_uncharted2Tonemap(pixel.b * exposure_bias) * white_scale, 1.0 / 2.2); + + return pixel; +} + +/******************************** ColorGradation ********************************/ +struct ColorGradation +{ + Curve* red; + Curve* green; + Curve* blue; +}; + ColorGradation* colorGradationCreate() { ColorGradation* result; @@ -166,7 +265,7 @@ ColorGradation* colorGradationCreate() result->red = curveCreate(); result->green = curveCreate(); result->blue = curveCreate(); - + return result; } @@ -264,7 +363,7 @@ Color colorGradationGet(ColorGradation* gradation, double value) result.g = curveGetValue(gradation->green, value); result.b = curveGetValue(gradation->blue, value); result.a = 1.0; - + return result; } diff --git a/lib_paysages/color.h b/lib_paysages/color.h index efda8b9..2b87d3b 100644 --- a/lib_paysages/color.h +++ b/lib_paysages/color.h @@ -2,6 +2,7 @@ #define _PAYSAGES_COLOR_H_ #include "curve.h" +#include "pack.h" #ifdef __cplusplus extern "C" { @@ -41,6 +42,19 @@ void colorMask(Color* base, Color* mask); double colorNormalize(Color* col); double colorGetValue(Color* col); +/* HDR profile for tone-mapping */ +typedef struct ColorProfile ColorProfile; + +ColorProfile* colorProfileCreate(); +void colorProfileDelete(ColorProfile* profile); + +void colorProfileSave(PackStream* stream, ColorProfile* profile); +void colorProfileLoad(PackStream* stream, ColorProfile* profile); + +void colorProfileClear(ColorProfile* profile); +int colorProfileCollect(ColorProfile* profile, Color pixel); +Color colorProfileApply(ColorProfile* profile, Color pixel); + /* ColorGradation */ typedef struct ColorGradation ColorGradation; diff --git a/lib_paysages/render.c b/lib_paysages/render.c index b1d3414..29e36de 100644 --- a/lib_paysages/render.c +++ b/lib_paysages/render.c @@ -6,6 +6,7 @@ #include "shared/types.h" #include "color.h" +#include "renderer.h" #include "system.h" typedef struct @@ -95,7 +96,7 @@ void renderQuit() RenderArea* renderCreateArea() { RenderArea* result; - + result = malloc(sizeof(RenderArea)); result->params.width = 1; result->params.height = 1; @@ -118,7 +119,7 @@ RenderArea* renderCreateArea() result->callback_start = _callbackStart; result->callback_draw = _callbackDraw; result->callback_update = _callbackUpdate; - + return result; } @@ -134,7 +135,7 @@ void renderDeleteArea(RenderArea* area) void renderSetParams(RenderArea* area, RenderParams params) { int width, height; - + width = params.width * params.antialias; height = params.height * params.antialias; @@ -178,7 +179,7 @@ void renderClear(RenderArea* area) RenderFragment* pixel; int x; int y; - + area->fragment_callbacks_count = 1; area->fragment_callbacks[0].function = NULL; area->fragment_callbacks[0].data = NULL; @@ -237,7 +238,7 @@ static inline Color _getFinalPixel(RenderArea* area, int x, int y) Color result, col; int sx, sy; RenderFragment* pixel_data; - + result.r = result.g = result.b = 0.0; result.a = 1.0; for (sx = 0; sx < area->params.antialias; sx++) @@ -267,7 +268,7 @@ static inline Color _getFinalPixel(RenderArea* area, int x, int y) result.b += col.b / (double)(area->params.antialias * area->params.antialias); } } - + return result; } @@ -275,7 +276,7 @@ static void _processDirtyPixels(RenderArea* area) { int x, y; int down, up, left, right; - + down = area->dirty_down / area->params.antialias; up = area->dirty_up / area->params.antialias; left = area->dirty_left / area->params.antialias; @@ -323,7 +324,7 @@ static inline unsigned int _pushCallback(RenderArea* area, FragmentCallback call return i; } } - + if (area->fragment_callbacks_count >= 64) { return 0; @@ -339,7 +340,7 @@ static inline unsigned int _pushCallback(RenderArea* area, FragmentCallback call static void _pushFragment(RenderArea* area, int x, int y, double z, int edge, Vector3 location, int callback) { RenderFragment* pixel_data; - + if (x >= 0 && x < area->params.width * area->params.antialias && y >= 0 && y < area->params.height * area->params.antialias && z > 1.0) { pixel_data = area->pixels + (y * area->params.width * area->params.antialias + x); @@ -382,7 +383,7 @@ static void _pushScanPoint(RenderArea* area, ScanPoint* point) { point->x = (int)floor(point->pixel.x); point->y = (int)floor(point->pixel.y); - + if (point->x < 0 || point->x >= area->params.width * area->params.antialias) { return; @@ -466,7 +467,7 @@ static void _pushScanLineEdge(RenderArea* area, ScanPoint* point1, ScanPoint* po _scanInterpolate(point1, &diff, fx / dx, &point); /*point.pixel.x = (double)curx;*/ - + _pushScanPoint(area, &point); } } @@ -541,7 +542,7 @@ void renderPushTriangle(RenderArea* area, Vector3 pixel1, Vector3 pixel2, Vector { return; } - + point1.pixel = pixel1; point1.location = location1; point1.callback = _pushCallback(area, fragment_callback); @@ -553,13 +554,13 @@ void renderPushTriangle(RenderArea* area, Vector3 pixel1, Vector3 pixel2, Vector point3.pixel = pixel3; point3.location = location3; point3.callback = _pushCallback(area, fragment_callback); - + _clearScanLines(area); - + _pushScanLineEdge(area, &point1, &point2); _pushScanLineEdge(area, &point2, &point3); _pushScanLineEdge(area, &point3, &point1); - + mutexAcquire(area->lock); _renderScanLines(area); mutexRelease(area->lock); @@ -584,18 +585,18 @@ void* _renderPostProcessChunk(void* data) { FragmentCallback callback; Color col; - + callback = chunk->area->fragment_callbacks[fragment->flags.callback]; if (callback.function) { col = callback.function(chunk->renderer, fragment->data.location, callback.data); - colorNormalize(&col); + /*colorNormalize(&col);*/ } else { col = COLOR_BLACK; } - + fragment->data.color.r = col.r; fragment->data.color.g = col.g; fragment->data.color.b = col.b; diff --git a/lib_paysages/render.h b/lib_paysages/render.h index 82cdc8b..647e897 100644 --- a/lib_paysages/render.h +++ b/lib_paysages/render.h @@ -3,12 +3,25 @@ #include #include "shared/types.h" -#include "renderer.h" #ifdef __cplusplus extern "C" { #endif - + +typedef void (*RenderCallbackStart)(int width, int height, Color background); +typedef void (*RenderCallbackDraw)(int x, int y, Color col); +typedef void (*RenderCallbackUpdate)(double progress); + +typedef struct RenderArea RenderArea; + +typedef struct +{ + int width; + int height; + int antialias; + int quality; +} RenderParams; + void renderInit(); void renderQuit(); diff --git a/lib_paysages/renderer.h b/lib_paysages/renderer.h index 3a3b26e..0c60e89 100644 --- a/lib_paysages/renderer.h +++ b/lib_paysages/renderer.h @@ -4,6 +4,7 @@ #include "shared/types.h" #include "atmosphere/public.h" #include "terrain/public.h" +#include "render.h" #ifdef __cplusplus extern "C" { diff --git a/lib_paysages/shared/types.h b/lib_paysages/shared/types.h index 65bc42b..cea7668 100644 --- a/lib_paysages/shared/types.h +++ b/lib_paysages/shared/types.h @@ -15,14 +15,6 @@ typedef struct LightStatus LightStatus; typedef Color (*f_RenderFragmentCallback)(struct Renderer* renderer, Vector3 location, void* data); -typedef struct -{ - int width; - int height; - int antialias; - int quality; -} RenderParams; - typedef struct { int length; @@ -39,12 +31,6 @@ typedef struct double shininess; } SurfaceMaterial; -typedef void (*RenderCallbackStart)(int width, int height, Color background); -typedef void (*RenderCallbackDraw)(int x, int y, Color col); -typedef void (*RenderCallbackUpdate)(double progress); - -typedef struct RenderArea RenderArea; - typedef struct { int hit;