Compare commits
1 commit
master
...
2025-09-18
| Author | SHA1 | Date | |
|---|---|---|---|
| 7038343b19 |
9 changed files with 373 additions and 29 deletions
|
|
@ -1,34 +1,157 @@
|
||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
||||||
in vec3 v_normal;
|
in vec3 v_world_normal;
|
||||||
in vec2 v_tex;
|
in vec2 v_tex;
|
||||||
in vec3 v_position;
|
in vec3 v_world_pos;
|
||||||
|
|
||||||
out vec4 frag_color;
|
out vec4 frag_color;
|
||||||
|
|
||||||
uniform vec3 u_light;
|
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
uniform vec3 color; // base colour factor (acts as solid colour when no texture)
|
uniform vec3 color; // base colour factor
|
||||||
|
uniform vec3 camera_pos; // camera world position
|
||||||
|
uniform vec3 light_dir; // directional light direction (from light towards scene)
|
||||||
|
uniform vec3 light_color; // directional light color
|
||||||
|
|
||||||
|
// -------------------------------------
|
||||||
|
// Constants and helpers (ported from atmosphere.cginc)
|
||||||
|
const float PI = 3.14159265359;
|
||||||
|
const float PLANET_RADIUS = 6371000.0;
|
||||||
|
const float ATMOSPHERE_HEIGHT = 100000.0;
|
||||||
|
const float RAYLEIGH_HEIGHT = (ATMOSPHERE_HEIGHT * 0.08);
|
||||||
|
const float MIE_HEIGHT = (ATMOSPHERE_HEIGHT * 0.012);
|
||||||
|
const float EXPOSURE = 20.0;
|
||||||
|
|
||||||
|
// Coefficients (1e-6 scaling kept)
|
||||||
|
const vec3 C_RAYLEIGH = vec3(5.802, 13.558, 33.100) * 1e-6;
|
||||||
|
const vec3 C_MIE = vec3(3.996, 3.996, 3.996) * 1e-6;
|
||||||
|
const vec3 C_OZONE = vec3(0.650, 1.881, 0.085) * 1e-6;
|
||||||
|
|
||||||
|
float saturate(float x) { return clamp(x, 0.0, 1.0); }
|
||||||
|
vec2 saturate(vec2 x) { return clamp(x, vec2(0.0), vec2(1.0)); }
|
||||||
|
vec3 saturate(vec3 x) { return clamp(x, vec3(0.0), vec3(1.0)); }
|
||||||
|
|
||||||
|
float AtmosphereHeight(vec3 positionWS) {
|
||||||
|
return length(positionWS - vec3(0.0, -PLANET_RADIUS, 0.0)) - PLANET_RADIUS;
|
||||||
|
}
|
||||||
|
float DensityRayleigh(float h) { return exp(-max(0.0, h / RAYLEIGH_HEIGHT)); }
|
||||||
|
float DensityMie (float h) { return exp(-max(0.0, h / MIE_HEIGHT)); }
|
||||||
|
float DensityOzone (float h) { return max(0.0, 1.0 - abs(h - 25000.0) / 15000.0); }
|
||||||
|
vec3 AtmosphereDensity(float h) { return vec3(DensityRayleigh(h), DensityMie(h), DensityOzone(h)); }
|
||||||
|
|
||||||
|
// Sphere intersection with atmosphere shell
|
||||||
|
vec2 SphereIntersection(vec3 rayStart, vec3 rayDir, vec3 sphereCenter, float sphereRadius) {
|
||||||
|
vec3 o = rayStart - sphereCenter;
|
||||||
|
float a = dot(rayDir, rayDir);
|
||||||
|
float b = 2.0 * dot(o, rayDir);
|
||||||
|
float c = dot(o, o) - (sphereRadius * sphereRadius);
|
||||||
|
float d = b*b - 4.0*a*c;
|
||||||
|
if (d < 0.0) return vec2(-1.0);
|
||||||
|
d = sqrt(d);
|
||||||
|
return vec2(-b - d, -b + d) / (2.0 * a);
|
||||||
|
}
|
||||||
|
vec2 AtmosphereIntersection(vec3 rayStart, vec3 rayDir) {
|
||||||
|
return SphereIntersection(rayStart, rayDir, vec3(0.0, -PLANET_RADIUS, 0.0), PLANET_RADIUS + ATMOSPHERE_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
float PhaseRayleigh(float costh) {
|
||||||
|
return 3.0 * (1.0 + costh*costh) / (16.0 * PI);
|
||||||
|
}
|
||||||
|
float PhaseMie(float costh, float g) {
|
||||||
|
g = min(g, 0.9381);
|
||||||
|
float k = 1.55*g - 0.55*g*g*g;
|
||||||
|
float kcosth = k*costh;
|
||||||
|
return (1.0 - k*k) / ((4.0*PI) * (1.0 - kcosth) * (1.0 - kcosth));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 IntegrateOpticalDepth(vec3 rayStart, vec3 rayDir) {
|
||||||
|
vec2 intersection = AtmosphereIntersection(rayStart, rayDir);
|
||||||
|
float rayLength = intersection.y;
|
||||||
|
int sampleCount = 8;
|
||||||
|
float stepSize = rayLength / float(sampleCount);
|
||||||
|
vec3 opticalDepth = vec3(0.0);
|
||||||
|
for (int i = 0; i < sampleCount; ++i) {
|
||||||
|
vec3 localPosition = rayStart + rayDir * (float(i) + 0.5) * stepSize;
|
||||||
|
float localHeight = AtmosphereHeight(localPosition);
|
||||||
|
vec3 localDensity = AtmosphereDensity(localHeight);
|
||||||
|
opticalDepth += localDensity * stepSize;
|
||||||
|
}
|
||||||
|
return opticalDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 Absorb(vec3 opticalDepth) {
|
||||||
|
// Mie absorbs slightly more than it scatters (~10%)
|
||||||
|
return exp(-(opticalDepth.x * C_RAYLEIGH + opticalDepth.y * C_MIE * 1.1 + opticalDepth.z * C_OZONE));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 IntegrateScattering(vec3 rayStart, vec3 rayDir, float rayLength, vec3 lightDir, vec3 lightColor, out vec3 transmittance) {
|
||||||
|
float rayHeight = AtmosphereHeight(rayStart);
|
||||||
|
float sampleDistributionExponent = 1.0 + saturate(1.0 - rayHeight / ATMOSPHERE_HEIGHT) * 8.0;
|
||||||
|
|
||||||
|
vec2 intersection = AtmosphereIntersection(rayStart, rayDir);
|
||||||
|
rayLength = min(rayLength, intersection.y);
|
||||||
|
if (intersection.x > 0.0) {
|
||||||
|
rayStart += rayDir * intersection.x;
|
||||||
|
rayLength -= intersection.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
float costh = dot(rayDir, lightDir);
|
||||||
|
float phaseR = PhaseRayleigh(costh);
|
||||||
|
float phaseM = PhaseMie(costh, 0.85);
|
||||||
|
|
||||||
|
int sampleCount = 64;
|
||||||
|
|
||||||
|
vec3 opticalDepth = vec3(0.0);
|
||||||
|
vec3 rayleigh = vec3(0.0);
|
||||||
|
vec3 mie = vec3(0.0);
|
||||||
|
float prevRayTime = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < sampleCount; ++i) {
|
||||||
|
float t = pow(float(i) / float(sampleCount), sampleDistributionExponent) * rayLength;
|
||||||
|
float stepSize = (t - prevRayTime);
|
||||||
|
vec3 localPosition = rayStart + rayDir * t;
|
||||||
|
float localHeight = AtmosphereHeight(localPosition);
|
||||||
|
vec3 localDensity = AtmosphereDensity(localHeight);
|
||||||
|
opticalDepth += localDensity * stepSize;
|
||||||
|
|
||||||
|
vec3 viewTransmittance = Absorb(opticalDepth);
|
||||||
|
vec3 opticalDepthLight = IntegrateOpticalDepth(localPosition, lightDir);
|
||||||
|
vec3 lightTransmittance = Absorb(opticalDepthLight);
|
||||||
|
|
||||||
|
rayleigh += viewTransmittance * lightTransmittance * phaseR * localDensity.x * stepSize;
|
||||||
|
mie += viewTransmittance * lightTransmittance * phaseM * localDensity.y * stepSize;
|
||||||
|
prevRayTime = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
transmittance = Absorb(opticalDepth);
|
||||||
|
return (rayleigh * C_RAYLEIGH + mie * C_MIE) * lightColor * EXPOSURE;
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// Combine base texture (or constant white) with colour factor supplied by CPU.
|
// Base albedo
|
||||||
vec3 base_col = texture(tex, v_tex).rgb * color;
|
vec3 base_col = texture(tex, v_tex).rgb * color;
|
||||||
|
|
||||||
vec3 ambient_color = base_col * 0.2;
|
// Lighting setup
|
||||||
vec3 diffuse_color = base_col * 0.6;
|
vec3 L = normalize(light_dir);
|
||||||
vec3 specular_color = vec3(1.0);
|
vec3 N = normalize(v_world_normal);
|
||||||
|
|
||||||
// u_light is the direction **from the light towards the fragment**.
|
// Directional light transmittance (planet shadow)
|
||||||
float diffuse = max(dot(normalize(v_normal), normalize(u_light)), 0.0);
|
vec3 lightTransmittance = Absorb(IntegrateOpticalDepth(v_world_pos, L));
|
||||||
|
|
||||||
vec3 camera_dir = normalize(-v_position);
|
// Rough ambient by sampling sky upwards
|
||||||
vec3 half_dir = normalize(normalize(u_light) + camera_dir);
|
vec3 tmp;
|
||||||
float specular = pow(max(dot(half_dir, normalize(v_normal)), 0.0), 16.0);
|
vec3 ambient = IntegrateScattering(v_world_pos, vec3(0.0, 1.0, 0.0), 1.0/0.0, L, light_color, tmp);
|
||||||
|
|
||||||
vec3 result = ambient_color + diffuse * diffuse_color + specular * specular_color;
|
// Lambert + atmospheric directional lighting
|
||||||
|
float NdotL = max(0.0, dot(N, L));
|
||||||
|
vec3 lit = base_col * NdotL * (ambient + light_color * lightTransmittance);
|
||||||
|
|
||||||
// Convert from linear to sRGB for display (approximate γ-correction)
|
// View-ray scattering and transmittance between surface and camera
|
||||||
result = pow(result, vec3(1.0 / 2.2));
|
vec3 V = camera_pos - v_world_pos;
|
||||||
|
float rayLength = length(V);
|
||||||
|
V = V / max(rayLength, 1e-6);
|
||||||
|
vec3 transmittance;
|
||||||
|
vec3 scattering = IntegrateScattering(camera_pos, -V, rayLength, L, light_color, transmittance);
|
||||||
|
|
||||||
|
vec3 result = lit * transmittance + scattering;
|
||||||
frag_color = vec4(result, 1.0);
|
frag_color = vec4(result, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@ uniform mat4 projection;
|
||||||
uniform vec2 uv_offset;
|
uniform vec2 uv_offset;
|
||||||
uniform vec2 uv_scale;
|
uniform vec2 uv_scale;
|
||||||
|
|
||||||
out vec3 v_normal;
|
out vec3 v_world_normal;
|
||||||
out vec2 v_tex;
|
out vec2 v_tex;
|
||||||
out vec3 v_position;
|
out vec3 v_world_pos;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
mat4 modelview = view * model;
|
mat3 model3 = mat3(model);
|
||||||
v_normal = transpose(inverse(mat3(modelview))) * normal;
|
v_world_normal = normalize(transpose(inverse(model3)) * normal);
|
||||||
v_tex = tex_coords * uv_scale + uv_offset;
|
v_tex = tex_coords * uv_scale + uv_offset;
|
||||||
v_position = (modelview * vec4(position, 1.0)).xyz;
|
v_world_pos = (model * vec4(position, 1.0)).xyz;
|
||||||
gl_Position = projection * modelview * vec4(position, 1.0);
|
gl_Position = projection * view * vec4(v_world_pos, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
136
assets/shaders/sky_atmosphere.frag
Normal file
136
assets/shaders/sky_atmosphere.frag
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
in vec2 v_uv;
|
||||||
|
out vec4 frag_color;
|
||||||
|
|
||||||
|
uniform mat4 inv_view;
|
||||||
|
uniform mat4 inv_projection;
|
||||||
|
uniform vec3 camera_pos;
|
||||||
|
uniform vec3 light_dir;
|
||||||
|
uniform vec3 light_color;
|
||||||
|
uniform float draw_planet;
|
||||||
|
|
||||||
|
const float PI = 3.14159265359;
|
||||||
|
const float PLANET_RADIUS = 6371000.0;
|
||||||
|
const float ATMOSPHERE_HEIGHT = 100000.0;
|
||||||
|
const float RAYLEIGH_HEIGHT = (ATMOSPHERE_HEIGHT * 0.08);
|
||||||
|
const float MIE_HEIGHT = (ATMOSPHERE_HEIGHT * 0.012);
|
||||||
|
const float EXPOSURE = 20.0;
|
||||||
|
const vec3 C_RAYLEIGH = vec3(5.802, 13.558, 33.100) * 1e-6;
|
||||||
|
const vec3 C_MIE = vec3(3.996, 3.996, 3.996) * 1e-6;
|
||||||
|
const vec3 C_OZONE = vec3(0.650, 1.881, 0.085) * 1e-6;
|
||||||
|
|
||||||
|
float AtmosphereHeight(vec3 positionWS) {
|
||||||
|
return length(positionWS - vec3(0.0, -PLANET_RADIUS, 0.0)) - PLANET_RADIUS;
|
||||||
|
}
|
||||||
|
float DensityRayleigh(float h) { return exp(-max(0.0, h / RAYLEIGH_HEIGHT)); }
|
||||||
|
float DensityMie (float h) { return exp(-max(0.0, h / MIE_HEIGHT)); }
|
||||||
|
float DensityOzone (float h) { return max(0.0, 1.0 - abs(h - 25000.0) / 15000.0); }
|
||||||
|
vec3 AtmosphereDensity(float h) { return vec3(DensityRayleigh(h), DensityMie(h), DensityOzone(h)); }
|
||||||
|
|
||||||
|
vec2 SphereIntersection(vec3 rayStart, vec3 rayDir, vec3 sphereCenter, float sphereRadius) {
|
||||||
|
vec3 o = rayStart - sphereCenter;
|
||||||
|
float a = dot(rayDir, rayDir);
|
||||||
|
float b = 2.0 * dot(o, rayDir);
|
||||||
|
float c = dot(o, o) - (sphereRadius * sphereRadius);
|
||||||
|
float d = b*b - 4.0*a*c;
|
||||||
|
if (d < 0.0) return vec2(-1.0);
|
||||||
|
d = sqrt(d);
|
||||||
|
return vec2(-b - d, -b + d) / (2.0 * a);
|
||||||
|
}
|
||||||
|
vec2 PlanetIntersection(vec3 rayStart, vec3 rayDir) {
|
||||||
|
return SphereIntersection(rayStart, rayDir, vec3(0.0, -PLANET_RADIUS, 0.0), PLANET_RADIUS);
|
||||||
|
}
|
||||||
|
vec2 AtmosphereIntersection(vec3 rayStart, vec3 rayDir) {
|
||||||
|
return SphereIntersection(rayStart, rayDir, vec3(0.0, -PLANET_RADIUS, 0.0), PLANET_RADIUS + ATMOSPHERE_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
float PhaseRayleigh(float costh) {
|
||||||
|
return 3.0 * (1.0 + costh*costh) / (16.0 * PI);
|
||||||
|
}
|
||||||
|
float PhaseMie(float costh, float g) {
|
||||||
|
g = min(g, 0.9381);
|
||||||
|
float k = 1.55*g - 0.55*g*g*g;
|
||||||
|
float kcosth = k*costh;
|
||||||
|
return (1.0 - k*k) / ((4.0*PI) * (1.0 - kcosth) * (1.0 - kcosth));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 IntegrateOpticalDepth(vec3 rayStart, vec3 rayDir) {
|
||||||
|
vec2 intersection = AtmosphereIntersection(rayStart, rayDir);
|
||||||
|
float rayLength = intersection.y;
|
||||||
|
int sampleCount = 8;
|
||||||
|
float stepSize = rayLength / float(sampleCount);
|
||||||
|
vec3 opticalDepth = vec3(0.0);
|
||||||
|
for (int i = 0; i < sampleCount; ++i) {
|
||||||
|
vec3 localPosition = rayStart + rayDir * (float(i) + 0.5) * stepSize;
|
||||||
|
float localHeight = AtmosphereHeight(localPosition);
|
||||||
|
vec3 localDensity = AtmosphereDensity(localHeight);
|
||||||
|
opticalDepth += localDensity * stepSize;
|
||||||
|
}
|
||||||
|
return opticalDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 Absorb(vec3 opticalDepth) {
|
||||||
|
return exp(-(opticalDepth.x * C_RAYLEIGH + opticalDepth.y * C_MIE * 1.1 + opticalDepth.z * C_OZONE));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 IntegrateScattering(vec3 rayStart, vec3 rayDir, float rayLength, vec3 lightDir, vec3 lightColor, out vec3 transmittance) {
|
||||||
|
float rayHeight = AtmosphereHeight(rayStart);
|
||||||
|
float sampleDistributionExponent = 1.0 + clamp(1.0 - rayHeight / ATMOSPHERE_HEIGHT, 0.0, 1.0) * 8.0;
|
||||||
|
|
||||||
|
vec2 intersection = AtmosphereIntersection(rayStart, rayDir);
|
||||||
|
rayLength = min(rayLength, intersection.y);
|
||||||
|
if (intersection.x > 0.0) {
|
||||||
|
rayStart += rayDir * intersection.x;
|
||||||
|
rayLength -= intersection.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
float costh = dot(rayDir, lightDir);
|
||||||
|
float phaseR = PhaseRayleigh(costh);
|
||||||
|
float phaseM = PhaseMie(costh, 0.85);
|
||||||
|
|
||||||
|
int sampleCount = 64;
|
||||||
|
vec3 opticalDepth = vec3(0.0);
|
||||||
|
vec3 rayleigh = vec3(0.0);
|
||||||
|
vec3 mie = vec3(0.0);
|
||||||
|
float prevRayTime = 0.0;
|
||||||
|
for (int i = 0; i < sampleCount; ++i) {
|
||||||
|
float t = pow(float(i) / float(sampleCount), sampleDistributionExponent) * rayLength;
|
||||||
|
float stepSize = (t - prevRayTime);
|
||||||
|
vec3 localPosition = rayStart + rayDir * t;
|
||||||
|
float localHeight = AtmosphereHeight(localPosition);
|
||||||
|
vec3 localDensity = AtmosphereDensity(localHeight);
|
||||||
|
opticalDepth += localDensity * stepSize;
|
||||||
|
vec3 viewTransmittance = Absorb(opticalDepth);
|
||||||
|
vec3 opticalDepthLight = IntegrateOpticalDepth(localPosition, lightDir);
|
||||||
|
vec3 lightTransmittance = Absorb(opticalDepthLight);
|
||||||
|
rayleigh += viewTransmittance * lightTransmittance * phaseR * localDensity.x * stepSize;
|
||||||
|
mie += viewTransmittance * lightTransmittance * phaseM * localDensity.y * stepSize;
|
||||||
|
prevRayTime = t;
|
||||||
|
}
|
||||||
|
transmittance = Absorb(opticalDepth);
|
||||||
|
return (rayleigh * C_RAYLEIGH + mie * C_MIE) * lightColor * EXPOSURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// Reconstruct view ray from NDC
|
||||||
|
vec2 ndc = v_uv * 2.0 - 1.0;
|
||||||
|
vec4 clip = vec4(ndc, 1.0, 1.0);
|
||||||
|
vec4 view = inv_projection * clip;
|
||||||
|
view = vec4(view.xy, -1.0, 0.0);
|
||||||
|
vec3 worldDir = normalize((inv_view * view).xyz);
|
||||||
|
|
||||||
|
float rayLength = 1.0/0.0; // infinity
|
||||||
|
if (draw_planet == 1.0) {
|
||||||
|
vec2 isect = PlanetIntersection(camera_pos, worldDir);
|
||||||
|
if (isect.x > 0.0) {
|
||||||
|
rayLength = min(rayLength, isect.x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 transmittance;
|
||||||
|
vec3 color = IntegrateScattering(camera_pos, worldDir, rayLength, normalize(light_dir), light_color, transmittance);
|
||||||
|
frag_color = vec4(color, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
13
assets/shaders/sky_atmosphere.vert
Normal file
13
assets/shaders/sky_atmosphere.vert
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
// Fullscreen triangle (no vbo)
|
||||||
|
out vec2 v_uv;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// gl_VertexID in {0,1,2}
|
||||||
|
vec2 pos = vec2((gl_VertexID << 1) & 2, gl_VertexID & 2);
|
||||||
|
v_uv = pos;
|
||||||
|
gl_Position = vec4(pos * 2.0 - 1.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use winit::event::Event;
|
use winit::{event::Event, window::Window};
|
||||||
use raidillon_assets::{ModelManagerRef, ModelManager};
|
use raidillon_assets::{ModelManagerRef, ModelManager};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -10,4 +10,5 @@ pub struct PlatformContext {
|
||||||
pub asset_manager: ModelManagerRef,
|
pub asset_manager: ModelManagerRef,
|
||||||
pub frame_width: f32,
|
pub frame_width: f32,
|
||||||
pub frame_height: f32,
|
pub frame_height: f32,
|
||||||
|
// pub window: &'a Window,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use winit::event::{Event, WindowEvent};
|
||||||
use raidillon_assets::ModelManagerRef;
|
use raidillon_assets::ModelManagerRef;
|
||||||
use raidillon_core::engine::EngineTrait;
|
use raidillon_core::engine::EngineTrait;
|
||||||
use crate::render::debug_ui::ImguiBridge;
|
use crate::render::debug_ui::ImguiBridge;
|
||||||
use crate::render::BasicMeshRenderingSystem;
|
use crate::render::{BasicMeshRenderingSystem, SkyAtmosphereRenderingSystem};
|
||||||
use crate::GliumAssetManager;
|
use crate::GliumAssetManager;
|
||||||
|
|
||||||
pub struct GliumPlatform<E: EngineTrait> {
|
pub struct GliumPlatform<E: EngineTrait> {
|
||||||
|
|
@ -39,6 +39,8 @@ impl<E: EngineTrait> Platform<E> for GliumPlatform<E> {
|
||||||
let mut rendering_system_manager = RenderingSystemManager::new();
|
let mut rendering_system_manager = RenderingSystemManager::new();
|
||||||
|
|
||||||
// Install rendering systems
|
// Install rendering systems
|
||||||
|
// Draw sky first, then meshes, then debug UI
|
||||||
|
rendering_system_manager.add::<SkyAtmosphereRenderingSystem>(&display, &window);
|
||||||
rendering_system_manager.add::<BasicMeshRenderingSystem>(&display, &window);
|
rendering_system_manager.add::<BasicMeshRenderingSystem>(&display, &window);
|
||||||
rendering_system_manager.add::<ImguiBridge>(&display, &window);
|
rendering_system_manager.add::<ImguiBridge>(&display, &window);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,9 @@ impl RenderingSystem for BasicMeshRenderingSystem {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Direction from the light source (0,+Y) towards the scene.
|
// Match sky light direction: from light towards the scene (upwards +Y)
|
||||||
let light_dir: Vec3 = Vec3::new(0.0, -1.0, 0.0).normalize();
|
let light_dir: Vec3 = Vec3::new(0.0, 1.0, 0.0).normalize();
|
||||||
|
let light_color: [f32; 3] = [1.0, 1.0, 1.0];
|
||||||
|
|
||||||
// let asset_manager = ctx.asset_manager.borrow();
|
// let asset_manager = ctx.asset_manager.borrow();
|
||||||
// let any_ref: &dyn Any = &**asset_manager;
|
// let any_ref: &dyn Any = &**asset_manager;
|
||||||
|
|
@ -93,7 +94,9 @@ impl RenderingSystem for BasicMeshRenderingSystem {
|
||||||
model: tr.matrix().to_cols_array_2d(),
|
model: tr.matrix().to_cols_array_2d(),
|
||||||
view: cam.view().to_cols_array_2d(),
|
view: cam.view().to_cols_array_2d(),
|
||||||
projection: cam.projection().to_cols_array_2d(),
|
projection: cam.projection().to_cols_array_2d(),
|
||||||
u_light: [light_dir.x, light_dir.y, light_dir.z],
|
camera_pos: [cam.eye.x, cam.eye.y, cam.eye.z],
|
||||||
|
light_dir: [light_dir.x, light_dir.y, light_dir.z],
|
||||||
|
light_color: light_color,
|
||||||
tex: sampler,
|
tex: sampler,
|
||||||
color: [c[0], c[1], c[2]],
|
color: [c[0], c[1], c[2]],
|
||||||
uv_offset: [mat.uv_offset.x, mat.uv_offset.y],
|
uv_offset: [mat.uv_offset.x, mat.uv_offset.y],
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
mod basic;
|
mod basic;
|
||||||
|
mod sky;
|
||||||
pub mod debug_ui;
|
pub mod debug_ui;
|
||||||
|
|
||||||
pub use basic::BasicMeshRenderingSystem;
|
pub use basic::BasicMeshRenderingSystem;
|
||||||
|
pub use sky::SkyAtmosphereRenderingSystem;
|
||||||
64
glium_platform/src/render/sky.rs
Normal file
64
glium_platform/src/render/sky.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
use glium::{uniform, Display, Program, Surface};
|
||||||
|
use glium::glutin::surface::WindowSurface;
|
||||||
|
use glium::index::NoIndices;
|
||||||
|
use glium::index::PrimitiveType;
|
||||||
|
use glium::vertex::EmptyVertexAttributes;
|
||||||
|
use glam::Mat4;
|
||||||
|
use crate::system::RenderingContext;
|
||||||
|
use crate::RenderingSystem;
|
||||||
|
use raidillon_assets::include_shader;
|
||||||
|
use raidillon_platform::Camera;
|
||||||
|
|
||||||
|
pub struct SkyAtmosphereRenderingSystem {
|
||||||
|
program: Program,
|
||||||
|
params: glium::DrawParameters<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderingSystem for SkyAtmosphereRenderingSystem {
|
||||||
|
fn initialize(display: &Display<WindowSurface>, _window: &glium::winit::window::Window) -> Self {
|
||||||
|
const VERT_SRC: &str = include_shader!("sky_atmosphere.vert");
|
||||||
|
const FRAG_SRC: &str = include_shader!("sky_atmosphere.frag");
|
||||||
|
|
||||||
|
let program = Program::from_source(display, VERT_SRC, FRAG_SRC, None).unwrap();
|
||||||
|
|
||||||
|
let params = glium::DrawParameters {
|
||||||
|
depth: glium::Depth {
|
||||||
|
test: glium::draw_parameters::DepthTest::Overwrite,
|
||||||
|
write: false,
|
||||||
|
.. Default::default()
|
||||||
|
},
|
||||||
|
backface_culling: glium::draw_parameters::BackfaceCullingMode::CullingDisabled,
|
||||||
|
.. Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
Self { program, params }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&mut self, ctx: &mut RenderingContext) {
|
||||||
|
let cam = match ctx.scene.world.query::<&Camera>().iter().next() {
|
||||||
|
Some((_, cam)) => *cam,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let inv_view: Mat4 = cam.view().inverse();
|
||||||
|
let inv_proj: Mat4 = cam.projection().inverse();
|
||||||
|
|
||||||
|
let light_dir = glam::Vec3::new(0.0, 2.0, 0.0).normalize();
|
||||||
|
let light_color: [f32; 3] = [1.0, 1.0, 1.0];
|
||||||
|
|
||||||
|
let uniforms = uniform! {
|
||||||
|
inv_view: inv_view.to_cols_array_2d(),
|
||||||
|
inv_projection: inv_proj.to_cols_array_2d(),
|
||||||
|
camera_pos: [cam.eye.x, cam.eye.y, cam.eye.z],
|
||||||
|
light_dir: [light_dir.x, light_dir.y, light_dir.z],
|
||||||
|
light_color: light_color,
|
||||||
|
draw_planet: 1.0f32,
|
||||||
|
};
|
||||||
|
|
||||||
|
let vb = EmptyVertexAttributes { len: 3 };
|
||||||
|
let ib = NoIndices(PrimitiveType::TrianglesList);
|
||||||
|
ctx.target.draw(vb, &ib, &self.program, &uniforms, &self.params).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue