1
0

first pass on sky

This commit is contained in:
Sky Johnson 2025-09-09 14:03:00 -05:00
parent 47c829f962
commit 9d60dddcc2
2 changed files with 306 additions and 0 deletions

248
client/sky/Sky.cpp Normal file
View File

@ -0,0 +1,248 @@
#include "Sky.hpp"
#include <rlgl.h>
#include <cmath>
#include <algorithm>
Sky::Sky()
: fogDensity(0.01f)
, timeOfDay(0.25f) // Start at sunrise
, shaderLoaded(false) {
sun.intensity = 1.0f;
sun.angle = 0.0f;
createSkyDome();
updateColors();
// Try to load a custom shader if available
// For now we'll use basic rendering
}
Sky::~Sky() {
if (shaderLoaded) {
UnloadShader(skyShader);
}
UnloadModel(skyModel);
}
void Sky::createSkyDome() {
// Create a large inverted sphere for the sky dome
// The sphere is inverted so we see the inside surface
skyDome = GenMeshSphere(1000.0f, 32, 32);
// Invert the mesh normals to render the inside
for (int i = 0; i < skyDome.vertexCount * 3; i++) {
skyDome.normals[i] *= -1.0f;
}
// Update mesh in GPU
UploadMesh(&skyDome, false);
skyModel = LoadModelFromMesh(skyDome);
}
void Sky::update(float) {
// Optional: auto-advance time of day for testing
// timeOfDay += deltaTime * 0.01f; // Very slow day cycle
// if (timeOfDay > 1.0f) timeOfDay -= 1.0f;
updateColors();
sun.updatePosition(timeOfDay);
}
void Sky::Sun::updatePosition(float timeOfDay) {
// Convert time of day to angle (0.25 = sunrise at 6am, 0.75 = sunset at 6pm)
// Adjust so that 0.25 (6am) = 0 degrees, 0.75 (6pm) = 180 degrees
float adjustedTime = timeOfDay - 0.25f;
if (adjustedTime < 0) adjustedTime += 1.0f;
// Only show sun during daytime (6am to 6pm)
if (timeOfDay >= 0.25f && timeOfDay <= 0.75f) {
float dayProgress = (timeOfDay - 0.25f) / 0.5f; // 0 to 1 during day
angle = dayProgress * PI; // 0 to PI (sunrise to sunset)
// Calculate sun position in an arc
float sunX = cosf(angle) * 150.0f; // East to West
float sunY = sinf(angle) * 100.0f + 20.0f; // Height arc, minimum 20 units up
float sunZ = 0.0f;
position = {sunX, sunY, sunZ};
} else {
// Sun is below horizon at night
position = {0.0f, -100.0f, 0.0f};
}
// Direction is from sun to origin (for lighting)
direction = Vector3Normalize(Vector3Scale(position, -1.0f));
}
void Sky::updateColors() {
float t = timeOfDay;
// Define key times
const float nightEnd = 0.2f; // 4:48 AM
const float sunrise = 0.25f; // 6:00 AM
const float noon = 0.5f; // 12:00 PM
const float sunset = 0.75f; // 6:00 PM
const float nightStart = 0.8f; // 7:12 PM
Color nightHorizon = {10, 15, 30, 255};
Color nightZenith = {5, 10, 20, 255};
Color sunriseHorizon = {255, 150, 100, 255};
Color sunriseZenith = {100, 150, 200, 255};
Color dayHorizon = {150, 200, 255, 255};
Color dayZenith = {100, 150, 255, 255};
Color sunsetHorizon = {255, 100, 50, 255};
Color sunsetZenith = {100, 100, 150, 255};
if (t < nightEnd) {
// Night
horizonColor = nightHorizon;
zenithColor = nightZenith;
sun.color = {50, 50, 70, 255};
sun.intensity = 0.1f;
} else if (t < sunrise) {
// Night to sunrise transition
float blend = (t - nightEnd) / (sunrise - nightEnd);
horizonColor = interpolateColor(nightHorizon, sunriseHorizon, blend);
zenithColor = interpolateColor(nightZenith, sunriseZenith, blend);
sun.color = interpolateColor({50, 50, 70, 255}, {255, 200, 150, 255}, blend);
sun.intensity = 0.1f + blend * 0.4f;
} else if (t < noon) {
// Sunrise to noon
float blend = (t - sunrise) / (noon - sunrise);
horizonColor = interpolateColor(sunriseHorizon, dayHorizon, blend);
zenithColor = interpolateColor(sunriseZenith, dayZenith, blend);
sun.color = interpolateColor({255, 200, 150, 255}, {255, 255, 250, 255}, blend);
sun.intensity = 0.5f + blend * 0.5f;
} else if (t < sunset) {
// Noon to sunset
float blend = (t - noon) / (sunset - noon);
horizonColor = interpolateColor(dayHorizon, sunsetHorizon, blend);
zenithColor = interpolateColor(dayZenith, sunsetZenith, blend);
sun.color = interpolateColor({255, 255, 250, 255}, {255, 180, 100, 255}, blend);
sun.intensity = 1.0f - blend * 0.3f;
} else if (t < nightStart) {
// Sunset to night transition
float blend = (t - sunset) / (nightStart - sunset);
horizonColor = interpolateColor(sunsetHorizon, nightHorizon, blend);
zenithColor = interpolateColor(sunsetZenith, nightZenith, blend);
sun.color = interpolateColor({255, 180, 100, 255}, {50, 50, 70, 255}, blend);
sun.intensity = 0.7f - blend * 0.6f;
} else {
// Night
horizonColor = nightHorizon;
zenithColor = nightZenith;
sun.color = {50, 50, 70, 255};
sun.intensity = 0.1f;
}
// Fog color follows horizon color but slightly desaturated
fogColor = interpolateColor(horizonColor, {200, 200, 200, 255}, 0.3f);
}
Color Sky::interpolateColor(const Color& a, const Color& b, float t) const {
t = std::clamp(t, 0.0f, 1.0f);
return {
(unsigned char)(a.r + (b.r - a.r) * t),
(unsigned char)(a.g + (b.g - a.g) * t),
(unsigned char)(a.b + (b.b - a.b) * t),
(unsigned char)(a.a + (b.a - a.a) * t)
};
}
void Sky::render(const Camera3D& camera) {
// Legacy function - just calls renderSkybox
renderSkybox(camera);
}
void Sky::renderSkybox(const Camera3D& camera) {
// Save current depth state
rlPushMatrix();
// Disable depth write but keep depth test for proper rendering order
rlDisableDepthMask();
// Position skybox at camera position so it moves with the camera
// This ensures the skybox is always centered on the viewer
rlTranslatef(camera.position.x, camera.position.y, camera.position.z);
// Draw the sky dome with gradient color
// We'll use vertex colors or a simple colored material
Color topColor = zenithColor;
Color bottomColor = horizonColor;
// For now, draw with a blended color
Color skyColor = interpolateColor(bottomColor, topColor, 0.5f);
DrawModel(skyModel, {0, 0, 0}, 1.0f, skyColor);
// Draw sun as a sphere on the skybox
if (sun.intensity > 0.2f && sun.position.y > 0) {
// Calculate sun direction from camera
Vector3 sunDir = Vector3Normalize(sun.position);
Vector3 sunPosOnSphere = Vector3Scale(sunDir, 900.0f); // Just inside the skybox
// Draw sun as a sphere
DrawSphere(sunPosOnSphere, 50.0f, sun.color);
// Draw sun glow layers
Color glowColor = sun.color;
glowColor.a = 80;
DrawSphere(sunPosOnSphere, 70.0f, glowColor);
glowColor.a = 40;
DrawSphere(sunPosOnSphere, 90.0f, glowColor);
}
// Restore depth state
rlEnableDepthMask();
rlPopMatrix();
}
void Sky::drawGradientSky() const {
// Draw a simple gradient from horizon to zenith
int screenHeight = GetScreenHeight();
int screenWidth = GetScreenWidth();
// Draw gradient rectangles
for (int y = 0; y < screenHeight; y++) {
float t = (float)y / (float)screenHeight;
Color gradientColor = interpolateColor(zenithColor, horizonColor, t);
DrawRectangle(0, y, screenWidth, 1, gradientColor);
}
}
void Sky::drawSun(const Camera3D& camera) const {
// Only draw sun during day time
if (sun.intensity > 0.2f) {
// Calculate sun screen position
Vector2 sunScreenPos = GetWorldToScreen(sun.position, camera);
// Check if sun is in view
if (sunScreenPos.x >= 0 && sunScreenPos.x <= GetScreenWidth() &&
sunScreenPos.y >= 0 && sunScreenPos.y <= GetScreenHeight()) {
// Draw sun glow
float glowRadius = 60.0f * sun.intensity;
Color glowColor = sun.color;
glowColor.a = 50;
DrawCircleGradient(sunScreenPos.x, sunScreenPos.y, glowRadius,
glowColor, {glowColor.r, glowColor.g, glowColor.b, 0});
// Draw sun disc
float sunRadius = 20.0f;
DrawCircle(sunScreenPos.x, sunScreenPos.y, sunRadius, sun.color);
}
}
}
void Sky::setTimeOfDay(float time) {
timeOfDay = std::clamp(time, 0.0f, 1.0f);
updateColors();
sun.updatePosition(timeOfDay);
}
Color Sky::getAmbientLight() const {
// Ambient light based on time of day
float ambientIntensity = 0.2f + sun.intensity * 0.3f;
return interpolateColor({20, 20, 30, 255}, zenithColor, ambientIntensity);
}

