yay procedural sky!
This commit is contained in:
parent
9d60dddcc2
commit
6ff828a167
@ -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
65
client/shaders/sky.fs
Normal 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
34
client/shaders/sky.vs
Normal 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);
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user