1
0

yay procedural sky!

This commit is contained in:
Sky Johnson 2025-09-09 14:29:46 -05:00
parent 9d60dddcc2
commit 6ff828a167
5 changed files with 193 additions and 53 deletions

View File

@ -126,14 +126,14 @@ class Game {
bool editMode = false;
std::string loginError = "";
std::string currentUsername = "";
// Heartbeat timing
float lastHeartbeatTime = 0.0f;
const float HEARTBEAT_INTERVAL = 5.0f; // Send heartbeat every 5 seconds
public:
Game() {
InitWindow(1280, 720, "Multiplayer Terrain Game");
InitWindow(1280, 720, "Game");
SetTargetFPS(60);
// Initialize sky after window is created
@ -169,7 +169,7 @@ public:
if (gameState == STATE_PLAYING && network.isConnected()) {
network.sendLogout();
}
UnloadTexture(terrainTexture);
for (auto& [color, texture] : playerTextures) {
UnloadTexture(texture);
@ -187,7 +187,7 @@ public:
update();
render();
}
// Clean logout when window is closing
if (gameState == STATE_PLAYING && network.isConnected()) {
network.sendLogout();
@ -230,7 +230,7 @@ private:
// Update sky
sky->update(GetFrameTime());
// Time of day controls (for testing)
if (IsKeyPressed(KEY_T)) {
float currentTime = sky->getTimeOfDay();
@ -284,7 +284,7 @@ private:
network.sendMove(moveInput.x, 0, moveInput.z);
lastHeartbeatTime = GetTime(); // Reset heartbeat timer when moving
}
// Send periodic heartbeats when not moving
float currentTime = GetTime();
if (currentTime - lastHeartbeatTime >= HEARTBEAT_INTERVAL) {
@ -334,7 +334,7 @@ private:
void render() {
BeginDrawing();
// Clear with a default color first
ClearBackground(SKYBLUE);
@ -400,7 +400,7 @@ private:
void renderGame() {
BeginMode3D(playerController.getCamera());
// Render skybox first (it will handle its own depth settings)
if (sky) {
sky->renderSkybox(playerController.getCamera());
@ -433,13 +433,13 @@ private:
std::string colorText = "Your color: " + network.getPlayerColor();
DrawText(colorText.c_str(), 10, 110, 20, WHITE);
}
// Show time of day
float timeHour = sky->getTimeOfDay() * 24.0f;
int hour = (int)timeHour;
int minute = (int)((timeHour - hour) * 60);
DrawText(TextFormat("Time: %02d:%02d", hour, minute), 10, 135, 20, WHITE);
DrawFPS(10, 160);
}
};

65
client/shaders/sky.fs Normal file
View File

@ -0,0 +1,65 @@
#version 330
// Input vertex attributes (from vertex shader)
in vec3 fragPosition;
in vec2 fragTexCoord;
in vec4 fragColor;
in vec3 fragNormal;
in vec3 worldPos;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Custom uniforms for sky
uniform vec3 horizonColor;
uniform vec3 zenithColor;
uniform vec3 sunDirection;
uniform vec3 sunColor;
uniform float sunIntensity;
// Output fragment color
out vec4 finalColor;
void main()
{
// Normalize the world position to get direction from center
vec3 direction = normalize(worldPos);
// Calculate gradient based on Y component (height)
float gradientFactor = smoothstep(-0.5, 1.0, direction.y);
// Interpolate between horizon and zenith colors
vec3 skyColor = mix(horizonColor, zenithColor, gradientFactor);
// Calculate sun contribution
vec3 sunDir = normalize(sunDirection);
float sunDot = dot(direction, sunDir);
// Sun rendering
vec3 color = skyColor;
// Only render sun if it's above horizon and has intensity
if (sunDir.y > 0.0 && sunIntensity > 0.1) {
// Sun disc with soft edges
float sunSize = 0.99; // Smaller value = larger sun
float sunEdge = 0.98;
if (sunDot > sunSize) {
// Bright sun core
color = mix(sunColor, vec3(1.0, 1.0, 0.95), 0.8);
} else if (sunDot > sunEdge) {
// Soft edge
float edge = smoothstep(sunEdge, sunSize, sunDot);
color = mix(skyColor, sunColor, edge);
}
// Sun glow
if (sunDot > 0.85) {
float glow = pow(max(0.0, (sunDot - 0.85) / 0.15), 2.0) * sunIntensity;
color = mix(color, sunColor, glow * 0.5);
}
}
finalColor = vec4(color, 1.0);
}

34
client/shaders/sky.vs Normal file
View File

@ -0,0 +1,34 @@
#version 330
// Input vertex attributes
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec3 vertexNormal;
in vec4 vertexColor;
// Input uniform values
uniform mat4 mvp;
uniform mat4 matModel;
uniform mat4 matNormal;
// Output vertex attributes (to fragment shader)
out vec3 fragPosition;
out vec2 fragTexCoord;
out vec4 fragColor;
out vec3 fragNormal;
out vec3 worldPos;
void main()
{
// Send vertex attributes to fragment shader
fragPosition = vec3(matModel * vec4(vertexPosition, 1.0));
fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
fragNormal = normalize(vec3(matNormal * vec4(vertexNormal, 0.0)));
// Store world position for sky calculations
worldPos = vertexPosition;
// Calculate final vertex position
gl_Position = mvp * vec4(vertexPosition, 1.0);
}

View File

@ -2,6 +2,7 @@
#include <rlgl.h>
#include <cmath>
#include <algorithm>
#include <iostream>
Sky::Sky()
: fogDensity(0.01f)
@ -14,8 +15,28 @@ Sky::Sky()
createSkyDome();
updateColors();
// Try to load a custom shader if available
// For now we'll use basic rendering
// Try to load the sky shader
const char* vsPath = "shaders/sky.vs";
const char* fsPath = "shaders/sky.fs";
if (FileExists(vsPath) && FileExists(fsPath)) {
skyShader = LoadShader(vsPath, fsPath);
// Get shader uniform locations
horizonColorLoc = GetShaderLocation(skyShader, "horizonColor");
zenithColorLoc = GetShaderLocation(skyShader, "zenithColor");
sunDirectionLoc = GetShaderLocation(skyShader, "sunDirection");
sunColorLoc = GetShaderLocation(skyShader, "sunColor");
sunIntensityLoc = GetShaderLocation(skyShader, "sunIntensity");
// Assign shader to sky model
skyModel.materials[0].shader = skyShader;
shaderLoaded = true;
std::cout << "Sky shader loaded successfully\n";
} else {
std::cout << "Sky shader files not found, using fallback rendering\n";
}
}
Sky::~Sky() {
@ -26,17 +47,11 @@ Sky::~Sky() {
}
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);
// Create a large sphere for the sky dome
skyDome = GenMeshSphere(500.0f, 16, 16);
// 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);
// Don't invert normals - let's use backface culling instead
// Just upload the mesh as-is
skyModel = LoadModelFromMesh(skyDome);
}
@ -162,38 +177,58 @@ void Sky::renderSkybox(const Camera3D& camera) {
// Disable depth write but keep depth test for proper rendering order
rlDisableDepthMask();
// Disable backface culling so we can see the inside of the sphere
rlDisableBackfaceCulling();
// 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
if (shaderLoaded) {
// First make sure sun position is updated
sun.updatePosition(timeOfDay);
// Draw sun as a sphere
DrawSphere(sunPosOnSphere, 50.0f, sun.color);
// Update shader uniforms
Vector3 horizonColorVec = {
horizonColor.r / 255.0f,
horizonColor.g / 255.0f,
horizonColor.b / 255.0f
};
Vector3 zenithColorVec = {
zenithColor.r / 255.0f,
zenithColor.g / 255.0f,
zenithColor.b / 255.0f
};
Vector3 sunColorVec = {
sun.color.r / 255.0f,
sun.color.g / 255.0f,
sun.color.b / 255.0f
};
// Draw sun glow layers
Color glowColor = sun.color;
glowColor.a = 80;
DrawSphere(sunPosOnSphere, 70.0f, glowColor);
// Normalize sun direction (make sure it's valid)
Vector3 sunDir = {0, 1, 0}; // Default up if sun position is invalid
if (Vector3Length(sun.position) > 0.001f) {
sunDir = Vector3Normalize(sun.position);
}
glowColor.a = 40;
DrawSphere(sunPosOnSphere, 90.0f, glowColor);
// Set shader uniforms
SetShaderValue(skyShader, horizonColorLoc, &horizonColorVec, SHADER_UNIFORM_VEC3);
SetShaderValue(skyShader, zenithColorLoc, &zenithColorVec, SHADER_UNIFORM_VEC3);
SetShaderValue(skyShader, sunDirectionLoc, &sunDir, SHADER_UNIFORM_VEC3);
SetShaderValue(skyShader, sunColorLoc, &sunColorVec, SHADER_UNIFORM_VEC3);
SetShaderValue(skyShader, sunIntensityLoc, &sun.intensity, SHADER_UNIFORM_FLOAT);
// Draw the sky dome with shader
DrawModel(skyModel, {0, 0, 0}, 1.0f, WHITE);
} else {
// Fallback: Draw without shader
Color skyColor = interpolateColor(horizonColor, zenithColor, 0.5f);
DrawModel(skyModel, {0, 0, 0}, 1.0f, skyColor);
}
// Restore depth state
rlEnableBackfaceCulling();
rlEnableDepthMask();
rlPopMatrix();
}

View File

@ -2,7 +2,6 @@
#include <raylib.h>
#include <raymath.h>
#include <vector>
class Sky {
private:
@ -12,7 +11,7 @@ private:
Color color;
float intensity;
float angle; // Sun angle for day/night cycle
void updatePosition(float timeOfDay);
Vector3 getLightDirection() const { return direction; }
};
@ -23,12 +22,19 @@ private:
Color fogColor;
float fogDensity;
float timeOfDay; // 0.0 to 1.0 (0 = midnight, 0.5 = noon)
Shader skyShader;
Mesh skyDome;
Model skyModel;
bool shaderLoaded;
// Shader locations
int horizonColorLoc;
int zenithColorLoc;
int sunDirectionLoc;
int sunColorLoc;
int sunIntensityLoc;
public:
Sky();
~Sky();
@ -36,23 +42,23 @@ public:
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;
};
};