mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 11:17:05 -04:00
Handle the case that the player is inside the fog.
This commit is contained in:
parent
50946c352b
commit
2e5910a9cc
@ -6,8 +6,68 @@ in vec2 texCoords;
|
||||
|
||||
layout(binding = 3) uniform sampler2D color;
|
||||
|
||||
uniform sampler2D depthTexture;
|
||||
uniform int blockType;
|
||||
uniform float nearPlane;
|
||||
|
||||
struct TextureData {
|
||||
int textureIndices[6];
|
||||
uint absorption;
|
||||
float reflectivity;
|
||||
float fogStrength;
|
||||
uint fogColor;
|
||||
};
|
||||
|
||||
layout(std430, binding = 1) buffer _textureData
|
||||
{
|
||||
TextureData textureData[];
|
||||
};
|
||||
|
||||
vec3 unpackColor(uint color) {
|
||||
return vec3(
|
||||
color>>16 & 255u,
|
||||
color>>8 & 255u,
|
||||
color & 255u
|
||||
)/255.0;
|
||||
}
|
||||
|
||||
float calculateFogDistance(float depthBufferValue) {
|
||||
float fogStrength = textureData[blockType].fogStrength;
|
||||
float distCameraTerrain = nearPlane*fogStrength/depthBufferValue;
|
||||
float distFromCamera = 0;
|
||||
float distFromTerrain = distFromCamera - distCameraTerrain;
|
||||
if(distCameraTerrain < 10) { // Resolution range is sufficient.
|
||||
return distFromTerrain;
|
||||
} else {
|
||||
// Here we have a few options to deal with this. We could for example weaken the fog effect to fit the entire range.
|
||||
// I decided to keep the fog strength close to the camera and far away, with a fog-free region in between.
|
||||
// I decided to this because I want far away fog to work (e.g. a distant ocean) as well as close fog(e.g. the top surface of the water when the player is under it)
|
||||
if(distFromTerrain > -5 && depthBufferValue != 0) {
|
||||
return distFromTerrain;
|
||||
} else if(distFromCamera < 5) {
|
||||
return distFromCamera - 10;
|
||||
} else {
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec3 fetch(ivec2 pos) {
|
||||
vec4 rgba = texelFetch(color, pos, 0);
|
||||
if(blockType != 0) { // TODO: Handle air fog as well.
|
||||
float fogDistance = calculateFogDistance(texelFetch(depthTexture, pos, 0).r);
|
||||
vec3 fogColor = unpackColor(textureData[blockType].fogColor);
|
||||
float fogFactor = exp(fogDistance);
|
||||
vec4 sourceColor = vec4(fogColor, 1);
|
||||
sourceColor.a = 1.0/fogFactor;
|
||||
sourceColor.rgb *= sourceColor.a;
|
||||
sourceColor.rgb -= fogColor;
|
||||
vec3 source2Color = vec3(1);
|
||||
rgba = vec4(
|
||||
source2Color*rgba.rgb + rgba.a*sourceColor.rgb,
|
||||
rgba.a*sourceColor.a
|
||||
);
|
||||
}
|
||||
if(rgba.a < 1) return vec3(0); // Prevent t-junctions from transparency from making a huge mess.
|
||||
return rgba.rgb/rgba.a;
|
||||
}
|
||||
|
@ -5,8 +5,68 @@ in vec2 texCoords;
|
||||
|
||||
uniform sampler2D color;
|
||||
|
||||
uniform sampler2D depthTexture;
|
||||
uniform int blockType;
|
||||
uniform float nearPlane;
|
||||
|
||||
struct TextureData {
|
||||
int textureIndices[6];
|
||||
uint absorption;
|
||||
float reflectivity;
|
||||
float fogStrength;
|
||||
uint fogColor;
|
||||
};
|
||||
|
||||
layout(std430, binding = 1) buffer _textureData
|
||||
{
|
||||
TextureData textureData[];
|
||||
};
|
||||
|
||||
vec3 unpackColor(uint color) {
|
||||
return vec3(
|
||||
color>>16 & 255u,
|
||||
color>>8 & 255u,
|
||||
color & 255u
|
||||
)/255.0;
|
||||
}
|
||||
|
||||
float calculateFogDistance(float depthBufferValue) {
|
||||
float fogStrength = textureData[blockType].fogStrength;
|
||||
float distCameraTerrain = nearPlane*fogStrength/depthBufferValue;
|
||||
float distFromCamera = 0;
|
||||
float distFromTerrain = distFromCamera - distCameraTerrain;
|
||||
if(distCameraTerrain < 10) { // Resolution range is sufficient.
|
||||
return distFromTerrain;
|
||||
} else {
|
||||
// Here we have a few options to deal with this. We could for example weaken the fog effect to fit the entire range.
|
||||
// I decided to keep the fog strength close to the camera and far away, with a fog-free region in between.
|
||||
// I decided to this because I want far away fog to work (e.g. a distant ocean) as well as close fog(e.g. the top surface of the water when the player is under it)
|
||||
if(distFromTerrain > -5 && depthBufferValue != 0) {
|
||||
return distFromTerrain;
|
||||
} else if(distFromCamera < 5) {
|
||||
return distFromCamera - 10;
|
||||
} else {
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
fragColor = texture(color, texCoords);
|
||||
if(blockType != 0) { // TODO: Handle air fog as well.
|
||||
float fogDistance = calculateFogDistance(texelFetch(depthTexture, ivec2(gl_FragCoord.xy), 0).r);
|
||||
vec3 fogColor = unpackColor(textureData[blockType].fogColor);
|
||||
float fogFactor = exp(fogDistance);
|
||||
vec4 sourceColor = vec4(fogColor, 1);
|
||||
sourceColor.a = 1.0/fogFactor;
|
||||
sourceColor.rgb *= sourceColor.a;
|
||||
sourceColor.rgb -= fogColor;
|
||||
vec3 source2Color = vec3(1);
|
||||
fragColor = vec4(
|
||||
source2Color*fragColor.rgb + fragColor.a*sourceColor.rgb,
|
||||
fragColor.a*sourceColor.a
|
||||
);
|
||||
}
|
||||
fragColor.rgb /= fragColor.a;
|
||||
float maxColor = max(1.0, max(fragColor.r, max(fragColor.g, fragColor.b)));
|
||||
fragColor.rgb = fragColor.rgb/maxColor;
|
||||
|
@ -18,7 +18,6 @@ pub const Samples = enum(u8) {
|
||||
chunk_rendering,
|
||||
entity_rendering,
|
||||
transparent_rendering,
|
||||
normalization,
|
||||
bloom_extract_downsample,
|
||||
bloom_first_pass,
|
||||
bloom_second_pass,
|
||||
@ -33,7 +32,6 @@ const names = [_][]const u8 {
|
||||
"Chunk Rendering",
|
||||
"Entity Rendering",
|
||||
"Transparent Rendering",
|
||||
"Normalization",
|
||||
"Bloom - Extract color and downsample",
|
||||
"Bloom - First Pass",
|
||||
"Bloom - Second Pass",
|
||||
|
@ -40,6 +40,9 @@ var fogUniforms: struct {
|
||||
var deferredRenderPassShader: graphics.Shader = undefined;
|
||||
var deferredUniforms: struct {
|
||||
color: c_int,
|
||||
depthTexture: c_int,
|
||||
blockType: c_int,
|
||||
nearPlane: c_int,
|
||||
} = undefined;
|
||||
|
||||
pub var activeFrameBuffer: c_uint = 0;
|
||||
@ -193,6 +196,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
worldFrameBuffer.bindDepthTexture(c.GL_TEXTURE3);
|
||||
|
||||
gpu_performance_measuring.startQuery(.transparent_rendering);
|
||||
c.glTextureBarrier();
|
||||
chunk.meshing.bindTransparentShaderAndUniforms(game.projectionMatrix, ambientLight, time);
|
||||
|
||||
c.glBlendEquationSeparate(c.GL_FUNC_ADD, c.GL_FUNC_ADD);
|
||||
@ -226,14 +230,20 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
fogShader.bind();
|
||||
// TODO: Draw the water fog if the player is underwater.
|
||||
|
||||
const playerBlock = RenderStructure.getBlock(@intFromFloat(@floor(playerPos[0])), @intFromFloat(@floor(playerPos[1])), @intFromFloat(@floor(playerPos[2]))) orelse blocks.Block{.typ = 0, .data = 0};
|
||||
|
||||
if(settings.bloom) {
|
||||
Bloom.render(lastWidth, lastHeight);
|
||||
Bloom.render(lastWidth, lastHeight, playerBlock);
|
||||
}
|
||||
gpu_performance_measuring.startQuery(.final_copy);
|
||||
worldFrameBuffer.unbind();
|
||||
worldFrameBuffer.bindTexture(c.GL_TEXTURE3);
|
||||
worldFrameBuffer.bindDepthTexture(c.GL_TEXTURE4);
|
||||
worldFrameBuffer.unbind();
|
||||
deferredRenderPassShader.bind();
|
||||
c.glUniform1i(deferredUniforms.color, 3);
|
||||
c.glUniform1i(deferredUniforms.depthTexture, 4);
|
||||
c.glUniform1i(deferredUniforms.blockType, playerBlock.typ);
|
||||
c.glUniform1f(deferredUniforms.nearPlane, zNear);
|
||||
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, activeFrameBuffer);
|
||||
|
||||
@ -264,13 +274,18 @@ const Bloom = struct {
|
||||
var secondPassShader: graphics.Shader = undefined;
|
||||
var colorExtractAndDownsampleShader: graphics.Shader = undefined;
|
||||
var upscaleShader: graphics.Shader = undefined;
|
||||
var colorExtractUniforms: struct {
|
||||
depthTexture: c_int,
|
||||
blockType: c_int,
|
||||
nearPlane: c_int,
|
||||
} = undefined;
|
||||
|
||||
pub fn init() !void {
|
||||
buffer1.init(false, c.GL_NEAREST, c.GL_CLAMP_TO_EDGE);
|
||||
buffer2.init(false, c.GL_NEAREST, c.GL_CLAMP_TO_EDGE);
|
||||
firstPassShader = try graphics.Shader.init("assets/cubyz/shaders/bloom/first_pass.vs", "assets/cubyz/shaders/bloom/first_pass.fs");
|
||||
secondPassShader = try graphics.Shader.init("assets/cubyz/shaders/bloom/second_pass.vs", "assets/cubyz/shaders/bloom/second_pass.fs");
|
||||
colorExtractAndDownsampleShader = try graphics.Shader.init("assets/cubyz/shaders/bloom/color_extractor_downsample.vs", "assets/cubyz/shaders/bloom/color_extractor_downsample.fs");
|
||||
colorExtractAndDownsampleShader = try graphics.Shader.initAndGetUniforms("assets/cubyz/shaders/bloom/color_extractor_downsample.vs", "assets/cubyz/shaders/bloom/color_extractor_downsample.fs", &colorExtractUniforms);
|
||||
upscaleShader = try graphics.Shader.init("assets/cubyz/shaders/bloom/upscale.vs", "assets/cubyz/shaders/bloom/upscale.fs");
|
||||
}
|
||||
|
||||
@ -282,10 +297,14 @@ const Bloom = struct {
|
||||
upscaleShader.deinit();
|
||||
}
|
||||
|
||||
fn extractImageDataAndDownsample() void {
|
||||
fn extractImageDataAndDownsample(playerBlock: blocks.Block) void {
|
||||
colorExtractAndDownsampleShader.bind();
|
||||
worldFrameBuffer.bindTexture(c.GL_TEXTURE3);
|
||||
worldFrameBuffer.bindDepthTexture(c.GL_TEXTURE4);
|
||||
buffer1.bind();
|
||||
c.glUniform1i(colorExtractUniforms.depthTexture, 4);
|
||||
c.glUniform1i(colorExtractUniforms.blockType, playerBlock.typ);
|
||||
c.glUniform1f(colorExtractUniforms.nearPlane, zNear);
|
||||
c.glBindVertexArray(graphics.draw.rectVAO);
|
||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
@ -314,7 +333,7 @@ const Bloom = struct {
|
||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
pub fn render(currentWidth: u31, currentHeight: u31) void {
|
||||
pub fn render(currentWidth: u31, currentHeight: u31, playerBlock: blocks.Block) void {
|
||||
if(width != currentWidth or height != currentHeight) {
|
||||
width = currentWidth;
|
||||
height = currentHeight;
|
||||
@ -326,9 +345,10 @@ const Bloom = struct {
|
||||
gpu_performance_measuring.startQuery(.bloom_extract_downsample);
|
||||
c.glDisable(c.GL_DEPTH_TEST);
|
||||
c.glDisable(c.GL_CULL_FACE);
|
||||
c.glDepthMask(c.GL_FALSE);
|
||||
|
||||
c.glViewport(0, 0, width/2, height/2);
|
||||
extractImageDataAndDownsample();
|
||||
extractImageDataAndDownsample(playerBlock);
|
||||
gpu_performance_measuring.stopQuery();
|
||||
gpu_performance_measuring.startQuery(.bloom_first_pass);
|
||||
firstPass();
|
||||
@ -341,6 +361,7 @@ const Bloom = struct {
|
||||
c.glBlendFunc(c.GL_ONE, c.GL_ONE);
|
||||
upscale();
|
||||
|
||||
c.glDepthMask(c.GL_TRUE);
|
||||
c.glEnable(c.GL_DEPTH_TEST);
|
||||
c.glEnable(c.GL_CULL_FACE);
|
||||
c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
Loading…
x
Reference in New Issue
Block a user