58
client/sky/Sky.hpp Normal file
View File

@ -0,0 +1,58 @@
#pragma once
#include <raylib.h>
#include <raymath.h>
#include <vector>
class Sky {
private:
struct Sun {
Vector3 position;
Vector3 direction;
Color color;
float intensity;
float angle; // Sun angle for day/night cycle
void updatePosition(float timeOfDay);
Vector3 getLightDirection() const { return direction; }
};
Sun sun;
Color horizonColor;
Color zenithColor;
Color fogColor;
float fogDensity;
float timeOfDay; // 0.0 to 1.0 (0 = midnight, 0.5 = noon)
Shader skyShader;
Mesh skyDome;
Model skyModel;
bool shaderLoaded;
public:
Sky();
~Sky();
void update(float deltaTime);
void render(const Camera3D& camera);
void renderSkybox(const Camera3D& camera); // Render skybox that follows camera
void setTimeOfDay(float time);
float getTimeOfDay() const { return timeOfDay; }
Vector3 getSunDirection() const { return sun.direction; }
Color getSunColor() const { return sun.color; }
float getSunIntensity() const { return sun.intensity; }
Color getFogColor() const { return fogColor; }
float getFogDensity() const { return fogDensity; }
Color getAmbientLight() const;
private:
void updateColors();
void createSkyDome();
Color interpolateColor(const Color& a, const Color& b, float t) const;
void drawGradientSky() const;
void drawSun(const Camera3D& camera) const;
};