OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
sky.cpp
Go to the documentation of this file.
1#include "sky.h"
2
3#include <Tempest/Application>
4#include <Tempest/CommandBuffer>
5#include <Tempest/Platform>
6#include <Tempest/Fence>
7
8#include <cctype>
9
10#include "utils/string_frm.h"
11#include "world/world.h"
12#include "gothic.h"
13#include "resources.h"
14
15using namespace Tempest;
16
17// https://www.slideshare.net/LukasLang/physically-based-lighting-in-unreal-engine-4
18// https://www.slideshare.net/DICEStudio/moving-frostbite-to-physically-based-rendering
19
20/* https://physicallybased.info
21 * The changing color of the Sun over the course of the day is mainly a result of the scattering of sunlight
22 * and is not due to changes in black-body radiation. The solar illuminance constant is equal to 128 000 lux,
23 * but atmospheric extinction brings the number of lux down to around 100 000 lux.
24 *
25 * clear sky = 6000 lx
26 * sky overcast = 2000 lx
27 *
28 * opaque = (100'000/pi)*NdotL = 31'800*NdotL
29 *
30 */
31static const float DirectSunLux = 128'000.f;
32static const float DirectMoonLux = 1.f;
33
34// static const float NightLight = 0.36f;
35// static const float ShadowSunLux = 10'000.f;
36// static const float StreetLight = 10.f;
37
38static float smoothstep(float edge0, float edge1, float x) {
39 float t = std::min(std::max((x - edge0) / (edge1 - edge0), 0.f), 1.f);
40 return t * t * (3.f - 2.f * t);
41 };
42
43static float linearstep(float edge0, float edge1, float x) {
44 float t = std::min(std::max((x - edge0) / (edge1 - edge0), 0.f), 1.f);
45 return t;
46 };
47
48Sky::Sky(const SceneGlobals& scene, const World& world)
49 :scene(scene) {
50 auto wname = world.name();
51 auto dot = wname.rfind('.');
52 auto name = dot==std::string::npos ? wname : wname.substr(0,dot);
53 for(size_t i=0; i<2; ++i) {
54 clouds[0].lay[i] = skyTexture(name,true, i);
55 clouds[1].lay[i] = skyTexture(name,false,i);
56 }
57
58 GSunIntensity = DirectSunLux;
59 GMoonIntensity = DirectMoonLux;
60
61 /*
62 zSunName=unsun5.tga
63 zSunSize=200
64 zSunAlpha=230
65 zMoonName=moon.tga
66 zMoonSize=400
67 zMoonAlpha=255
68 */
69 sunImg = Resources::loadTexture(Gothic::settingsGetS("SKY_OUTDOOR","zSunName"));
70 moonImg = Resources::loadTexture(Gothic::settingsGetS("SKY_OUTDOOR","zMoonName"));
71 if(sunImg==nullptr)
72 sunImg = &Resources::fallbackBlack();
73 if(moonImg==nullptr)
74 moonImg = &Resources::fallbackBlack();
75 }
76
78 }
79
80float Sky::isNight() const {
81 return 1.f - linearstep(-0.18f, 0.f, sun.dir().y);
82 }
83
84void Sky::updateLight(const int64_t now) {
85 // https://www.suncalc.org/#/52.4561,13.4033,5/2020.06.28/13:09/1/3
86 const int64_t rise = gtime( 4,45).toInt();
87 const int64_t meridian = gtime(13, 9).toInt();
88 const int64_t set = gtime(21,33).toInt();
89 const int64_t midnight = gtime(1,0,0).toInt();
90 const float shadowLength = 0.56f;
91
92 float pulse = 0.f;
93 if(rise<=now && now<meridian){
94 pulse = 0.f + float(now-rise)/float(meridian-rise);
95 }
96 else if(meridian<=now && now<set){
97 pulse = 1.f - float(now-meridian)/float(set-meridian);
98 }
99 else if(set<=now){
100 pulse = 0.f - float(now-set)/float(midnight-set);
101 }
102 else if(now<rise){
103 pulse = -1.f + (float(now)/float(rise));
104 }
105
113 //pulse = 0.5;
114
115 {
116 float k = float(now)/float(midnight);
117 float ax = 360-360*std::fmod(k+0.25f,1.f);
118 ax = ax*float(M_PI/180.0);
119 sun.setDir(-std::sin(ax)*shadowLength, pulse, std::cos(ax)*shadowLength);
120 //sun.setDir(0, 1, 0); //debug
121 }
122
123 static float sunMul = 1;
124 static float ambMul = 1;
125 // static auto groundAlbedo = Vec3(0.34f, 0.42f, 0.26f); // Foliage(MacBeth)
126 // static auto groundAlbedo = Vec3(0.39f, 0.40f, 0.33f);
127 static auto groundAlbedo = Vec3(0.3f); // aligned to sky-shading
128
129 // const float dirY = sun.dir().y;
130 // float dayTint = std::max(dirY+0.01f, 0.f);
131
132 // const float aDirect = linearstep(-0.0f, 0.8f, dirY);
133 const float sunOcclude = smoothstep(0.0f, 0.01f, sun.dir().y);
134
135 Vec3 direct;
136 direct = DirectSunLux * Vec3(1.0f);
137
138 ambient = DirectSunLux * float(1.0/M_PI) * groundAlbedo * sunOcclude;
139 ambient += DirectMoonLux * float(1.0/M_PI) * groundAlbedo;
140 // ambient *= 0.78f; // atmosphere transmission is in shader
141 ambient *= 0.68f; // NdoL prediction
142 ambient *= 0.5; // maybe in shadow or maybe not
143 ambient *= 2.0*float(M_PI); // 2*pi (hermisphere integral)
144 // ambient *= 0.8f; // tuneup
145 ambient *= float(1.0/M_PI); // predivide by lambertian lobe
146
147 //ambient += Vec3(0.001f); // should avoid zeros
148
149 sun.setColor(direct*sunMul);
150 ambient = ambient*ambMul;
151 }
152
153Vec2 Sky::cloudsOffset(int layer) const {
154 auto ticks = scene.tickCount;
155 auto t0 = float(ticks%90000 )/90000.f;
156 auto t1 = float(ticks%270000)/270000.f;
157
158 Vec2 ret = {};
159 if(layer==0)
160 ret.x = t0; else
161 ret.x = t1;
162 return ret;
163 }
164
165const Texture2d* Sky::skyTexture(std::string_view name, bool day, size_t id) {
166 if(auto t = implSkyTexture(name,day,id))
167 return t;
168 if(auto t = implSkyTexture("",day,id))
169 return t;
170 return &Resources::fallbackBlack();
171 }
172
173const Texture2d* Sky::implSkyTexture(std::string_view name, bool day, size_t id) {
174 string_frm tex("");
175 if(name.empty()) {
176 if(day)
177 tex = string_frm("SKYDAY_LAYER", int(id),"_A0.TGA"); else
178 tex = string_frm("SKYNIGHT_LAYER",int(id),"_A0.TGA");
179 } else {
180 if(day)
181 tex = string_frm("SKYDAY_", name,"_LAYER",int(id),"_A0.TGA"); else
182 tex = string_frm("SKYNIGHT_",name,"_LAYER",int(id),"_A0.TGA");
183 }
184 for(auto& i:tex)
185 i = char(std::toupper(i));
186
187 auto r = Resources::loadTexture(tex, true);
189 return &Resources::fallbackBlack(); //format error
190 return r;
191 }
static std::string_view settingsGetS(std::string_view sec, std::string_view name)
Definition gothic.cpp:824
void setDir(const Tempest::Vec3 &d)
Tempest::Vec3 dir() const
Definition lightsource.h:12
void setColor(const Tempest::Vec3 &cl)
static const Tempest::Texture2d & fallbackTexture()
static const Tempest::Texture2d * loadTexture(std::string_view name, bool forceMips=false)
static const Tempest::Texture2d & fallbackBlack()
uint64_t tickCount
Tempest::Vec2 cloudsOffset(int layer) const
Definition sky.cpp:153
Sky(const SceneGlobals &scene, const World &world)
Definition sky.cpp:48
~Sky()
Definition sky.cpp:77
void updateLight(const int64_t now)
Definition sky.cpp:84
float isNight() const
Definition sky.cpp:80
Definition world.h:31
std::string_view name() const
Definition world.h:42
int64_t toInt() const
Definition gametime.h:14
static float linearstep(float edge0, float edge1, float x)
Definition renderer.cpp:35
static float smoothstep(float edge0, float edge1, float x)
Definition renderer.cpp:30
static const float DirectMoonLux
Definition sky.cpp:32
static float linearstep(float edge0, float edge1, float x)
Definition sky.cpp:43
static float smoothstep(float edge0, float edge1, float x)
Definition sky.cpp:38
static const float DirectSunLux
Definition sky.cpp:31
const Tempest::Texture2d * lay[2]
Definition sky.h:15