/* -*-c++-*- */ /* osgEarth - Geospatial SDK for OpenSceneGraph * Copyright 2018 Pelican Mapping * http://osgearth.org * * osgEarth is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ #pragma once #include #include #include #include #include #include #include namespace { const char* render_wind = R"( #version 450 #pragma vp_function oe_ui_render_wind_vert, vertex_view out vec3 viewpos3_wind; void oe_ui_render_wind_vert(inout vec4 vertex) { viewpos3_wind = vertex.xyz; } [break] #version 450 #pragma vp_function oeui_render_wind_texture, fragment_output #pragma import_defines(OE_WIND_TEX) #pragma import_defines(OE_WIND_TEX_MATRIX) in vec3 viewpos3_wind; out vec4 frag_out; #ifdef OE_WIND_TEX uniform sampler3D OE_WIND_TEX; uniform mat4 OE_WIND_TEX_MATRIX; uniform vec3 oe_Camera; uniform float osg_FrameTime; #pragma import_defines(OE_TWEAKABLE) #ifdef OE_TWEAKABLE #define tweakable uniform #else #define tweakable const #endif tweakable float oe_wind_power = 1.0; #define MAX_WIND_SPEED 50.0 #endif void oeui_render_wind_texture(inout vec4 color) { frag_out = color; #ifdef OE_WIND_TEX vec4 texel = textureProj(OE_WIND_TEX, (OE_WIND_TEX_MATRIX*vec4(viewpos3_wind,1))); float speed = texel.a * oe_wind_power; vec3 wind_view = 2.0*texel.xyz - 1.0; vec3 wind_clip = mat3(gl_ProjectionMatrix) * wind_view; vec2 wind_screen = wind_clip.xy * oe_Camera.xy; vec2 coord = (gl_FragCoord.xy - 0.5); vec2 rv = normalize(wind_screen); vec2 coordProj = mat2(rv.x, -rv.y, rv.y, rv.x) * coord; const float oe_wind_animation_speed = 2.8 * MAX_WIND_SPEED * speed; // 32.0 int cx = int(coordProj.x - int(osg_FrameTime*oe_wind_animation_speed)); int ci = cx % 32; const int stipple = 0x00000001; int pattern32 = 0xffffffff & (stipple & (1 << ci)); if (pattern32 != 0) frag_out = vec4(0.5,0.5,1,0.5); #endif } )"; } namespace osgEarth { using namespace osgEarth::Util; class EnvironmentGUI : public ImGuiPanel { private: osg::observer_ptr _mapNode; osg::observer_ptr _skyNode; osg::observer_ptr _shadowCaster; osg::observer_ptr _windLayer; bool _showDetails = false; float _hour; int _day, _month, _year; float _exposure = 3.5f; float _contrast = 1.0f; float _ambient = 0.033f; float _max_ambient_intensity = 0.75; bool _first = true; bool _shadows = false; float _haze_cutoff = 0.0f, _haze_strength = 16.0f; float _shadow_darkness = 0.5f, _shadow_blur = 0.001f; float _wind_power = 1.0f; public: EnvironmentGUI() : ImGuiPanel("Environment/Sky") { DateTime now; _hour = now.hours(), _day = now.day(), _month = now.month(), _year = now.year(); } void load(const Config& conf) override { conf.get("ShowDetails", _showDetails); //conf.get("Hour", _hour); //conf.get("Day", _day); //conf.get("Month", _month); //conf.get("Year", _year); conf.get("Exposure", _exposure); conf.get("Contrast", _contrast); conf.get("Ambient", _ambient); conf.get("HazeCutoff", _haze_cutoff); conf.get("HazeStrength", _haze_strength); conf.get("WindPower", _wind_power); } void save(Config& conf) override { conf.set("ShowDetails", _showDetails); //conf.set("Hour", _hour); //conf.set("Day", _day); //conf.set("Month", _month); //conf.set("Year", _year); conf.set("Exposure", _exposure); conf.set("Contrast", _contrast); conf.set("Ambient", _ambient); conf.set("HazeCutoff", _haze_cutoff); conf.set("HazeStrength", _haze_strength); conf.set("WindPower", _wind_power); } void draw(osg::RenderInfo& ri) override { if (!isVisible() || !findNodeOrHide(_mapNode, ri)) return; if (ImGui::Begin(name(), visible())) { if (!findNode(_skyNode, ri)) { ImGui::Text("No Sky installed."); if (ImGui::Button("Install")) { auto sky = SkyNode::create(); auto parent = _mapNode->getParent(0); sky->addChild(_mapNode.get()); parent->addChild(sky); parent->removeChild(_mapNode.get()); sky->attach(view(ri)); } ImGui::End(); return; } if (_first) { findNode(_shadowCaster, ri); if (_shadowCaster.valid()) _shadows = _shadowCaster->getEnabled(); findLayer(_windLayer, ri); _skyNode->setDateTime(DateTime(_year, _month, _day, _hour)); // so we can visualize tiume-series layers. _skyNode->setSimulationTimeTracksDateTime(true); } bool lighting = _skyNode->getLighting(); ImGui::Checkbox("Lighting", &lighting); _skyNode->setLighting(lighting); if (_shadowCaster.valid()) { ImGui::SameLine(); ImGui::Checkbox("Shadows", &_shadows); _shadowCaster->setEnabled(_shadows); } ImGui::SameLine(); if (ImGui::Checkbox("Details", &_showDetails)) dirtySettings(); ImGui::SameLine(); if (ImGui::Button("Now")) { _skyNode->setDateTime(DateTime()); dirtySettings(); } ImGui::Separator(); if (ImGuiLTable::Begin("Environment")) { ImGuiLTable::Section("Date & Time:"); auto mark = _skyNode->getDateTime(); auto day = mark.day(); auto month = mark.month(); auto year = mark.year(); auto hour = mark.hours(); if (ImGuiLTable::SliderDouble("Hour (UTC)", &hour, 0.0f, 24.0f)) _hour = hour, dirtySettings(); if (_showDetails) { if (ImGuiLTable::SliderInt("Day", &day, 1, 31)) _day = day, dirtySettings(); if (ImGuiLTable::SliderInt("Month", &month, 1, 12)) _month = month, dirtySettings(); if (ImGuiLTable::SliderInt("Year", &year, 1970, 2061)) _year = year, dirtySettings(); } _skyNode->setDateTime(DateTime(year, month, day, hour)); if (lighting) { if (ImGuiLTable::SliderFloat("Exposure", &_exposure, 1.0f, 10.0f)) dirtySettings(); _skyNode->getOrCreateStateSet()->getOrCreateUniform("oe_sky_exposure", osg::Uniform::FLOAT)->set(_exposure); if (ImGuiLTable::SliderFloat("Ambient min", &_ambient, 0.0f, 1.0f)) dirtySettings(); _skyNode->getSunLight()->setAmbient(osg::Vec4(_ambient, _ambient, _ambient, 1.0f)); if (ImGuiLTable::SliderFloat("Ambient max", &_max_ambient_intensity, 0.0f, 1.0f)) dirtySettings(); _skyNode->getOrCreateStateSet()->getOrCreateUniform("oe_sky_maxAmbientIntensity", osg::Uniform::FLOAT)->set(_max_ambient_intensity); auto diffuse_color = _skyNode->getSunLight()->getDiffuse(); if (ImGuiLTable::ColorEdit3("Diffuse color", &diffuse_color[0], ImGuiColorEditFlags_Float)) { _skyNode->getSunLight()->setDiffuse(diffuse_color); dirtySettings(); } static float normal_boost = 1.0f; if (ImGuiLTable::SliderFloat("Normal boost", &normal_boost, 1.0f, 5.0f)) { _skyNode->getOrCreateStateSet()->getOrCreateUniform("oe_normal_boost", osg::Uniform::FLOAT)->set(normal_boost); dirtySettings(); } } else { _shadows = false; } if (_windLayer.valid()) { ImGui::Separator(); ImGuiLTable::Section("Wind"); if (ImGuiLTable::SliderFloat("Speed mult", &_wind_power, 0.0f, 9.0f, "%.1f", 0) || _first) { stateset(ri)->addUniform(new osg::Uniform("oe_wind_power", _wind_power), osg::StateAttribute::OVERRIDE | 0x01); dirtySettings(); } static bool show_wind = false; if (ImGuiLTable::Checkbox("Debug view", &show_wind)) { if (show_wind) ShaderLoader::load(VirtualProgram::getOrCreate(stateset(ri)), render_wind); else ShaderLoader::unload(VirtualProgram::getOrCreate(stateset(ri)), render_wind); } } if (_showDetails) { ImGui::Separator(); ImGuiLTable::Section("Details"); if (_shadows) { if (ImGuiLTable::SliderFloat("Shadow darkness", &_shadow_darkness, 0.0f, 1.0f)) stateset(ri)->addUniform(new osg::Uniform("oe_shadow_color", _shadow_darkness), 0x7); if (ImGuiLTable::SliderFloat("Shadow blur", &_shadow_blur, 0.0f, 0.002f)) stateset(ri)->addUniform(new osg::Uniform("oe_shadow_blur", _shadow_blur), 0x07); } if (ImGuiLTable::SliderFloat("Haze cutoff", &_haze_cutoff, 0.0f, 0.2f)) dirtySettings(); _skyNode->getOrCreateStateSet()->getOrCreateUniform("atmos_haze_cutoff", osg::Uniform::FLOAT)->set(_haze_cutoff); if (ImGuiLTable::SliderFloat("Haze strength", &_haze_strength, 0.0f, 24.0f)) dirtySettings(); _skyNode->getOrCreateStateSet()->getOrCreateUniform("atmos_haze_strength", osg::Uniform::FLOAT)->set(_haze_strength); bool atmos_visible = _skyNode->getAtmosphereVisible(); ImGuiLTable::Checkbox("Atmosphere", &atmos_visible); _skyNode->setAtmosphereVisible(atmos_visible); bool sun_visible = _skyNode->getSunVisible(); ImGuiLTable::Checkbox("Sun", &sun_visible); _skyNode->setSunVisible(sun_visible); bool moon_visible = _skyNode->getMoonVisible(); ImGuiLTable::Checkbox("Moon", &moon_visible); _skyNode->setMoonVisible(moon_visible); bool stars_visible = _skyNode->getStarsVisible(); ImGuiLTable::Checkbox("Stars", &stars_visible); _skyNode->setStarsVisible(stars_visible); ImGui::Separator(); DateTime dt = _skyNode->getDateTime(); CelestialBody sun = _skyNode->getEphemeris()->getSunPosition(dt); ImGuiLTable::Text("Sun:", "RA (%.2f) Decl (%.2f)", sun.rightAscension.as(Units::DEGREES), sun.declination.as(Units::DEGREES)); CelestialBody moon = _skyNode->getEphemeris()->getMoonPosition(dt); ImGuiLTable::Text("Moon:", "RA (%.2f) Decl (%.2f)", moon.rightAscension.as(Units::DEGREES), moon.declination.as(Units::DEGREES)); } ImGuiLTable::End(); } _first = false; } ImGui::End(); } }; }