mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 03:06:55 -04:00
Improve performance by storing the noise-based fake reflection in a cube map
This commit is contained in:
parent
1951416317
commit
1a3a16c852
@ -12,6 +12,8 @@ uniform int time;
|
||||
uniform vec3 ambientLight;
|
||||
uniform sampler2DArray texture_sampler;
|
||||
uniform sampler2DArray emissionSampler;
|
||||
uniform samplerCube reflectionMap;
|
||||
uniform float reflectionMapSize;
|
||||
|
||||
layout(binding = 3) uniform sampler2D depthTexture;
|
||||
|
||||
@ -68,51 +70,6 @@ uniform float zFar;
|
||||
|
||||
uniform Fog fog;
|
||||
|
||||
ivec3 random3to3(ivec3 v) {
|
||||
v &= 15;
|
||||
ivec3 fac = ivec3(11248723, 105436839, 45399083);
|
||||
int seed = v.x*fac.x ^ v.y*fac.y ^ v.z*fac.z;
|
||||
v = seed*fac;
|
||||
return v;
|
||||
}
|
||||
|
||||
float snoise(vec3 v){ // TODO: Maybe use a cubemap.
|
||||
const vec2 C = vec2(1.0/6.0, 1.0/3.0);
|
||||
|
||||
// First corner
|
||||
vec3 i = floor(v + dot(v, C.yyy));
|
||||
vec3 x0 = v - i + dot(i, C.xxx);
|
||||
|
||||
// Other corners
|
||||
vec3 g = step(x0.yzx, x0.xyz);
|
||||
vec3 l = 1.0 - g;
|
||||
vec3 i1 = min(g.xyz, l.zxy);
|
||||
vec3 i2 = max(g.xyz, l.zxy);
|
||||
|
||||
// x0 = x0 - 0. + 0.0 * C
|
||||
vec3 x1 = x0 - i1 + 1.0*C.xxx;
|
||||
vec3 x2 = x0 - i2 + 2.0*C.xxx;
|
||||
vec3 x3 = x0 - 1. + 3.0*C.xxx;
|
||||
|
||||
// Get gradients:
|
||||
ivec3 rand = random3to3(ivec3(i));
|
||||
vec3 p0 = vec3(rand);
|
||||
|
||||
rand = random3to3((ivec3(i + i1)));
|
||||
vec3 p1 = vec3(rand);
|
||||
|
||||
rand = random3to3((ivec3(i + i2)));
|
||||
vec3 p2 = vec3(rand);
|
||||
|
||||
rand = random3to3((ivec3(i + 1)));
|
||||
vec3 p3 = vec3(rand);
|
||||
|
||||
// Mix final noise value
|
||||
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
|
||||
m = m*m;
|
||||
return 42.0*dot(m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)))/(1 << 31);
|
||||
}
|
||||
|
||||
vec3 unpackColor(uint color) {
|
||||
return vec3(
|
||||
color>>16 & 255u,
|
||||
@ -177,6 +134,15 @@ vec2 getTextureCoordsNormal(vec3 voxelPosition, int textureDir) {
|
||||
}
|
||||
}
|
||||
|
||||
vec4 fixedCubeMapLookup(vec3 v) { // Taken from http://the-witness.net/news/2012/02/seamless-cube-map-filtering/
|
||||
float M = max(max(abs(v.x), abs(v.y)), abs(v.z));
|
||||
float scale = (reflectionMapSize - 1)/reflectionMapSize;
|
||||
if (abs(v.x) != M) v.x *= scale;
|
||||
if (abs(v.y) != M) v.y *= scale;
|
||||
if (abs(v.z) != M) v.z *= scale;
|
||||
return texture(reflectionMap, v);
|
||||
}
|
||||
|
||||
void main() {
|
||||
int textureIndex = textureData[blockType].textureIndices[faceNormal];
|
||||
textureIndex = textureIndex + time / animation[textureIndex].time % animation[textureIndex].frames;
|
||||
@ -199,7 +165,7 @@ void main() {
|
||||
// TODO: Change this when it rains.
|
||||
// TODO: Normal mapping.
|
||||
// TODO: Allow textures to contribute to this term.
|
||||
textureColor.rgb += (textureData[blockType].reflectivity/2*vec3(snoise(normalize(reflect(direction, normals[faceNormal])))) + vec3(textureData[blockType].reflectivity))*ambientLight*normalVariation;
|
||||
textureColor.rgb += (textureData[blockType].reflectivity*fixedCubeMapLookup(reflect(direction, normals[faceNormal])).xyz)*ambientLight*normalVariation;
|
||||
textureColor.rgb += texture(emissionSampler, vec3(getTextureCoordsNormal(startPosition/16, faceNormal), textureIndex)).rgb;
|
||||
blendColor.rgb *= 1 - textureColor.a;
|
||||
textureColor.a = 1;
|
||||
|
62
assets/cubyz/shaders/fake_reflection.fs
Normal file
62
assets/cubyz/shaders/fake_reflection.fs
Normal file
@ -0,0 +1,62 @@
|
||||
#version 430
|
||||
|
||||
in vec3 coords;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform vec3 normalVector;
|
||||
uniform vec3 upVector;
|
||||
uniform vec3 rightVector;
|
||||
uniform float frequency;
|
||||
|
||||
ivec3 random3to3(ivec3 v) {
|
||||
v &= 15;
|
||||
ivec3 fac = ivec3(11248723, 105436839, 45399083);
|
||||
int seed = v.x*fac.x ^ v.y*fac.y ^ v.z*fac.z;
|
||||
v = seed*fac;
|
||||
return v;
|
||||
}
|
||||
|
||||
float snoise(vec3 v) {
|
||||
const vec2 C = vec2(1.0/6.0, 1.0/3.0);
|
||||
|
||||
// First corner
|
||||
vec3 i = floor(v + dot(v, C.yyy));
|
||||
vec3 x0 = v - i + dot(i, C.xxx);
|
||||
|
||||
// Other corners
|
||||
vec3 g = step(x0.yzx, x0.xyz);
|
||||
vec3 l = 1.0 - g;
|
||||
vec3 i1 = min(g.xyz, l.zxy);
|
||||
vec3 i2 = max(g.xyz, l.zxy);
|
||||
|
||||
// x0 = x0 - 0. + 0.0 * C
|
||||
vec3 x1 = x0 - i1 + 1.0*C.xxx;
|
||||
vec3 x2 = x0 - i2 + 2.0*C.xxx;
|
||||
vec3 x3 = x0 - 1. + 3.0*C.xxx;
|
||||
|
||||
// Get gradients:
|
||||
ivec3 rand = random3to3(ivec3(i));
|
||||
vec3 p0 = vec3(rand);
|
||||
|
||||
rand = random3to3((ivec3(i + i1)));
|
||||
vec3 p1 = vec3(rand);
|
||||
|
||||
rand = random3to3((ivec3(i + i2)));
|
||||
vec3 p2 = vec3(rand);
|
||||
|
||||
rand = random3to3((ivec3(i + 1)));
|
||||
vec3 p3 = vec3(rand);
|
||||
|
||||
// Mix final noise value
|
||||
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
|
||||
m = m*m;
|
||||
return 42.0*dot(m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)))/(1 << 31);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 position = normalize(coords);
|
||||
position = position.x*rightVector + position.y*upVector + position.z*normalVector;
|
||||
position *= frequency;
|
||||
fragColor = vec4(vec3(snoise(position)*0.5 + 0.5), 1);
|
||||
}
|
12
assets/cubyz/shaders/fake_reflection.vs
Normal file
12
assets/cubyz/shaders/fake_reflection.vs
Normal file
@ -0,0 +1,12 @@
|
||||
#version 430
|
||||
|
||||
layout (location=0) in vec2 inTexCoords;
|
||||
|
||||
out vec3 coords;
|
||||
|
||||
uniform float reflectionMapSize;
|
||||
|
||||
void main() {
|
||||
coords = vec3((inTexCoords*2 - vec2(1, 1))*(reflectionMapSize + 1)/reflectionMapSize, 1);
|
||||
gl_Position = vec4(inTexCoords*2 - vec2(1, 1), 0, 1);
|
||||
}
|
@ -397,6 +397,8 @@ pub const meshing = struct {
|
||||
@"fog.density": c_int,
|
||||
texture_sampler: c_int,
|
||||
emissionSampler: c_int,
|
||||
reflectionMap: c_int,
|
||||
reflectionMapSize: c_int,
|
||||
time: c_int,
|
||||
visibilityMask: c_int,
|
||||
voxelSize: c_int,
|
||||
@ -449,6 +451,8 @@ pub const meshing = struct {
|
||||
|
||||
c.glUniform1i(uniforms.texture_sampler, 0);
|
||||
c.glUniform1i(uniforms.emissionSampler, 1);
|
||||
c.glUniform1i(uniforms.reflectionMap, 2);
|
||||
c.glUniform1f(uniforms.reflectionMapSize, renderer.reflectionCubeMapSize);
|
||||
|
||||
c.glUniformMatrix4fv(uniforms.viewMatrix, 1, c.GL_FALSE, @ptrCast(&game.camera.viewMatrix));
|
||||
|
||||
@ -472,6 +476,8 @@ pub const meshing = struct {
|
||||
|
||||
c.glUniform1i(transparentUniforms.texture_sampler, 0);
|
||||
c.glUniform1i(transparentUniforms.emissionSampler, 1);
|
||||
c.glUniform1i(transparentUniforms.reflectionMap, 2);
|
||||
c.glUniform1f(transparentUniforms.reflectionMapSize, renderer.reflectionCubeMapSize);
|
||||
|
||||
c.glUniformMatrix4fv(transparentUniforms.viewMatrix, 1, c.GL_FALSE, @ptrCast(&game.camera.viewMatrix));
|
||||
|
||||
|
102
src/graphics.zig
102
src/graphics.zig
@ -6,12 +6,13 @@ const std = @import("std");
|
||||
const freetype = @import("freetype");
|
||||
const harfbuzz = @import("harfbuzz");
|
||||
|
||||
const Mat4f = @import("vec.zig").Mat4f;
|
||||
const Vec4i = @import("vec.zig").Vec4i;
|
||||
const Vec4f = @import("vec.zig").Vec4f;
|
||||
const Vec2f = @import("vec.zig").Vec2f;
|
||||
const Vec2i = @import("vec.zig").Vec2i;
|
||||
const Vec3f = @import("vec.zig").Vec3f;
|
||||
const vec = @import("vec.zig");
|
||||
const Mat4f = vec.Mat4f;
|
||||
const Vec4i = vec.Vec4i;
|
||||
const Vec4f = vec.Vec4f;
|
||||
const Vec2f = vec.Vec2f;
|
||||
const Vec2i = vec.Vec2i;
|
||||
const Vec3f = vec.Vec3f;
|
||||
|
||||
const main = @import("main.zig");
|
||||
const Window = main.Window;
|
||||
@ -1323,7 +1324,7 @@ pub const FrameBuffer = struct {
|
||||
c.glClear(c.GL_COLOR_BUFFER_BIT | c.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
pub fn validate(self: *FrameBuffer) bool {
|
||||
pub fn validate(self: *const FrameBuffer) bool {
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, self.frameBuffer);
|
||||
defer c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0);
|
||||
if(c.glCheckFramebufferStatus(c.GL_FRAMEBUFFER) != c.GL_FRAMEBUFFER_COMPLETE) {
|
||||
@ -1333,22 +1334,22 @@ pub const FrameBuffer = struct {
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn bindTexture(self: *FrameBuffer, target: c_uint) void {
|
||||
pub fn bindTexture(self: *const FrameBuffer, target: c_uint) void {
|
||||
c.glActiveTexture(target);
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, self.texture);
|
||||
}
|
||||
|
||||
pub fn bindDepthTexture(self: *FrameBuffer, target: c_uint) void {
|
||||
pub fn bindDepthTexture(self: *const FrameBuffer, target: c_uint) void {
|
||||
std.debug.assert(self.hasDepthTexture);
|
||||
c.glActiveTexture(target);
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, self.depthTexture);
|
||||
}
|
||||
|
||||
pub fn bind(self: *FrameBuffer) void {
|
||||
pub fn bind(self: *const FrameBuffer) void {
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, self.frameBuffer);
|
||||
}
|
||||
|
||||
pub fn unbind(_: *FrameBuffer) void {
|
||||
pub fn unbind(_: *const FrameBuffer) void {
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
};
|
||||
@ -1533,6 +1534,85 @@ pub const Texture = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const CubeMapTexture = struct {
|
||||
textureID: c_uint,
|
||||
|
||||
pub fn init() CubeMapTexture {
|
||||
var self: CubeMapTexture = undefined;
|
||||
c.glGenTextures(1, &self.textureID);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: CubeMapTexture) void {
|
||||
c.glDeleteTextures(1, &self.textureID);
|
||||
}
|
||||
|
||||
pub fn bindTo(self: CubeMapTexture, binding: u5) void {
|
||||
c.glActiveTexture(@intCast(c.GL_TEXTURE0 + binding));
|
||||
c.glBindTexture(c.GL_TEXTURE_CUBE_MAP, self.textureID);
|
||||
}
|
||||
|
||||
pub fn bind(self: CubeMapTexture) void {
|
||||
c.glBindTexture(c.GL_TEXTURE_CUBE_MAP, self.textureID);
|
||||
}
|
||||
|
||||
/// (Re-)Generates the GPU buffer.
|
||||
pub fn generate(self: CubeMapTexture, width: u31, height: u31) void {
|
||||
self.bind();
|
||||
|
||||
c.glTexImage2D(c.GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, c.GL_RGBA8, width, height, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, null);
|
||||
c.glTexImage2D(c.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, c.GL_RGBA8, width, height, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, null);
|
||||
c.glTexImage2D(c.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, c.GL_RGBA8, width, height, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, null);
|
||||
c.glTexImage2D(c.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, c.GL_RGBA8, width, height, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, null);
|
||||
c.glTexImage2D(c.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, c.GL_RGBA8, width, height, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, null);
|
||||
c.glTexImage2D(c.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, c.GL_RGBA8, width, height, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, null);
|
||||
c.glTexParameteri(c.GL_TEXTURE_CUBE_MAP, c.GL_TEXTURE_MIN_FILTER, c.GL_LINEAR);
|
||||
c.glTexParameteri(c.GL_TEXTURE_CUBE_MAP, c.GL_TEXTURE_MAG_FILTER, c.GL_LINEAR);
|
||||
c.glTexParameteri(c.GL_TEXTURE_CUBE_MAP, c.GL_TEXTURE_WRAP_S, c.GL_CLAMP_TO_EDGE);
|
||||
c.glTexParameteri(c.GL_TEXTURE_CUBE_MAP, c.GL_TEXTURE_WRAP_T, c.GL_CLAMP_TO_EDGE);
|
||||
c.glTexParameteri(c.GL_TEXTURE_CUBE_MAP, c.GL_TEXTURE_WRAP_R, c.GL_CLAMP_TO_EDGE);
|
||||
c.glTexParameteri(c.GL_TEXTURE_CUBE_MAP, c.GL_TEXTURE_BASE_LEVEL, 0);
|
||||
c.glTexParameteri(c.GL_TEXTURE_CUBE_MAP, c.GL_TEXTURE_MAX_LEVEL, 0);
|
||||
}
|
||||
|
||||
pub fn faceNormal(face: usize) Vec3f {
|
||||
const normals = [_]Vec3f {
|
||||
.{ 1, 0, 0}, // +x
|
||||
.{-1, 0, 0}, // -x
|
||||
.{0, 1, 0}, // +y
|
||||
.{0, -1, 0}, // -y
|
||||
.{0, 0, 1}, // +z
|
||||
.{0, 0, -1}, // -z
|
||||
};
|
||||
return normals[face];
|
||||
}
|
||||
|
||||
pub fn faceUp(face: usize) Vec3f {
|
||||
const ups = [_]Vec3f {
|
||||
.{0, -1, 0}, // +x
|
||||
.{0, -1, 0}, // -x
|
||||
.{0, 0, 1}, // +y
|
||||
.{0, 0, -1}, // -y
|
||||
.{0, -1, 0}, // +z
|
||||
.{0, -1, 0}, // -z
|
||||
};
|
||||
return ups[face];
|
||||
}
|
||||
|
||||
pub fn faceRight(face: usize) Vec3f {
|
||||
comptime var rights: [6]Vec3f = undefined;
|
||||
inline for(0..6) |i| {
|
||||
rights[i] = comptime vec.cross(faceNormal(i), faceUp(i));
|
||||
}
|
||||
return rights[face];
|
||||
}
|
||||
|
||||
pub fn bindToFramebuffer(self: CubeMapTexture, fb: FrameBuffer, face: c_uint) void {
|
||||
fb.bind();
|
||||
c.glFramebufferTexture2D(c.GL_FRAMEBUFFER, c.GL_COLOR_ATTACHMENT0, @as(c_uint, c.GL_TEXTURE_CUBE_MAP_POSITIVE_X) + face, self.textureID, 0);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Color = extern struct {
|
||||
r: u8,
|
||||
g: u8,
|
||||
|
@ -40,24 +40,62 @@ var deferredUniforms: struct {
|
||||
zNear: c_int,
|
||||
zFar: c_int,
|
||||
} = undefined;
|
||||
var fakeReflectionShader: graphics.Shader = undefined;
|
||||
var fakeReflectionUniforms: struct {
|
||||
normalVector: c_int,
|
||||
upVector: c_int,
|
||||
rightVector: c_int,
|
||||
frequency: c_int,
|
||||
reflectionMapSize: c_int,
|
||||
} = undefined;
|
||||
|
||||
pub var activeFrameBuffer: c_uint = 0;
|
||||
|
||||
pub const reflectionCubeMapSize = 64;
|
||||
var reflectionCubeMap: graphics.CubeMapTexture = undefined;
|
||||
|
||||
pub fn init() !void {
|
||||
deferredRenderPassShader = try Shader.initAndGetUniforms("assets/cubyz/shaders/deferred_render_pass.vs", "assets/cubyz/shaders/deferred_render_pass.fs", &deferredUniforms);
|
||||
fakeReflectionShader = try Shader.initAndGetUniforms("assets/cubyz/shaders/fake_reflection.vs", "assets/cubyz/shaders/fake_reflection.fs", &fakeReflectionUniforms);
|
||||
worldFrameBuffer.init(true, c.GL_NEAREST, c.GL_CLAMP_TO_EDGE);
|
||||
worldFrameBuffer.updateSize(Window.width, Window.height, c.GL_RGBA16F);
|
||||
try Bloom.init();
|
||||
try MeshSelection.init();
|
||||
try MenuBackGround.init();
|
||||
reflectionCubeMap = graphics.CubeMapTexture.init();
|
||||
reflectionCubeMap.generate(reflectionCubeMapSize, reflectionCubeMapSize);
|
||||
initReflectionCubeMap();
|
||||
}
|
||||
|
||||
pub fn deinit() void {
|
||||
deferredRenderPassShader.deinit();
|
||||
fakeReflectionShader.deinit();
|
||||
worldFrameBuffer.deinit();
|
||||
Bloom.deinit();
|
||||
MeshSelection.deinit();
|
||||
MenuBackGround.deinit();
|
||||
reflectionCubeMap.deinit();
|
||||
}
|
||||
|
||||
fn initReflectionCubeMap() void {
|
||||
c.glViewport(0, 0, reflectionCubeMapSize, reflectionCubeMapSize);
|
||||
var framebuffer: graphics.FrameBuffer = undefined;
|
||||
framebuffer.init(false, c.GL_LINEAR, c.GL_CLAMP_TO_EDGE);
|
||||
defer framebuffer.deinit();
|
||||
framebuffer.bind();
|
||||
fakeReflectionShader.bind();
|
||||
c.glUniform1f(fakeReflectionUniforms.frequency, 1);
|
||||
c.glUniform1f(fakeReflectionUniforms.reflectionMapSize, reflectionCubeMapSize);
|
||||
for(0..6) |face| {
|
||||
c.glUniform3fv(fakeReflectionUniforms.normalVector, 1, @ptrCast(&graphics.CubeMapTexture.faceNormal(face)));
|
||||
c.glUniform3fv(fakeReflectionUniforms.upVector, 1, @ptrCast(&graphics.CubeMapTexture.faceUp(face)));
|
||||
c.glUniform3fv(fakeReflectionUniforms.rightVector, 1, @ptrCast(&graphics.CubeMapTexture.faceRight(face)));
|
||||
reflectionCubeMap.bindToFramebuffer(framebuffer, @intCast(face));
|
||||
c.glBindVertexArray(graphics.draw.rectVAO);
|
||||
c.glDisable(c.GL_DEPTH_TEST);
|
||||
c.glDisable(c.GL_CULL_FACE);
|
||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
var worldFrameBuffer: graphics.FrameBuffer = undefined;
|
||||
@ -138,6 +176,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
// Update the uniforms. The uniforms are needed to render the replacement meshes.
|
||||
chunk.meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight, time);
|
||||
|
||||
reflectionCubeMap.bindTo(2);
|
||||
c.glActiveTexture(c.GL_TEXTURE0);
|
||||
blocks.meshes.blockTextureArray.bind();
|
||||
c.glActiveTexture(c.GL_TEXTURE1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user