From 1fec110dffcb5740aa20bb826b92aa6a3824503d Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 24 Nov 2013 23:54:30 +0200 Subject: [PATCH] Render a sky in the upper hemisphere of a view's background I'll have to do something about the lower hemisphere as well, but this already makes train views look 46% better. --- data/sky.object | 32 +++++++++++++++++++++++++++ data/sky.shader | 54 ++++++++++++++++++++++++++++++++++++++++++++++ source/3d/sky.cpp | 20 +++++++++++++++++ source/3d/sky.h | 26 ++++++++++++++++++++++ source/3d/view.cpp | 8 +++++-- source/3d/view.h | 2 ++ 6 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 data/sky.object create mode 100644 data/sky.shader create mode 100644 source/3d/sky.cpp create mode 100644 source/3d/sky.h diff --git a/data/sky.object b/data/sky.object new file mode 100644 index 0000000..0e278f6 --- /dev/null +++ b/data/sky.object @@ -0,0 +1,32 @@ +mesh +{ + vertices VERTEX3 + { + vertex3 -1 -1 -1; + vertex3 1 -1 -1; + vertex3 -1 1 -1; + vertex3 1 1 -1; + vertex3 -1 -1 1; + vertex3 1 -1 1; + vertex3 -1 1 1; + vertex3 1 1 1; + }; + batch TRIANGLE_STRIP + { + indices 0 1 2 3 7 1 5 0 4 2 6 7 4 5; + }; +}; +technique +{ + pass "sky" + { + shader "sky.shader"; + uniforms + { + uniform3f "wavelengths" 0.56 0.53 0.42; + uniform1f "scatter_constant" 0.0079; + uniform1f "sun_intensity" 1.0; + uniform1f "sun_size" 0.005; + }; + }; +}; diff --git a/data/sky.shader b/data/sky.shader new file mode 100644 index 0000000..66dd8ec --- /dev/null +++ b/data/sky.shader @@ -0,0 +1,54 @@ +vertex_shader " + varying vec3 eye_look_dir; + void main() + { + vec4 eye_pos = vec4(mat3(gl_ModelViewMatrix)*gl_Vertex.xyz, 1); + gl_Position = gl_ProjectionMatrix*eye_pos; + eye_look_dir = eye_pos.xyz; + }"; + +fragment_shader " + uniform vec3 eye_sky_dir; + uniform vec3 wavelengths; + uniform float scatter_constant; + uniform float sun_intensity; + uniform float sun_size; + varying vec3 eye_look_dir; + float thickness(float c, float r) + { + float rc = r*c; + return sqrt(2.0*r+1.0+rc*rc)-rc; + } + float srgb(float c) + { + if(c<0.0031308) + return 12.92*c; + else + return (1.055)*pow(c, 1.0/2.4)-0.055; + } + void main() + { + vec3 n_eye_look_dir = normalize(eye_look_dir); + vec3 n_eye_sun_dir = normalize(gl_LightSource[0].position.xyz); + + if(dot(n_eye_look_dir, eye_sky_dir)>0) + { + float look_scale = thickness(dot(n_eye_look_dir, eye_sky_dir), 635.0); + float sun_scale = thickness(dot(n_eye_sun_dir, eye_sky_dir), 635.0); + float c = dot(n_eye_look_dir, n_eye_sun_dir); + float scatter_strength = (1.0+c*c)/2.0; + vec3 scatter_factor = scatter_constant/pow(wavelengths, vec3(4.0)); + + vec3 color; + float scale_ratio = look_scale/sun_scale; + if(scale_ratio>0.999 && scale_ratio<1.001) + color = sun_intensity*scatter_strength*scatter_factor*sun_scale*exp(-scatter_factor*sun_scale); + else + color = sun_intensity*scatter_strength*(exp(-scatter_factor*sun_scale)-exp(-scatter_factor*look_scale))/(1.0-sun_scale/look_scale); + if(dot(n_eye_look_dir, n_eye_sun_dir)>cos(sun_size)) + color += exp(-scatter_factor*look_scale)*sun_intensity; + gl_FragColor = vec4(srgb(color.r), srgb(color.g), srgb(color.b), 1.0); + } + else + gl_FragColor = vec4(vec3(0.0), 1.0); + }"; diff --git a/source/3d/sky.cpp b/source/3d/sky.cpp new file mode 100644 index 0000000..332b6d2 --- /dev/null +++ b/source/3d/sky.cpp @@ -0,0 +1,20 @@ +#include +#include "catalogue.h" +#include "sky.h" + +using namespace Msp; + +namespace R2C2 { + +Sky3D::Sky3D(Catalogue3D &cat): + GL::ObjectInstance(cat.get("sky.object")) +{ } + +void Sky3D::setup_render(GL::Renderer &renderer, const GL::Tag &) const +{ + GL::Vector4 sky_dir = renderer.matrix_stack().top()*GL::Vector4(0, 0 ,1, 0); + shdata.uniform("eye_sky_dir", sky_dir.x, sky_dir.y, sky_dir.z); + renderer.add_shader_data(shdata); +} + +} // namespace R2C2 diff --git a/source/3d/sky.h b/source/3d/sky.h new file mode 100644 index 0000000..88b170b --- /dev/null +++ b/source/3d/sky.h @@ -0,0 +1,26 @@ +#ifndef R2C2_3D_SKY_H_ +#define R2C2_3D_SKY_H_ + +#include +#include +#include + +namespace R2C2 { + +class Catalogue3D; + +class Sky3D: public Msp::GL::ObjectInstance +{ +private: + mutable Msp::GL::ProgramData shdata; + +public: + Sky3D(Catalogue3D &); + +private: + virtual void setup_render(Msp::GL::Renderer &, const Msp::GL::Tag &) const; +}; + +} // namespace R2C2 + +#endif diff --git a/source/3d/view.cpp b/source/3d/view.cpp index 673daef..b833605 100644 --- a/source/3d/view.cpp +++ b/source/3d/view.cpp @@ -13,13 +13,17 @@ View3D::View3D(Layout3D &l, unsigned w, unsigned h): layout(l), width(w), height(h), - pipeline(w, h) + pipeline(w, h), + sky(layout.get_catalogue()) { pipeline.set_camera(&camera); + pipeline.add_renderable(sky); pipeline.add_renderable_for_pass(layout.get_scene(), 0); pipeline.add_renderable_for_pass(layout.get_scene(), "translucent"); - GL::Pipeline::Pass *pass = &pipeline.add_pass(0); + GL::Pipeline::Pass *pass = &pipeline.add_pass("sky"); + + pass = &pipeline.add_pass(0); pass->set_lighting(&layout.get_lighting()); pass->set_depth_test(&GL::DepthTest::lequal()); diff --git a/source/3d/view.h b/source/3d/view.h index 5e954a7..3b0d625 100644 --- a/source/3d/view.h +++ b/source/3d/view.h @@ -3,6 +3,7 @@ #include #include +#include "sky.h" namespace R2C2 { @@ -16,6 +17,7 @@ protected: unsigned height; Msp::GL::Camera camera; Msp::GL::Pipeline pipeline; + Sky3D sky; public: View3D(Layout3D &, unsigned, unsigned); -- 2.43.0