Work on daylight and directional light.

This commit is contained in:
IntegratedQuantum 2022-09-20 13:58:13 +02:00
parent acceb26a36
commit 95eb578719
8 changed files with 242 additions and 49 deletions

View File

@ -3,9 +3,8 @@
in vec3 mvVertexPos;
in vec2 outTexCoord;
flat in float textureIndex;
in vec3 outNormal;
in float outNormalVariation;
uniform vec3 directionalLight;
uniform vec3 ambientLight;
uniform sampler2DArray texture_sampler;
uniform sampler2DArray emissionSampler;
@ -31,7 +30,7 @@ vec4 calcFog(vec3 pos, vec4 color, Fog fog) {
}
void main() {
fragColor = texture(texture_sampler, vec3(outTexCoord, textureIndex))*vec4((1 - dot(directionalLight, outNormal))*ambientLight, 1);
fragColor = texture(texture_sampler, vec3(outTexCoord, textureIndex))*outNormalVariation*vec4(ambientLight, 1);
if (fragColor.a <= 0.1f) discard;
if (fog.activ) {

View File

@ -3,7 +3,7 @@
out vec3 mvVertexPos;
out vec2 outTexCoord;
flat out float textureIndex;
out vec3 outNormal;
out float outNormalVariation;
uniform mat4 projectionMatrix;
@ -32,6 +32,14 @@ layout(std430, binding = 3) buffer _faceData
uniform int time;
const float[6] outNormalVariations = float[6](
0.9, //vec3(-1, 0, 0),
0.9, //vec3(1, 0, 0),
0.85, //vec3(0, 0, -1),
0.95, //vec3(0, 0, 1),
0.8, //vec3(0, -1, 0),
1.0 //vec3(0, 1, 0)
);
const vec3[6] normals = vec3[6](
vec3(-1, 0, 0),
vec3(1, 0, 0),
@ -80,7 +88,7 @@ void main() {
vec4 mvPos = viewMatrix*vec4(globalPosition, 1);
gl_Position = projectionMatrix*mvPos;
outNormal = normals[normal];
outNormalVariation = outNormalVariations[normal];
mvVertexPos = mvPos.xyz;
// Check if this vertex is outside the bounds that should be rendered:

View File

@ -493,7 +493,6 @@ pub const meshing = struct {
viewMatrix: c_int,
modelPosition: c_int,
ambientLight: c_int,
directionalLight: c_int,
@"fog.activ": c_int,
@"fog.color": c_int,
@"fog.density": c_int,
@ -538,7 +537,7 @@ pub const meshing = struct {
faces.deinit();
}
pub fn bindShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, directional: Vec3f, time: u32) void {
pub fn bindShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, time: u32) void {
shader.bind();
c.glUniform1i(uniforms.@"fog.activ", if(game.fog.active) 1 else 0);
@ -553,7 +552,6 @@ pub const meshing = struct {
c.glUniformMatrix4fv(uniforms.viewMatrix, 1, c.GL_FALSE, @ptrCast([*c]f32, &game.camera.viewMatrix));
c.glUniform3f(uniforms.ambientLight, ambient.x, ambient.y, ambient.z);
c.glUniform3f(uniforms.directionalLight, directional.x, directional.y, directional.z);
c.glUniform1i(uniforms.time, @bitCast(i32, time));

View File

@ -1,14 +1,22 @@
const std = @import("std");
const assets = @import("assets.zig");
const chunk = @import("chunk.zig");
const json = @import("json.zig");
const JsonElement = json.JsonElement;
const main = @import("main.zig");
const keyboard = &main.keyboard;
const network = @import("network.zig");
const Connection = network.Connection;
const ConnectionManager = network.ConnectionManager;
const vec = @import("vec.zig");
const Vec3f = vec.Vec3f;
const Vec4f = vec.Vec4f;
const Vec3d = vec.Vec3d;
const Mat4f = vec.Mat4f;
const graphics = @import("graphics.zig");
const Fog = graphics.Fog;
const renderer = @import("renderer.zig");
pub const camera = struct {
pub var rotation: Vec3f = Vec3f{.x=0, .y=0, .z=0};
@ -37,9 +45,203 @@ pub var playerPos: Vec3d = Vec3d{.x=0, .y=0, .z=0};
pub var playerVel: Vec3d = Vec3d{.x=0, .y=0, .z=0};
pub var isFlying: bool = true;
pub var blockPalette: *assets.BlockPalette = undefined;
pub const World = u1; // TODO
pub var testWorld: World = 0;
pub const World = struct {
const dayCycle: u63 = 12000; // Length of one in-game day in 100ms. Midnight is at DAY_CYCLE/2. Sunrise and sunset each take about 1/16 of the day. Currently set to 20 minutes
conn: *Connection,
manager: *ConnectionManager,
ambientLight: f32 = 0,
clearColor: Vec4f = Vec4f{.x=0, .y=0, .z=0, .w=1},
name: []const u8,
milliTime: i64,
gameTime: i64 = 0,
spawn: Vec3f = undefined,
blockPalette: *assets.BlockPalette = undefined,
// TODO:
// public ItemEntityManager itemEntityManager;
// public BlockPalette blockPalette;
// TODO: public Biome playerBiome;
// public final ArrayList<String> chatHistory = new ArrayList<>();
pub fn init(self: *World, ip: []const u8, manager: *ConnectionManager) !void {
self.* = World {
.conn = try Connection.init(manager, ip),
.manager = manager,
.name = "client",
.milliTime = std.time.milliTimestamp(),
};
// TODO:
// super.itemEntityManager = new InterpolatedItemEntityManager(this);
// player = new ClientPlayer(this, 0);
try network.Protocols.handShake.clientSide(self.conn, "quanturmdoelvloper"); // TODO: Read name from settings.
}
pub fn deinit(self: *World) void {
self.conn.deinit();
}
pub fn finishHandshake(self: *World, jsonObject: JsonElement) !void {
// TODO: Consider using a per-world allocator.
self.blockPalette = try assets.BlockPalette.init(renderer.RenderOctree.allocator, jsonObject.getChild("blockPalette"));
var jsonSpawn = jsonObject.getChild("spawn");
self.spawn.x = jsonSpawn.get(f32, "x", 0);
self.spawn.y = jsonSpawn.get(f32, "y", 0);
self.spawn.z = jsonSpawn.get(f32, "z", 0);
// TODO:
// if(Server.world != null) {
// // Share the registries of the local server:
// registries = Server.world.getCurrentRegistries();
// } else {
// registries = new CurrentWorldRegistries(this, "serverAssets/", blockPalette);
// }
//
// player.loadFrom(json.getObjectOrNew("player"), this);
// player.id = json.getInt("player_id", -1);
//
// // Call mods for this new world. Mods sometimes need to do extra stuff for the specific world.
// ModLoader.postWorldGen(registries);
try assets.loadWorldAssets("serverAssets", self.blockPalette);
}
pub fn update(self: *World) !void {
var newTime: i64 = std.time.milliTimestamp();
while(self.milliTime +% 100 -% newTime < 0) { // TODO: Just use milli time directly?
self.milliTime +%= 100;
self.gameTime +%= 1;
}
// Ambient light:
{
var dayTime = std.math.absInt(@mod(self.gameTime, dayCycle) -% dayCycle/2) catch 0;
if(dayTime < dayCycle/4 - dayCycle/16) {
self.ambientLight = 0.1;
self.clearColor.x = 0;
self.clearColor.y = 0;
self.clearColor.z = 0;
} else if(dayTime > dayCycle/4 + dayCycle/16) {
self.ambientLight = 1;
self.clearColor.x = 0.8;
self.clearColor.y = 0.8;
self.clearColor.z = 1.0;
} else {
// b:
if(dayTime > dayCycle/4) {
self.clearColor.z = @intToFloat(f32, dayTime - dayCycle/4)/@intToFloat(f32, dayCycle/16);
} else {
self.clearColor.z = 0;
}
// g:
if(dayTime > dayCycle/4 + dayCycle/32) {
self.clearColor.y = 0.8;
} else if(dayTime > dayCycle/4 - dayCycle/32) {
self.clearColor.y = 0.8 + 0.8*@intToFloat(f32, dayTime - dayCycle/4 - dayCycle/32)/@intToFloat(f32, dayCycle/16);
} else {
self.clearColor.y = 0;
}
// r:
if(dayTime > dayCycle/4) {
self.clearColor.x = 0.8;
} else {
self.clearColor.x = 0.8 + 0.8*@intToFloat(f32, dayTime - dayCycle/4)/@intToFloat(f32, dayCycle/16);
}
dayTime -= dayCycle/4;
dayTime <<= 3;
self.ambientLight = 0.55 + 0.45*@intToFloat(f32, dayTime)/@intToFloat(f32, dayCycle/2);
}
}
try network.Protocols.playerPosition.send(self.conn, playerPos, playerVel, @intCast(u16, newTime & 65535));
}
// TODO:
// public void drop(ItemStack stack, Vector3d pos, Vector3f dir, float velocity) {
// Protocols.GENERIC_UPDATE.itemStackDrop(serverConnection, stack, pos, dir, velocity);
// }
// public void updateBlock(int x, int y, int z, int newBlock) {
// NormalChunk ch = getChunk(x, y, z);
// if (ch != null) {
// int old = ch.getBlock(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask);
// if(old != newBlock) {
// ch.updateBlock(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask, newBlock);
// Protocols.BLOCK_UPDATE.send(serverConnection, x, y, z, newBlock);
// }
// }
// }
// /**
// * Block update that came from the server. In this case there needs to be no update sent to the server.
// */
// public void remoteUpdateBlock(int x, int y, int z, int newBlock) {
// NormalChunk ch = getChunk(x, y, z);
// if (ch != null) {
// int old = ch.getBlock(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask);
// if(old != newBlock) {
// ch.updateBlock(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask, newBlock);
// }
// }
// }
// public void queueChunks(ChunkData[] chunks) {
// Protocols.CHUNK_REQUEST.sendRequest(serverConnection, chunks);
// }
// public NormalChunk getChunk(int wx, int wy, int wz) {
// RenderOctTree.OctTreeNode node = Cubyz.chunkTree.findNode(new ChunkData(wx, wy, wz, 1));
// if(node == null)
// return null;
// ChunkData chunk = node.mesh.getChunk();
// if(chunk instanceof NormalChunk)
// return (NormalChunk)chunk;
// return null;
// }
// public void cleanup() {
// connectionManager.cleanup();
// ThreadPool.clear();
// }
//
// public final BlockInstance getBlockInstance(int x, int y, int z) {
// VisibleChunk ch = (VisibleChunk)getChunk(x, y, z);
// if (ch != null && ch.isLoaded()) {
// return ch.getBlockInstanceAt(Chunk.getIndex(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask));
// } else {
// return null;
// }
// }
//
// public int getLight(int x, int y, int z, Vector3f sunLight, boolean easyLighting) {
// VisibleChunk ch = (VisibleChunk)getChunk(x, y, z);
// if (ch == null || !ch.isLoaded() || !easyLighting)
// return 0xffffffff;
// return ch.getLight(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask);
// }
//
// public void getLight(VisibleChunk ch, int x, int y, int z, int[] array) {
// int block = getBlock(x, y, z);
// if (block == 0) return;
// int selfLight = Blocks.light(block);
// x--;
// y--;
// z--;
// for(int ix = 0; ix < 3; ix++) {
// for(int iy = 0; iy < 3; iy++) {
// for(int iz = 0; iz < 3; iz++) {
// array[ix + iy*3 + iz*9] = getLight(ch, x+ix, y+iy, z+iz, selfLight);
// }
// }
// }
// }
//
// protected int getLight(VisibleChunk ch, int x, int y, int z, int minLight) {
// if (x - ch.wx != (x & Chunk.chunkMask) || y - ch.wy != (y & Chunk.chunkMask) || z - ch.wz != (z & Chunk.chunkMask))
// ch = (VisibleChunk)getChunk(x, y, z);
// if (ch == null || !ch.isLoaded())
// return 0xff000000;
// int light = ch.getLight(x & Chunk.chunkMask, y & Chunk.chunkMask, z & Chunk.chunkMask);
// // Make sure all light channels are at least as big as the minimum:
// if ((light & 0xff000000) >>> 24 < (minLight & 0xff000000) >>> 24) light = (light & 0x00ffffff) | (minLight & 0xff000000);
// if ((light & 0x00ff0000) < (minLight & 0x00ff0000)) light = (light & 0xff00ffff) | (minLight & 0x00ff0000);
// if ((light & 0x0000ff00) < (minLight & 0x0000ff00)) light = (light & 0xffff00ff) | (minLight & 0x0000ff00);
// if ((light & 0x000000ff) < (minLight & 0x000000ff)) light = (light & 0xffffff00) | (minLight & 0x000000ff);
// return light;
// }
};
pub var testWorld: World = undefined; // TODO:
pub var world: ?*World = &testWorld;
pub var projectionMatrix: Mat4f = Mat4f.identity();
@ -48,7 +250,7 @@ pub var lodProjectionMatrix: Mat4f = Mat4f.identity();
pub var fog = Fog{.active = true, .color=.{.x=0, .y=1, .z=0.5}, .density=1.0/15.0/256.0};
pub fn update(deltaTime: f64) void {
pub fn update(deltaTime: f64) !void {
var movement = Vec3d{.x=0, .y=0, .z=0};
var forward = Vec3d.rotateY(Vec3d{.x=0, .y=0, .z=-1}, -camera.rotation.y);
var right = Vec3d{.x=forward.z, .y=0, .z=-forward.x};
@ -94,4 +296,5 @@ pub fn update(deltaTime: f64) void {
}
playerPos.addEqual(movement.mulScalar(deltaTime));
try world.?.update();
}

View File

@ -253,15 +253,11 @@ pub fn main() !void {
var manager = try network.ConnectionManager.init(12347, true);
defer manager.deinit();
var conn = try network.Connection.init(manager, "127.0.0.1");
defer conn.deinit();
try network.Protocols.handShake.clientSide(conn, "quanturmdoelvloper");
try game.world.?.init("127.0.0.1", manager);
defer game.world.?.deinit();
Window.setMouseGrabbed(true);
try assets.loadWorldAssets("serverAssets", game.blockPalette);
try blocks.meshes.generateTextureArray();
c.glCullFace(c.GL_BACK);
@ -282,14 +278,12 @@ pub fn main() !void {
var newTime = std.time.milliTimestamp();
var deltaTime = @intToFloat(f64, newTime -% lastTime)/1000.0;
lastTime = newTime;
var timeShort = @intCast(u16, lastTime & 65535);
game.update(deltaTime);
try renderer.RenderOctree.update(conn, game.playerPos, 4, 2.0);
try game.update(deltaTime);
try renderer.RenderOctree.update(game.world.?.conn, game.playerPos, 4, 2.0);
{ // Render the game
c.glEnable(c.GL_CULL_FACE);
c.glEnable(c.GL_DEPTH_TEST);
try renderer.render(game.playerPos);
try network.Protocols.playerPosition.send(conn, game.playerPos, game.playerVel, timeShort);
}
{ // Render the GUI

View File

@ -609,10 +609,7 @@ pub const Protocols = blk: {
stepServerData => {
var jsonObject = json.parseFromString(main.threadAllocator, data[1..]);
defer jsonObject.free(main.threadAllocator);
// TODO: ((ServerConnection)conn).world.finishHandshake(json);
{// TODO: Move this into world loading finishHandshake().
game.blockPalette = try assets.BlockPalette.init(renderer.RenderOctree.allocator, jsonObject.getChild("blockPalette")); // TODO: Use the world allocator and free this.
}
try game.world.?.finishHandshake(jsonObject);
conn.handShakeState = stepComplete;
conn.handShakeWaiting.broadcast(); // Notify the waiting client thread.
},

View File

@ -173,27 +173,21 @@ pub fn render(playerPosition: Vec3d) !void {
// }
if(game.world) |world| {
// // TODO: Handle colors and sun position in the world.
// ambient.x = ambient.y = ambient.z = Cubyz.world.getGlobalLighting();
// if (ambient.x < 0.1f) ambient.x = 0.1f;
// if (ambient.y < 0.1f) ambient.y = 0.1f;
// if (ambient.z < 0.1f) ambient.z = 0.1f;
// clearColor = Cubyz.world.getClearColor();
// Cubyz.fog.setColor(clearColor);
var ambient: Vec3f = undefined;
ambient.x = @maximum(0.1, world.ambientLight);
ambient.y = @maximum(0.1, world.ambientLight);
ambient.z = @maximum(0.1, world.ambientLight);
var skyColor = Vec3f.xyz(world.clearColor);
game.fog.color = skyColor;
// TODO:
// Cubyz.fog.setActive(ClientSettings.FOG_COEFFICIENT != 0);
// Cubyz.fog.setDensity(1 / (ClientSettings.EFFECTIVE_RENDER_DISTANCE*ClientSettings.FOG_COEFFICIENT));
// clearColor = clearColor.mul(0.25f, new Vector4f());
//
// light.setColor(clearColor);
//
// float lightY = ((float)Cubyz.world.gameTime % World.DAY_CYCLE) / (float) (World.DAY_CYCLE/2) - 1f;
// float lightX = ((float)Cubyz.world.gameTime % World.DAY_CYCLE) / (float) (World.DAY_CYCLE/2) - 1f;
// light.getDirection().set(lightY, 0, lightX);
// // Set intensity:
// light.setDirection(light.getDirection().mul(0.1f*Cubyz.world.getGlobalLighting()/light.getDirection().length()));
// Window.setClearColor(clearColor);
try renderWorld(world, Vec3f{.x=1, .y=1, .z=1}, Vec3f{.x=0.3, .y=-1, .z=0.5}, playerPosition);
skyColor.mulEqualScalar(0.25);
try renderWorld(world, ambient, skyColor, playerPosition);
try RenderOctree.updateMeshes(startTime + maximumMeshTime);
} else {
// TODO:
// clearColor.y = clearColor.z = 0.7f;
// clearColor.x = 0.1f;@import("main.zig")
//
@ -205,10 +199,10 @@ pub fn render(playerPosition: Vec3d) !void {
// Keyboard.release(); // TODO: Why is this called in the render thread???
}
pub fn renderWorld(world: *World, ambientLight: Vec3f, directionalLight: Vec3f, playerPos: Vec3d) !void {
pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPos: Vec3d) !void {
_ = world;
buffers.bind();
buffers.clearAndBind(Vec4f{.x=0, .y=1, .z=0.5, .w=1});
buffers.clearAndBind(Vec4f{.x=skyColor.x, .y=skyColor.y, .z=skyColor.z, .w=1});
// TODO:// Clean up old chunk meshes:
// Meshes.cleanUp();
game.camera.updateViewMatrix();
@ -220,7 +214,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, directionalLight: Vec3f,
const waterFog = Fog{.active=true, .color=.{.x=0.0, .y=0.1, .z=0.2}, .density=0.1};
// Update the uniforms. The uniforms are needed to render the replacement meshes.
chunk.meshing.bindShaderAndUniforms(game.lodProjectionMatrix, ambientLight, directionalLight, time);
chunk.meshing.bindShaderAndUniforms(game.lodProjectionMatrix, ambientLight, time);
//TODO: NormalChunkMesh.bindShader(ambientLight, directionalLight.getDirection(), time);
@ -260,7 +254,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, directionalLight: Vec3f,
// Render the far away ReducedChunks:
c.glDepthRangef(0.05, 1.0); // Used to fix z-fighting.
chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight, directionalLight, time);
chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight, time);
c.glUniform1i(chunk.meshing.uniforms.@"waterFog.activ", if(waterFog.active) 1 else 0);
c.glUniform3fv(chunk.meshing.uniforms.@"waterFog.color", 1, @ptrCast([*c]f32, &waterFog.color));
c.glUniform1f(chunk.meshing.uniforms.@"waterFog.density", waterFog.density);
@ -590,7 +584,7 @@ pub const RenderOctree = struct {
allocator.destroy(updatable);
}
updatableList.deinit();
game.blockPalette.deinit();
game.world.?.blockPalette.deinit();
if(gpa.deinit()) {
@panic("Memory leak");
}

View File

@ -164,7 +164,7 @@ fn GenericVectorMath(comptime Vec: type, comptime T: type) type {
}
}
pub fn mulEqualScalar(self: *Vec, scalar: T) Vec {
pub fn mulEqualScalar(self: *Vec, scalar: T) void {
inline for(@typeInfo(Vec).Struct.fields) |field| {
@field(self, field.name) *= scalar;
}