mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 11:17:05 -04:00
Fake reflections and transparency (both absorptive and regular transparency are possible)
This commit is contained in:
parent
7cb347ce3c
commit
5ca4ab6a9d
@ -1,48 +0,0 @@
|
||||
#version 430
|
||||
|
||||
in vec2 outTexCoord;
|
||||
flat in float textureIndex;
|
||||
in vec3 outColor;
|
||||
in vec3 mvVertexPos;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out vec4 position;
|
||||
|
||||
struct Fog {
|
||||
bool activ;
|
||||
vec3 color;
|
||||
float density;
|
||||
};
|
||||
|
||||
uniform sampler2DArray texture_sampler;
|
||||
uniform sampler2DArray emissionSampler;
|
||||
uniform Fog fog;
|
||||
uniform int selectedIndex;
|
||||
|
||||
vec4 ambientC;
|
||||
|
||||
void setupColors(vec3 textCoord) {
|
||||
ambientC = texture(texture_sampler, textCoord);
|
||||
}
|
||||
|
||||
vec4 calcFog(vec3 pos, vec4 color, Fog fog) {
|
||||
float distance = length(pos);
|
||||
float fogFactor = 1.0/exp((distance*fog.density)*(distance*fog.density));
|
||||
fogFactor = clamp(fogFactor, 0.0, 1.0);
|
||||
vec3 resultColor = mix(fog.color, color.xyz, fogFactor);
|
||||
return vec4(resultColor.xyz, color.w + 1 - fogFactor);
|
||||
}
|
||||
|
||||
void main() {
|
||||
setupColors(vec3(outTexCoord, textureIndex));
|
||||
if (ambientC.a != 1) discard;
|
||||
|
||||
fragColor = ambientC*vec4(outColor, 1);
|
||||
fragColor.rgb += texture(emissionSampler, vec3(outTexCoord, textureIndex)).rgb;
|
||||
|
||||
if (fog.activ) {
|
||||
fragColor = calcFog(mvVertexPos, fragColor, fog);
|
||||
}
|
||||
fragColor.rgb /= 4;
|
||||
position = vec4(mvVertexPos, 1);
|
||||
}
|
@ -3,11 +3,8 @@
|
||||
in vec3 mvVertexPos;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out vec4 position;
|
||||
|
||||
void main() {
|
||||
fragColor = vec4(0, 0, 0, 1);
|
||||
fragColor.rgb /= 4;
|
||||
|
||||
position = vec4(mvVertexPos, 1);
|
||||
}
|
||||
|
@ -1,49 +0,0 @@
|
||||
#version 430
|
||||
|
||||
layout (location=0) in vec3 position;
|
||||
layout (location=1) in vec3 texCoord;
|
||||
layout (location=2) in vec3 vertexNormal;
|
||||
layout (location=3) in int easyLight;
|
||||
|
||||
out vec2 outTexCoord;
|
||||
flat out float textureIndex;
|
||||
out vec3 mvVertexPos;
|
||||
out vec3 outColor;
|
||||
|
||||
uniform mat4 projectionMatrix;
|
||||
uniform vec3 ambientLight;
|
||||
uniform vec3 directionalLight;
|
||||
uniform mat4 viewMatrix;
|
||||
uniform vec3 modelPosition;
|
||||
|
||||
layout(std430, binding = 0) buffer _animationTimes
|
||||
{
|
||||
int animationTimes[];
|
||||
};
|
||||
layout(std430, binding = 1) buffer _animationFrames
|
||||
{
|
||||
int animationFrames[];
|
||||
};
|
||||
|
||||
uniform int time;
|
||||
|
||||
vec3 calcLight(int srgb) {
|
||||
float s = (srgb >> 24) & 255;
|
||||
float r = (srgb >> 16) & 255;
|
||||
float g = (srgb >> 8) & 255;
|
||||
float b = (srgb >> 0) & 255;
|
||||
s = s*(1 - dot(directionalLight, vertexNormal));
|
||||
r = max(s*ambientLight.x, r);
|
||||
g = max(s*ambientLight.y, g);
|
||||
b = max(s*ambientLight.z, b);
|
||||
return vec3(r, g, b);
|
||||
}
|
||||
|
||||
void main() {
|
||||
outColor = calcLight(easyLight)*0.003890625;
|
||||
vec4 mvPos = viewMatrix*vec4(position + modelPosition, 1);
|
||||
gl_Position = projectionMatrix*mvPos;
|
||||
outTexCoord = texCoord.xy;
|
||||
textureIndex = texCoord.z + time / animationTimes[int(texCoord.z)] % animationFrames[int(texCoord.z)];
|
||||
mvVertexPos = mvPos.xyz;
|
||||
}
|
@ -14,7 +14,6 @@ uniform sampler2DArray texture_sampler;
|
||||
uniform sampler2DArray emissionSampler;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out vec4 position;
|
||||
|
||||
struct Fog {
|
||||
bool activ;
|
||||
@ -205,13 +204,8 @@ void main() {
|
||||
ivec2 textureCoords = getTextureCoords(result.voxelPosition, result.textureDir);
|
||||
fragColor = mipMapSample(texture_sampler, textureCoords, textureIndex, lod)*vec4(ambientLight*normalVariation, 1);
|
||||
|
||||
if (fragColor.a <= 0.1f) fragColor.a = 1; // TODO: Proper alpha handling.
|
||||
if (fragColor.a < 1) discard;
|
||||
|
||||
if (fog.activ) {
|
||||
|
||||
// Underwater fog in lod(assumes that the fog is maximal):
|
||||
fragColor = vec4((1 - fragColor.a) * waterFog.color.xyz + fragColor.a * fragColor.xyz, 1);
|
||||
}
|
||||
fragColor.rgb += mipMapSample(emissionSampler, textureCoords, textureIndex, lod).rgb;
|
||||
|
||||
if (fog.activ) {
|
||||
@ -219,7 +213,6 @@ void main() {
|
||||
}
|
||||
if(!renderedToItemTexture) {
|
||||
fragColor.rgb /= 4;
|
||||
position = vec4(mvVertexPos, 1);
|
||||
}
|
||||
// TODO: Update the depth.
|
||||
}
|
||||
|
190
assets/cubyz/shaders/chunks/transparent_fragment.fs
Normal file
190
assets/cubyz/shaders/chunks/transparent_fragment.fs
Normal file
@ -0,0 +1,190 @@
|
||||
#version 430
|
||||
|
||||
in vec3 mvVertexPos;
|
||||
flat in int blockType;
|
||||
flat in int faceNormal;
|
||||
flat in int modelIndex;
|
||||
in vec3 startPosition;
|
||||
in vec3 direction;
|
||||
|
||||
uniform int time;
|
||||
uniform vec3 ambientLight;
|
||||
uniform sampler2DArray texture_sampler;
|
||||
uniform sampler2DArray emissionSampler;
|
||||
|
||||
layout (location = 0, index = 0) out vec4 fragColor;
|
||||
layout (location = 0, index = 1) out vec4 blendColor;
|
||||
|
||||
struct Fog {
|
||||
bool activ;
|
||||
vec3 color;
|
||||
float density;
|
||||
};
|
||||
|
||||
struct AnimationData {
|
||||
int frames;
|
||||
int time;
|
||||
};
|
||||
|
||||
layout(std430, binding = 0) buffer _animation
|
||||
{
|
||||
AnimationData animation[];
|
||||
};
|
||||
layout(std430, binding = 1) buffer _textureIndices
|
||||
{
|
||||
int textureIndices[][6];
|
||||
};
|
||||
|
||||
|
||||
const float[6] normalVariations = float[6](
|
||||
1.0, //vec3(0, 1, 0),
|
||||
0.84, //vec3(0, -1, 0),
|
||||
0.92, //vec3(1, 0, 0),
|
||||
0.92, //vec3(-1, 0, 0),
|
||||
0.96, //vec3(0, 0, 1),
|
||||
0.88 //vec3(0, 0, -1)
|
||||
);
|
||||
const vec3[6] normals = vec3[6](
|
||||
vec3(0, 1, 0),
|
||||
vec3(0, -1, 0),
|
||||
vec3(1, 0, 0),
|
||||
vec3(-1, 0, 0),
|
||||
vec3(0, 0, 1),
|
||||
vec3(0, 0, -1)
|
||||
);
|
||||
|
||||
|
||||
uniform Fog fog;
|
||||
uniform Fog waterFog; // TODO: Select fog from texture
|
||||
uniform bool renderedToItemTexture;
|
||||
|
||||
vec4 calcFog(vec3 pos, vec4 color, Fog fog) {
|
||||
float distance = length(pos);
|
||||
float fogFactor = 1.0/exp((distance*fog.density)*(distance*fog.density));
|
||||
fogFactor = clamp(fogFactor, 0.0, 1.0);
|
||||
vec4 resultColor = mix(vec4(fog.color, 1), color, fogFactor);
|
||||
return resultColor;
|
||||
}
|
||||
|
||||
ivec2 getTextureCoords(ivec3 voxelPosition, int textureDir) {
|
||||
switch(textureDir) {
|
||||
case 0:
|
||||
return ivec2(15 - voxelPosition.x, voxelPosition.z);
|
||||
case 1:
|
||||
return ivec2(voxelPosition.x, voxelPosition.z);
|
||||
case 2:
|
||||
return ivec2(15 - voxelPosition.z, voxelPosition.y);
|
||||
case 3:
|
||||
return ivec2(voxelPosition.z, voxelPosition.y);
|
||||
case 4:
|
||||
return ivec2(voxelPosition.x, voxelPosition.y);
|
||||
case 5:
|
||||
return ivec2(15 - voxelPosition.x, voxelPosition.y);
|
||||
}
|
||||
}
|
||||
|
||||
float getLod(ivec3 voxelPosition, int normal, vec3 direction, float variance) {
|
||||
return max(0, min(4, log2(variance*length(direction)/abs(dot(vec3(normals[normal]), direction)))));
|
||||
}
|
||||
|
||||
float perpendicularFwidth(vec3 direction) { // Estimates how big fwidth would be if the fragment normal was perpendicular to the light direction.
|
||||
vec3 variance = dFdx(direction);
|
||||
variance += direction;
|
||||
variance = variance*length(direction)/length(variance);
|
||||
variance -= direction;
|
||||
return 16*length(variance);
|
||||
}
|
||||
|
||||
vec4 mipMapSample(sampler2DArray texture, ivec2 textureCoords, int textureIndex, float lod) { // TODO: anisotropic filtering?
|
||||
int lowerLod = int(floor(lod));
|
||||
int higherLod = lowerLod+1;
|
||||
float interpolation = lod - lowerLod;
|
||||
vec4 lower = texelFetch(texture, ivec3(textureCoords >> lowerLod, textureIndex), lowerLod);
|
||||
vec4 higher = texelFetch(texture, ivec3(textureCoords >> higherLod, textureIndex), higherLod);
|
||||
return higher*interpolation + (1 - interpolation)*lower;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void main() {
|
||||
float variance = perpendicularFwidth(direction);
|
||||
int textureIndex = textureIndices[blockType][faceNormal];
|
||||
textureIndex = textureIndex + time / animation[textureIndex].time % animation[textureIndex].frames;
|
||||
float normalVariation = normalVariations[faceNormal];
|
||||
float lod = getLod(ivec3(startPosition), faceNormal, direction, variance);
|
||||
ivec2 textureCoords = getTextureCoords(ivec3(startPosition), faceNormal);
|
||||
fragColor = mipMapSample(texture_sampler, textureCoords, textureIndex, lod)*vec4(ambientLight*normalVariation, 1);
|
||||
|
||||
if (fragColor.a == 1) discard;
|
||||
|
||||
if (fog.activ) {
|
||||
// TODO: Underwater fog if possible.
|
||||
}
|
||||
blendColor = fragColor;
|
||||
fragColor.rgb = vec3(0);
|
||||
|
||||
if(fragColor.a < 1) {
|
||||
// Fake reflection:
|
||||
// TODO: Make the amount configurable.
|
||||
// TODO: Also allow this for opaque pixels.
|
||||
// TODO: Change this when it rains.
|
||||
// TODO: Normal mapping.
|
||||
// TODO: Allow textures to contribute to this term.
|
||||
fragColor.rgb += 0.1*vec3(snoise(normalize(reflect(direction, normals[faceNormal])))) + vec3(0.2);
|
||||
fragColor.a = 1;
|
||||
} else {
|
||||
fragColor.rgb += mipMapSample(emissionSampler, textureCoords, textureIndex, lod).rgb;
|
||||
}
|
||||
|
||||
if (fog.activ) {
|
||||
fragColor = calcFog(mvVertexPos, fragColor, fog);
|
||||
}
|
||||
if(!renderedToItemTexture) {
|
||||
fragColor.rgb /= 4;
|
||||
}
|
||||
// TODO: Update the depth.
|
||||
}
|
@ -4,7 +4,6 @@ out vec4 fragColor;
|
||||
in vec2 texCoords;
|
||||
|
||||
uniform sampler2D color;
|
||||
uniform sampler2D position;
|
||||
|
||||
void main() {
|
||||
fragColor = texture(color, texCoords);
|
||||
|
@ -13,7 +13,6 @@ struct Fog {
|
||||
uniform Fog fog;
|
||||
|
||||
uniform sampler2D color;
|
||||
uniform sampler2D position;
|
||||
|
||||
vec4 calcFog(vec3 pos, vec4 color, Fog fog) {
|
||||
float distance = length(pos);
|
||||
@ -24,6 +23,6 @@ vec4 calcFog(vec3 pos, vec4 color, Fog fog) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
fragColor = calcFog(texture(position, texCoords).xyz, texture(color, texCoords)*vec4(4, 4, 4, 1), fog);
|
||||
// TODO: Reconstruct position from the depth value. fragColor = calcFog(texture(position, texCoords).xyz, texture(color, texCoords)*vec4(4, 4, 4, 1), fog);
|
||||
fragColor.rgb /= 4;
|
||||
}
|
@ -10,7 +10,6 @@ flat in uvec3 lower;
|
||||
flat in uvec3 upper;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out vec4 position;
|
||||
|
||||
struct Fog {
|
||||
bool activ;
|
||||
@ -223,7 +222,6 @@ void mainBlockDrop() {
|
||||
fragColor = calcFog(startPosition, fragColor, fog);
|
||||
}
|
||||
fragColor.rgb /= 4;
|
||||
position = vec4(startPosition, 1);
|
||||
}
|
||||
|
||||
// itemDrops -------------------------------------------------------------------------------------------------------------------------
|
||||
@ -314,7 +312,6 @@ void mainItemDrop() {
|
||||
fragColor = calcFog(modifiedCameraSpacePos, color, fog);
|
||||
}
|
||||
fragColor.rgb /= 4;
|
||||
position = vec4(modifiedCameraSpacePos, 1);
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
@ -1,66 +0,0 @@
|
||||
#version 430
|
||||
|
||||
in vec2 outTexCoord;
|
||||
flat in float textureIndex;
|
||||
in vec3 outColor;
|
||||
in vec3 mvVertexPos;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out vec4 position;
|
||||
|
||||
struct Fog {
|
||||
bool activ;
|
||||
vec3 color;
|
||||
float density;
|
||||
};
|
||||
|
||||
uniform sampler2DArray texture_sampler;
|
||||
uniform sampler2DArray emissionSampler;
|
||||
uniform sampler2D break_sampler;
|
||||
uniform Fog fog;
|
||||
uniform Fog waterFog; // TODO: Select fog from texture
|
||||
uniform vec2 windowSize;
|
||||
uniform vec3 ambientLight;
|
||||
|
||||
uniform sampler2D positionBuffer;
|
||||
uniform sampler2D colorBuffer;
|
||||
uniform bool drawFrontFace;
|
||||
|
||||
vec4 ambientC;
|
||||
|
||||
void setupColors(vec3 textCoord) {
|
||||
ambientC = texture(texture_sampler, textCoord);
|
||||
}
|
||||
|
||||
vec4 calcFog(vec3 pos, vec4 color, Fog fog) {
|
||||
float distance = length(pos);
|
||||
float fogFactor = 1.0/exp((distance*fog.density)*(distance*fog.density));
|
||||
fogFactor = clamp(fogFactor, 0.0, 1.0);
|
||||
vec3 resultColor = mix(fog.color, color.xyz, fogFactor);
|
||||
return vec4(resultColor.xyz, color.w + 1 - fogFactor);
|
||||
}
|
||||
|
||||
void main() {
|
||||
setupColors(vec3(outTexCoord, textureIndex));
|
||||
if (ambientC.a == 1) discard;
|
||||
|
||||
fragColor = ambientC*vec4(outColor, 1);
|
||||
fragColor.rgb += texture(emissionSampler, vec3(outTexCoord, textureIndex)).rgb;
|
||||
|
||||
if (fog.activ) {
|
||||
fragColor = calcFog(mvVertexPos, fragColor, fog);
|
||||
|
||||
// Underwater fog:
|
||||
if (drawFrontFace) { // There is only fog betwen front and back face of the same volume.
|
||||
vec2 frameBufferPos = gl_FragCoord.xy/windowSize;
|
||||
vec4 oldColor = texture(colorBuffer, frameBufferPos);
|
||||
oldColor.rgb *= 4;
|
||||
vec3 oldPosition = texture(positionBuffer, frameBufferPos).xyz;
|
||||
oldColor = calcFog(oldPosition - mvVertexPos, oldColor, waterFog);
|
||||
fragColor = vec4((1 - fragColor.a) * oldColor.xyz + fragColor.a * fragColor.xyz, 1);
|
||||
}
|
||||
}
|
||||
fragColor.rgb /= 4;
|
||||
|
||||
position = vec4(mvVertexPos, 1);
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
#version 430
|
||||
|
||||
layout (location=0) in vec3 position;
|
||||
layout (location=1) in vec3 texCoord;
|
||||
layout (location=2) in vec3 vertexNormal;
|
||||
layout (location=3) in int easyLight;
|
||||
|
||||
out vec2 outTexCoord;
|
||||
flat out float textureIndex;
|
||||
out vec3 mvVertexPos;
|
||||
out vec3 outColor;
|
||||
|
||||
uniform mat4 projectionMatrix;
|
||||
uniform vec3 ambientLight;
|
||||
uniform vec3 directionalLight;
|
||||
uniform mat4 viewMatrix;
|
||||
uniform vec3 modelPosition;
|
||||
|
||||
layout(std430, binding = 0) buffer _animationTimes
|
||||
{
|
||||
int animationTimes[];
|
||||
};
|
||||
layout(std430, binding = 1) buffer _animationFrames
|
||||
{
|
||||
int animationFrames[];
|
||||
};
|
||||
|
||||
uniform int time;
|
||||
|
||||
vec3 calcLight(int srgb) {
|
||||
float s = (srgb >> 24) & 255;
|
||||
float r = (srgb >> 16) & 255;
|
||||
float g = (srgb >> 8) & 255;
|
||||
float b = (srgb >> 0) & 255;
|
||||
s = s*(1 - dot(directionalLight, vertexNormal));
|
||||
r = max(s*ambientLight.x, r);
|
||||
g = max(s*ambientLight.y, g);
|
||||
b = max(s*ambientLight.z, b);
|
||||
return vec3(r, g, b);
|
||||
}
|
||||
|
||||
void main() {
|
||||
outColor = calcLight(easyLight)*0.003890625;
|
||||
vec4 mvPos = viewMatrix*vec4(position + modelPosition, 1);
|
||||
gl_Position = projectionMatrix*mvPos;
|
||||
outTexCoord = texCoord.xy;
|
||||
textureIndex = texCoord.z + time / animationTimes[int(texCoord.z)] % animationFrames[int(texCoord.z)];
|
||||
mvVertexPos = mvPos.xyz;
|
||||
}
|
397
src/chunk.zig
397
src/chunk.zig
@ -368,6 +368,7 @@ pub const Chunk = struct {
|
||||
|
||||
pub const meshing = struct {
|
||||
var shader: Shader = undefined;
|
||||
var transparentShader: Shader = undefined;
|
||||
pub var uniforms: struct {
|
||||
projectionMatrix: c_int,
|
||||
viewMatrix: c_int,
|
||||
@ -387,6 +388,25 @@ pub const meshing = struct {
|
||||
voxelSize: c_int,
|
||||
renderedToItemTexture: c_int,
|
||||
} = undefined;
|
||||
pub var transparentUniforms: struct {
|
||||
projectionMatrix: c_int,
|
||||
viewMatrix: c_int,
|
||||
modelPosition: c_int,
|
||||
screenSize: c_int,
|
||||
ambientLight: c_int,
|
||||
@"fog.activ": c_int,
|
||||
@"fog.color": c_int,
|
||||
@"fog.density": c_int,
|
||||
texture_sampler: c_int,
|
||||
emissionSampler: c_int,
|
||||
@"waterFog.activ": c_int,
|
||||
@"waterFog.color": c_int,
|
||||
@"waterFog.density": c_int,
|
||||
time: c_int,
|
||||
visibilityMask: c_int,
|
||||
voxelSize: c_int,
|
||||
renderedToItemTexture: c_int,
|
||||
} = undefined;
|
||||
var vao: c_uint = undefined;
|
||||
var vbo: c_uint = undefined;
|
||||
var faces: std.ArrayList(u32) = undefined;
|
||||
@ -394,6 +414,7 @@ pub const meshing = struct {
|
||||
|
||||
pub fn init() !void {
|
||||
shader = try Shader.initAndGetUniforms("assets/cubyz/shaders/chunks/chunk_vertex.vs", "assets/cubyz/shaders/chunks/chunk_fragment.fs", &uniforms);
|
||||
transparentShader = try Shader.initAndGetUniforms("assets/cubyz/shaders/chunks/chunk_vertex.vs", "assets/cubyz/shaders/chunks/transparent_fragment.fs", &transparentUniforms);
|
||||
|
||||
var rawData: [6*3 << (3*chunkShift)]u32 = undefined; // 6 vertices per face, maximum 3 faces/block
|
||||
const lut = [_]u32{0, 1, 2, 2, 1, 3};
|
||||
@ -415,6 +436,7 @@ pub const meshing = struct {
|
||||
|
||||
pub fn deinit() void {
|
||||
shader.deinit();
|
||||
transparentShader.deinit();
|
||||
c.glDeleteVertexArrays(1, &vao);
|
||||
c.glDeleteBuffers(1, &vbo);
|
||||
faces.deinit();
|
||||
@ -444,6 +466,29 @@ pub const meshing = struct {
|
||||
c.glBindVertexArray(vao);
|
||||
}
|
||||
|
||||
pub fn bindTransparentShaderAndUniforms(projMatrix: Mat4f, ambient: Vec3f, time: u32) void {
|
||||
transparentShader.bind();
|
||||
|
||||
c.glUniform1i(transparentUniforms.@"fog.activ", if(game.fog.active) 1 else 0);
|
||||
c.glUniform3fv(transparentUniforms.@"fog.color", 1, @ptrCast(&game.fog.color));
|
||||
c.glUniform1f(transparentUniforms.@"fog.density", game.fog.density);
|
||||
|
||||
c.glUniformMatrix4fv(transparentUniforms.projectionMatrix, 1, c.GL_FALSE, @ptrCast(&projMatrix));
|
||||
|
||||
c.glUniform1i(transparentUniforms.texture_sampler, 0);
|
||||
c.glUniform1i(transparentUniforms.emissionSampler, 1);
|
||||
|
||||
c.glUniformMatrix4fv(transparentUniforms.viewMatrix, 1, c.GL_FALSE, @ptrCast(&game.camera.viewMatrix));
|
||||
|
||||
c.glUniform3f(transparentUniforms.ambientLight, ambient[0], ambient[1], ambient[2]);
|
||||
|
||||
c.glUniform1i(transparentUniforms.time, @as(u31, @truncate(time)));
|
||||
|
||||
c.glUniform1i(transparentUniforms.renderedToItemTexture, 0);
|
||||
|
||||
c.glBindVertexArray(vao);
|
||||
}
|
||||
|
||||
pub const FaceData = switch(@import("builtin").target.cpu.arch.endian()) {
|
||||
.Little => packed struct {
|
||||
position: u32,
|
||||
@ -455,94 +500,61 @@ pub const meshing = struct {
|
||||
},
|
||||
};
|
||||
|
||||
pub const ChunkMesh = struct {
|
||||
pos: ChunkPosition,
|
||||
size: i32,
|
||||
chunk: std.atomic.Atomic(?*Chunk),
|
||||
const PrimitiveMesh = struct {
|
||||
faces: std.ArrayList(FaceData),
|
||||
bufferAllocation: graphics.LargeBuffer.Allocation = .{.start = 0, .len = 0},
|
||||
coreCount: u31 = 0,
|
||||
neighborStart: [7]u31 = [_]u31{0} ** 7,
|
||||
vertexCount: u31 = 0,
|
||||
generated: bool = false,
|
||||
mutex: std.Thread.Mutex = std.Thread.Mutex{},
|
||||
visibilityMask: u8 = 0xff,
|
||||
|
||||
pub fn init(allocator: Allocator, pos: ChunkPosition) ChunkMesh {
|
||||
return ChunkMesh{
|
||||
.pos = pos,
|
||||
.size = chunkSize*pos.voxelSize,
|
||||
.faces = std.ArrayList(FaceData).init(allocator),
|
||||
.chunk = std.atomic.Atomic(?*Chunk).init(null),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *ChunkMesh) void {
|
||||
fn deinit(self: *PrimitiveMesh) void {
|
||||
faceBuffer.free(self.bufferAllocation) catch unreachable;
|
||||
self.faces.deinit();
|
||||
if(self.chunk.load(.Monotonic)) |ch| {
|
||||
main.globalAllocator.destroy(ch);
|
||||
}
|
||||
}
|
||||
|
||||
fn canBeSeenThroughOtherBlock(block: Block, other: Block, neighbor: u3) bool {
|
||||
const rotatedModel = blocks.meshes.model(block);
|
||||
const model = &models.voxelModels.items[rotatedModel.modelIndex];
|
||||
const freestandingModel = rotatedModel.modelIndex != models.fullCube and switch(rotatedModel.permutation.permuteNeighborIndex(neighbor)) {
|
||||
Neighbors.dirNegX => model.min[0] != 0,
|
||||
Neighbors.dirPosX => model.max[0] != 16,
|
||||
Neighbors.dirDown => model.min[1] != 0,
|
||||
Neighbors.dirUp => model.max[1] != 16,
|
||||
Neighbors.dirNegZ => model.min[2] != 0,
|
||||
Neighbors.dirPosZ => model.max[2] != 16,
|
||||
else => unreachable,
|
||||
};
|
||||
return block.typ != 0 and (
|
||||
freestandingModel
|
||||
or other.typ == 0
|
||||
or (!std.meta.eql(block, other) and other.viewThrough())
|
||||
or blocks.meshes.model(other).modelIndex != 0 // TODO: make this more strict to avoid overdraw.
|
||||
);
|
||||
}
|
||||
|
||||
pub fn regenerateMainMesh(self: *ChunkMesh, chunk: *Chunk) !void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
fn reset(self: *PrimitiveMesh) void {
|
||||
self.faces.clearRetainingCapacity();
|
||||
var n: u32 = 0;
|
||||
var x: u8 = 0;
|
||||
while(x < chunkSize): (x += 1) {
|
||||
var y: u8 = 0;
|
||||
while(y < chunkSize): (y += 1) {
|
||||
var z: u8 = 0;
|
||||
while(z < chunkSize): (z += 1) {
|
||||
const block = (&chunk.blocks)[getIndex(x, y, z)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
if(block.typ == 0) continue;
|
||||
// Check all neighbors:
|
||||
for(Neighbors.iterable) |i| {
|
||||
n += 1;
|
||||
const x2 = x + Neighbors.relX[i];
|
||||
const y2 = y + Neighbors.relY[i];
|
||||
const z2 = z + Neighbors.relZ[i];
|
||||
if(x2&chunkMask != x2 or y2&chunkMask != y2 or z2&chunkMask != z2) continue; // Neighbor is outside the chunk.
|
||||
const neighborBlock = (&chunk.blocks)[getIndex(x2, y2, z2)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
if(canBeSeenThroughOtherBlock(block, neighborBlock, i)) {
|
||||
try self.faces.append(constructFaceData(block, i, @intCast(x2), @intCast(y2), @intCast(z2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(self.chunk.load(.Monotonic)) |oldChunk| {
|
||||
main.globalAllocator.destroy(oldChunk);
|
||||
}
|
||||
self.chunk.store(chunk, .Monotonic);
|
||||
fn resetToCore(self: *PrimitiveMesh) void {
|
||||
self.faces.shrinkRetainingCapacity(self.coreCount);
|
||||
}
|
||||
|
||||
fn append(self: *PrimitiveMesh, face: FaceData) !void {
|
||||
try self.faces.append(face);
|
||||
}
|
||||
|
||||
fn updateCore(self: *PrimitiveMesh) void {
|
||||
self.coreCount = @intCast(self.faces.items.len);
|
||||
self.neighborStart = [_]u31{self.coreCount} ** 7;
|
||||
}
|
||||
|
||||
fn addFace(self: *ChunkMesh, faceData: FaceData, fromNeighborChunk: ?u3) !void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
fn startNeighbor(self: *PrimitiveMesh, neighbor: usize) void {
|
||||
self.neighborStart[neighbor] = @intCast(self.faces.items.len);
|
||||
}
|
||||
|
||||
fn replaceNeighbors(self: *PrimitiveMesh, neighbor: usize, additionalNeighborFaces: []FaceData) !void {
|
||||
var rangeStart = self.neighborStart[neighbor ^ 1];
|
||||
var rangeEnd = self.neighborStart[(neighbor ^ 1)+1];
|
||||
try self.faces.replaceRange(rangeStart, rangeEnd - rangeStart, additionalNeighborFaces);
|
||||
for(self.neighborStart[1+(neighbor ^ 1)..]) |*neighborStart| {
|
||||
neighborStart.* = neighborStart.* - (rangeEnd - rangeStart) + @as(u31, @intCast(additionalNeighborFaces.len));
|
||||
}
|
||||
try self.uploadData();
|
||||
}
|
||||
|
||||
fn finish(self: *PrimitiveMesh) !void {
|
||||
self.neighborStart[6] = @intCast(self.faces.items.len);
|
||||
try self.uploadData();
|
||||
}
|
||||
|
||||
fn uploadData(self: *PrimitiveMesh) !void {
|
||||
self.vertexCount = @intCast(6*self.faces.items.len);
|
||||
try faceBuffer.realloc(&self.bufferAllocation, @intCast(8*self.faces.items.len));
|
||||
faceBuffer.bufferSubData(self.bufferAllocation.start, FaceData, self.faces.items);
|
||||
}
|
||||
|
||||
fn addFace(self: *PrimitiveMesh, faceData: FaceData, fromNeighborChunk: ?u3) !void {
|
||||
var insertionIndex: u31 = undefined;
|
||||
if(fromNeighborChunk) |neighbor| {
|
||||
insertionIndex = self.neighborStart[neighbor];
|
||||
@ -559,8 +571,7 @@ pub const meshing = struct {
|
||||
try self.faces.insert(insertionIndex, faceData);
|
||||
}
|
||||
|
||||
fn removeFace(self: *ChunkMesh, faceData: FaceData, fromNeighborChunk: ?u3) void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
fn removeFace(self: *PrimitiveMesh, faceData: FaceData, fromNeighborChunk: ?u3) void {
|
||||
var searchStart: u32 = undefined;
|
||||
var searchEnd: u32 = undefined;
|
||||
if(fromNeighborChunk) |neighbor| {
|
||||
@ -586,8 +597,7 @@ pub const meshing = struct {
|
||||
@panic("Couldn't find the face to remove. This case is not handled.");
|
||||
}
|
||||
|
||||
fn changeFace(self: *ChunkMesh, oldFaceData: FaceData, newFaceData: FaceData, fromNeighborChunk: ?u3) void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
fn changeFace(self: *PrimitiveMesh, oldFaceData: FaceData, newFaceData: FaceData, fromNeighborChunk: ?u3) void {
|
||||
var searchRange: []FaceData = undefined;
|
||||
if(fromNeighborChunk) |neighbor| {
|
||||
searchRange = self.faces.items[self.neighborStart[neighbor]..self.neighborStart[neighbor+1]];
|
||||
@ -603,6 +613,140 @@ pub const meshing = struct {
|
||||
}
|
||||
std.log.err("Couldn't find the face to replace.", .{});
|
||||
}
|
||||
};
|
||||
|
||||
pub const ChunkMesh = struct {
|
||||
pos: ChunkPosition,
|
||||
size: i32,
|
||||
chunk: std.atomic.Atomic(?*Chunk),
|
||||
opaqueMesh: PrimitiveMesh,
|
||||
transparentMesh: PrimitiveMesh,
|
||||
generated: bool = false,
|
||||
mutex: std.Thread.Mutex = std.Thread.Mutex{},
|
||||
visibilityMask: u8 = 0xff,
|
||||
|
||||
pub fn init(allocator: Allocator, pos: ChunkPosition) ChunkMesh {
|
||||
return ChunkMesh{
|
||||
.pos = pos,
|
||||
.size = chunkSize*pos.voxelSize,
|
||||
.opaqueMesh = .{
|
||||
.faces = std.ArrayList(FaceData).init(allocator)
|
||||
},
|
||||
.transparentMesh = .{
|
||||
.faces = std.ArrayList(FaceData).init(allocator)
|
||||
},
|
||||
.chunk = std.atomic.Atomic(?*Chunk).init(null),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *ChunkMesh) void {
|
||||
self.opaqueMesh.deinit();
|
||||
self.transparentMesh.deinit();
|
||||
if(self.chunk.load(.Monotonic)) |ch| {
|
||||
main.globalAllocator.destroy(ch);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isEmpty(self: *const ChunkMesh) bool {
|
||||
return self.opaqueMesh.vertexCount == 0 and self.transparentMesh.vertexCount == 0;
|
||||
}
|
||||
|
||||
fn canBeSeenThroughOtherBlock(block: Block, other: Block, neighbor: u3) bool {
|
||||
const rotatedModel = blocks.meshes.model(block);
|
||||
const model = &models.voxelModels.items[rotatedModel.modelIndex];
|
||||
const freestandingModel = rotatedModel.modelIndex != models.fullCube and switch(rotatedModel.permutation.permuteNeighborIndex(neighbor)) {
|
||||
Neighbors.dirNegX => model.min[0] != 0,
|
||||
Neighbors.dirPosX => model.max[0] != 16,
|
||||
Neighbors.dirDown => model.min[1] != 0,
|
||||
Neighbors.dirUp => model.max[1] != 16,
|
||||
Neighbors.dirNegZ => model.min[2] != 0,
|
||||
Neighbors.dirPosZ => model.max[2] != 16,
|
||||
else => unreachable,
|
||||
};
|
||||
return block.typ != 0 and (
|
||||
freestandingModel
|
||||
or other.typ == 0
|
||||
or (!std.meta.eql(block, other) and other.viewThrough())
|
||||
or blocks.meshes.model(other).modelIndex != 0 // TODO: make this more strict to avoid overdraw.
|
||||
);
|
||||
}
|
||||
|
||||
pub fn regenerateMainMesh(self: *ChunkMesh, chunk: *Chunk) !void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
self.opaqueMesh.reset();
|
||||
self.transparentMesh.reset();
|
||||
var n: u32 = 0;
|
||||
var x: u8 = 0;
|
||||
while(x < chunkSize): (x += 1) {
|
||||
var y: u8 = 0;
|
||||
while(y < chunkSize): (y += 1) {
|
||||
var z: u8 = 0;
|
||||
while(z < chunkSize): (z += 1) {
|
||||
const block = (&chunk.blocks)[getIndex(x, y, z)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
if(block.typ == 0) continue;
|
||||
// Check all neighbors:
|
||||
for(Neighbors.iterable) |i| {
|
||||
n += 1;
|
||||
const x2 = x + Neighbors.relX[i];
|
||||
const y2 = y + Neighbors.relY[i];
|
||||
const z2 = z + Neighbors.relZ[i];
|
||||
if(x2&chunkMask != x2 or y2&chunkMask != y2 or z2&chunkMask != z2) continue; // Neighbor is outside the chunk.
|
||||
const neighborBlock = (&chunk.blocks)[getIndex(x2, y2, z2)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
if(canBeSeenThroughOtherBlock(block, neighborBlock, i)) {
|
||||
if(block.transparent()) {
|
||||
try self.transparentMesh.append(constructFaceData(block, i, @intCast(x2), @intCast(y2), @intCast(z2)));
|
||||
} else {
|
||||
try self.opaqueMesh.append(constructFaceData(block, i, @intCast(x2), @intCast(y2), @intCast(z2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(self.chunk.swap(chunk, .Monotonic)) |oldChunk| {
|
||||
main.globalAllocator.destroy(oldChunk);
|
||||
}
|
||||
self.transparentMesh.updateCore();
|
||||
self.opaqueMesh.updateCore();
|
||||
}
|
||||
|
||||
fn addFace(self: *ChunkMesh, faceData: FaceData, fromNeighborChunk: ?u3, transparent: bool) !void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
if(transparent) {
|
||||
try self.transparentMesh.addFace(faceData, fromNeighborChunk);
|
||||
} else {
|
||||
try self.opaqueMesh.addFace(faceData, fromNeighborChunk);
|
||||
}
|
||||
}
|
||||
|
||||
fn removeFace(self: *ChunkMesh, faceData: FaceData, fromNeighborChunk: ?u3, transparent: bool) void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
if(transparent) {
|
||||
self.transparentMesh.removeFace(faceData, fromNeighborChunk);
|
||||
} else {
|
||||
self.opaqueMesh.removeFace(faceData, fromNeighborChunk);
|
||||
}
|
||||
}
|
||||
|
||||
fn changeFace(self: *ChunkMesh, oldFaceData: FaceData, newFaceData: FaceData, fromNeighborChunk: ?u3, oldTransparent: bool, newTransparent: bool) !void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
if(oldTransparent) {
|
||||
if(newTransparent) {
|
||||
self.transparentMesh.changeFace(oldFaceData, newFaceData, fromNeighborChunk);
|
||||
} else {
|
||||
self.transparentMesh.removeFace(oldFaceData, fromNeighborChunk);
|
||||
try self.opaqueMesh.addFace(newFaceData, fromNeighborChunk);
|
||||
}
|
||||
} else {
|
||||
if(newTransparent) {
|
||||
self.opaqueMesh.removeFace(oldFaceData, fromNeighborChunk);
|
||||
try self.transparentMesh.addFace(newFaceData, fromNeighborChunk);
|
||||
} else {
|
||||
self.opaqueMesh.changeFace(oldFaceData, newFaceData, fromNeighborChunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateBlock(self: *ChunkMesh, _x: i32, _y: i32, _z: i32, newBlock: Block) !void { // TODO: Investigate bug when placing blocks.
|
||||
const x = _x & chunkMask;
|
||||
@ -635,22 +779,22 @@ pub const meshing = struct {
|
||||
if(canBeSeenThroughOtherBlock(oldBlock, neighborBlock, neighbor) != newVisibility) {
|
||||
if(newVisibility) { // Adding the face
|
||||
if(neighborMesh == self) {
|
||||
try self.addFace(newFaceData, null);
|
||||
try self.addFace(newFaceData, null, newBlock.transparent());
|
||||
} else {
|
||||
try neighborMesh.addFace(newFaceData, neighbor);
|
||||
try neighborMesh.addFace(newFaceData, neighbor, newBlock.transparent());
|
||||
}
|
||||
} else { // Removing the face
|
||||
if(neighborMesh == self) {
|
||||
self.removeFace(oldFaceData, null);
|
||||
self.removeFace(oldFaceData, null, oldBlock.transparent());
|
||||
} else {
|
||||
neighborMesh.removeFace(oldFaceData, neighbor);
|
||||
neighborMesh.removeFace(oldFaceData, neighbor, oldBlock.transparent());
|
||||
}
|
||||
}
|
||||
} else if(newVisibility) { // Changing the face
|
||||
if(neighborMesh == self) {
|
||||
self.changeFace(oldFaceData, newFaceData, null);
|
||||
try self.changeFace(oldFaceData, newFaceData, null, oldBlock.transparent(), newBlock.transparent());
|
||||
} else {
|
||||
neighborMesh.changeFace(oldFaceData, newFaceData, neighbor);
|
||||
try neighborMesh.changeFace(oldFaceData, newFaceData, neighbor, oldBlock.transparent(), newBlock.transparent());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -661,36 +805,34 @@ pub const meshing = struct {
|
||||
if(canBeSeenThroughOtherBlock(neighborBlock, oldBlock, neighbor ^ 1) != newVisibility) {
|
||||
if(newVisibility) { // Adding the face
|
||||
if(neighborMesh == self) {
|
||||
try self.addFace(newFaceData, null);
|
||||
try self.addFace(newFaceData, null, newBlock.transparent());
|
||||
} else {
|
||||
try self.addFace(newFaceData, neighbor);
|
||||
try self.addFace(newFaceData, neighbor, newBlock.transparent());
|
||||
}
|
||||
} else { // Removing the face
|
||||
if(neighborMesh == self) {
|
||||
self.removeFace(oldFaceData, null);
|
||||
self.removeFace(oldFaceData, null, oldBlock.transparent());
|
||||
} else {
|
||||
self.removeFace(oldFaceData, neighbor);
|
||||
self.removeFace(oldFaceData, neighbor, oldBlock.transparent());
|
||||
}
|
||||
}
|
||||
} else if(newVisibility) { // Changing the face
|
||||
if(neighborMesh == self) {
|
||||
self.changeFace(oldFaceData, newFaceData, null);
|
||||
try self.changeFace(oldFaceData, newFaceData, null, oldBlock.transparent(), newBlock.transparent());
|
||||
} else {
|
||||
self.changeFace(oldFaceData, newFaceData, neighbor);
|
||||
try self.changeFace(oldFaceData, newFaceData, neighbor, oldBlock.transparent(), newBlock.transparent());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(neighborMesh != self) try neighborMesh.uploadData();
|
||||
if(neighborMesh != self) {
|
||||
try neighborMesh.opaqueMesh.uploadData();
|
||||
try neighborMesh.transparentMesh.uploadData();
|
||||
}
|
||||
}
|
||||
self.chunk.load(.Monotonic).?.blocks[getIndex(x, y, z)] = newBlock;
|
||||
try self.uploadData();
|
||||
}
|
||||
|
||||
fn uploadData(self: *ChunkMesh) !void {
|
||||
self.vertexCount = @intCast(6*self.faces.items.len);
|
||||
try faceBuffer.realloc(&self.bufferAllocation, @intCast(8*self.faces.items.len));
|
||||
faceBuffer.bufferSubData(self.bufferAllocation.start, FaceData, self.faces.items);
|
||||
try self.opaqueMesh.uploadData();
|
||||
try self.transparentMesh.uploadData();
|
||||
}
|
||||
|
||||
pub inline fn constructFaceData(block: Block, normal: u32, x: u32, y: u32, z: u32) FaceData {
|
||||
@ -704,17 +846,21 @@ pub const meshing = struct {
|
||||
pub fn uploadDataAndFinishNeighbors(self: *ChunkMesh) !void {
|
||||
std.debug.assert(!self.mutex.tryLock()); // The mutex should be locked when calling this function.
|
||||
const chunk = self.chunk.load(.Monotonic) orelse return; // In the mean-time the mesh was discarded and recreated and all the data was lost.
|
||||
self.faces.shrinkRetainingCapacity(self.coreCount);
|
||||
self.opaqueMesh.resetToCore();
|
||||
self.transparentMesh.resetToCore();
|
||||
for(Neighbors.iterable) |neighbor| {
|
||||
self.neighborStart[neighbor] = @intCast(self.faces.items.len);
|
||||
self.opaqueMesh.startNeighbor(neighbor);
|
||||
self.transparentMesh.startNeighbor(neighbor);
|
||||
var nullNeighborMesh = renderer.RenderStructure.getNeighbor(self.pos, self.pos.voxelSize, neighbor);
|
||||
if(nullNeighborMesh) |neighborMesh| {
|
||||
std.debug.assert(neighborMesh != self);
|
||||
neighborMesh.mutex.lock();
|
||||
defer neighborMesh.mutex.unlock();
|
||||
if(neighborMesh.generated) {
|
||||
var additionalNeighborFaces = std.ArrayList(FaceData).init(main.threadAllocator);
|
||||
defer additionalNeighborFaces.deinit();
|
||||
var additionalNeighborFacesOpaque = std.ArrayList(FaceData).init(main.threadAllocator);
|
||||
defer additionalNeighborFacesOpaque.deinit();
|
||||
var additionalNeighborFacesTransparent = std.ArrayList(FaceData).init(main.threadAllocator);
|
||||
defer additionalNeighborFacesTransparent.deinit();
|
||||
var x3: u8 = if(neighbor & 1 == 0) @intCast(chunkMask) else 0;
|
||||
var x1: u8 = 0;
|
||||
while(x1 < chunkSize): (x1 += 1) {
|
||||
@ -742,20 +888,23 @@ pub const meshing = struct {
|
||||
var block = (&chunk.blocks)[getIndex(x, y, z)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
var otherBlock = (&neighborMesh.chunk.load(.Monotonic).?.blocks)[getIndex(otherX, otherY, otherZ)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
if(canBeSeenThroughOtherBlock(block, otherBlock, neighbor)) {
|
||||
try additionalNeighborFaces.append(constructFaceData(block, neighbor, otherX, otherY, otherZ));
|
||||
if(block.transparent()) {
|
||||
try additionalNeighborFacesTransparent.append(constructFaceData(block, neighbor, otherX, otherY, otherZ));
|
||||
} else {
|
||||
try additionalNeighborFacesOpaque.append(constructFaceData(block, neighbor, otherX, otherY, otherZ));
|
||||
}
|
||||
}
|
||||
if(canBeSeenThroughOtherBlock(otherBlock, block, neighbor ^ 1)) {
|
||||
try self.faces.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z));
|
||||
if(otherBlock.transparent()) {
|
||||
try self.transparentMesh.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z));
|
||||
} else {
|
||||
try self.opaqueMesh.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var rangeStart = neighborMesh.neighborStart[neighbor ^ 1];
|
||||
var rangeEnd = neighborMesh.neighborStart[(neighbor ^ 1)+1];
|
||||
try neighborMesh.faces.replaceRange(rangeStart, rangeEnd - rangeStart, additionalNeighborFaces.items);
|
||||
for(neighborMesh.neighborStart[1+(neighbor ^ 1)..]) |*neighborStart| {
|
||||
neighborStart.* = neighborStart.* - (rangeEnd - rangeStart) + @as(u31, @intCast(additionalNeighborFaces.items.len));
|
||||
}
|
||||
try neighborMesh.uploadData();
|
||||
try neighborMesh.opaqueMesh.replaceNeighbors(neighbor, additionalNeighborFacesOpaque.items);
|
||||
try neighborMesh.transparentMesh.replaceNeighbors(neighbor, additionalNeighborFacesTransparent.items);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -795,7 +944,11 @@ pub const meshing = struct {
|
||||
var block = (&chunk.blocks)[getIndex(x, y, z)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
var otherBlock = (&neighborMesh.chunk.load(.Monotonic).?.blocks)[getIndex(otherX, otherY, otherZ)]; // ← a temporary fix to a compiler performance bug. TODO: check if this was fixed.
|
||||
if(canBeSeenThroughOtherBlock(otherBlock, block, neighbor ^ 1)) {
|
||||
try self.faces.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z));
|
||||
if(otherBlock.transparent()) {
|
||||
try self.transparentMesh.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z));
|
||||
} else {
|
||||
try self.opaqueMesh.append(constructFaceData(otherBlock, neighbor ^ 1, x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -803,8 +956,8 @@ pub const meshing = struct {
|
||||
return error.LODMissing;
|
||||
}
|
||||
}
|
||||
self.neighborStart[6] = @intCast(self.faces.items.len);
|
||||
try self.uploadData();
|
||||
try self.opaqueMesh.finish();
|
||||
try self.transparentMesh.finish();
|
||||
self.generated = true;
|
||||
}
|
||||
|
||||
@ -812,7 +965,7 @@ pub const meshing = struct {
|
||||
if(!self.generated) {
|
||||
return;
|
||||
}
|
||||
if(self.vertexCount == 0) return;
|
||||
if(self.opaqueMesh.vertexCount == 0) return;
|
||||
c.glUniform3f(
|
||||
uniforms.modelPosition,
|
||||
@floatCast(@as(f64, @floatFromInt(self.pos.wx)) - playerPosition[0]),
|
||||
@ -821,7 +974,23 @@ pub const meshing = struct {
|
||||
);
|
||||
c.glUniform1i(uniforms.visibilityMask, self.visibilityMask);
|
||||
c.glUniform1i(uniforms.voxelSize, self.pos.voxelSize);
|
||||
c.glDrawElementsBaseVertex(c.GL_TRIANGLES, self.vertexCount, c.GL_UNSIGNED_INT, null, self.bufferAllocation.start/8*4);
|
||||
c.glDrawElementsBaseVertex(c.GL_TRIANGLES, self.opaqueMesh.vertexCount, c.GL_UNSIGNED_INT, null, self.opaqueMesh.bufferAllocation.start/8*4);
|
||||
}
|
||||
|
||||
pub fn renderTransparent(self: *ChunkMesh, playerPosition: Vec3d) void { // TODO: Transparency sorting
|
||||
if(!self.generated) {
|
||||
return;
|
||||
}
|
||||
if(self.transparentMesh.vertexCount == 0) return;
|
||||
c.glUniform3f(
|
||||
transparentUniforms.modelPosition,
|
||||
@floatCast(@as(f64, @floatFromInt(self.pos.wx)) - playerPosition[0]),
|
||||
@floatCast(@as(f64, @floatFromInt(self.pos.wy)) - playerPosition[1]),
|
||||
@floatCast(@as(f64, @floatFromInt(self.pos.wz)) - playerPosition[2])
|
||||
);
|
||||
c.glUniform1i(transparentUniforms.visibilityMask, self.visibilityMask);
|
||||
c.glUniform1i(transparentUniforms.voxelSize, self.pos.voxelSize);
|
||||
c.glDrawElementsBaseVertex(c.GL_TRIANGLES, self.transparentMesh.vertexCount, c.GL_UNSIGNED_INT, null, self.transparentMesh.bufferAllocation.start/8*4);
|
||||
}
|
||||
};
|
||||
};
|
@ -34,12 +34,10 @@ var fogUniforms: struct {
|
||||
fog_activ: c_int,
|
||||
fog_color: c_int,
|
||||
fog_density: c_int,
|
||||
position: c_int,
|
||||
color: c_int,
|
||||
} = undefined;
|
||||
var deferredRenderPassShader: graphics.Shader = undefined;
|
||||
var deferredUniforms: struct {
|
||||
position: c_int,
|
||||
color: c_int,
|
||||
} = undefined;
|
||||
|
||||
@ -66,20 +64,17 @@ pub fn deinit() void {
|
||||
const buffers = struct {
|
||||
var buffer: c_uint = undefined;
|
||||
var colorTexture: c_uint = undefined;
|
||||
var positionTexture: c_uint = undefined;
|
||||
var depthBuffer: c_uint = undefined;
|
||||
fn init() void {
|
||||
c.glGenFramebuffers(1, &buffer);
|
||||
c.glGenRenderbuffers(1, &depthBuffer);
|
||||
c.glGenTextures(1, &colorTexture);
|
||||
c.glGenTextures(1, &positionTexture);
|
||||
|
||||
updateBufferSize(Window.width, Window.height);
|
||||
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, buffer);
|
||||
|
||||
c.glFramebufferTexture2D(c.GL_FRAMEBUFFER, c.GL_COLOR_ATTACHMENT0, c.GL_TEXTURE_2D, colorTexture, 0);
|
||||
c.glFramebufferTexture2D(c.GL_FRAMEBUFFER, c.GL_COLOR_ATTACHMENT1, c.GL_TEXTURE_2D, positionTexture, 0);
|
||||
|
||||
c.glFramebufferRenderbuffer(c.GL_FRAMEBUFFER, c.GL_DEPTH_STENCIL_ATTACHMENT, c.GL_RENDERBUFFER, depthBuffer);
|
||||
|
||||
@ -90,7 +85,6 @@ const buffers = struct {
|
||||
c.glDeleteFramebuffers(1, &buffer);
|
||||
c.glDeleteRenderbuffers(1, &depthBuffer);
|
||||
c.glDeleteTextures(1, &colorTexture);
|
||||
c.glDeleteTextures(1, &positionTexture);
|
||||
}
|
||||
|
||||
fn regenTexture(texture: c_uint, internalFormat: c_int, format: c_uint, width: u31, height: u31) void {
|
||||
@ -105,13 +99,12 @@ const buffers = struct {
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, buffer);
|
||||
|
||||
regenTexture(colorTexture, c.GL_RGB10_A2, c.GL_RGB, width, height);
|
||||
regenTexture(positionTexture, c.GL_RGB16F, c.GL_RGB, width, height);
|
||||
|
||||
c.glBindRenderbuffer(c.GL_RENDERBUFFER, depthBuffer);
|
||||
c.glRenderbufferStorage(c.GL_RENDERBUFFER, c.GL_DEPTH24_STENCIL8, width, height);
|
||||
c.glBindRenderbuffer(c.GL_RENDERBUFFER, 0);
|
||||
|
||||
const attachments = [_]c_uint{c.GL_COLOR_ATTACHMENT0, c.GL_COLOR_ATTACHMENT1};
|
||||
const attachments = [_]c_uint{c.GL_COLOR_ATTACHMENT0};
|
||||
c.glDrawBuffers(attachments.len, &attachments);
|
||||
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0);
|
||||
@ -120,8 +113,6 @@ const buffers = struct {
|
||||
fn bindTextures() void {
|
||||
c.glActiveTexture(c.GL_TEXTURE3);
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, colorTexture);
|
||||
c.glActiveTexture(c.GL_TEXTURE4);
|
||||
c.glBindTexture(c.GL_TEXTURE_2D, positionTexture);
|
||||
}
|
||||
|
||||
fn bind() void {
|
||||
@ -270,7 +261,23 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
|
||||
try itemdrop.ItemDropRenderer.renderItemDrops(game.projectionMatrix, ambientLight, playerPos, time);
|
||||
|
||||
// // Render transparent chunk meshes:
|
||||
// Render transparent chunk meshes:
|
||||
|
||||
chunk.meshing.bindTransparentShaderAndUniforms(game.projectionMatrix, ambientLight, time);
|
||||
c.glUniform1i(chunk.meshing.transparentUniforms.@"waterFog.activ", if(waterFog.active) 1 else 0);
|
||||
c.glUniform3fv(chunk.meshing.transparentUniforms.@"waterFog.color", 1, @ptrCast(&waterFog.color));
|
||||
c.glUniform1f(chunk.meshing.transparentUniforms.@"waterFog.density", waterFog.density);
|
||||
|
||||
c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_SRC1_COLOR);
|
||||
{
|
||||
var i: usize = meshes.items.len;
|
||||
while(true) {
|
||||
if(i == 0) break;
|
||||
i -= 1;
|
||||
meshes.items[i].renderTransparent(playerPos);
|
||||
}
|
||||
}
|
||||
c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA);
|
||||
// NormalChunkMesh.bindTransparentShader(ambientLight, directionalLight.getDirection(), time);
|
||||
|
||||
buffers.bindTextures();
|
||||
@ -308,7 +315,6 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
// fogShader.setUniform(FogUniforms.loc_fog_color, waterFog.getColor());
|
||||
// fogShader.setUniform(FogUniforms.loc_fog_density, waterFog.getDensity());
|
||||
// glUniform1i(FogUniforms.loc_color, 3);
|
||||
// glUniform1i(FogUniforms.loc_position, 4);
|
||||
|
||||
// glBindVertexArray(Graphics.rectVAO);
|
||||
// glDisable(GL_DEPTH_TEST);
|
||||
@ -323,7 +329,6 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
buffers.bindTextures();
|
||||
deferredRenderPassShader.bind();
|
||||
c.glUniform1i(deferredUniforms.color, 3);
|
||||
c.glUniform1i(deferredUniforms.position, 4);
|
||||
|
||||
c.glBindFramebuffer(c.GL_FRAMEBUFFER, activeFrameBuffer);
|
||||
|
||||
@ -1097,7 +1102,7 @@ pub const RenderStructure = struct {
|
||||
@floatFromInt(size),
|
||||
@floatFromInt(size),
|
||||
@floatFromInt(size),
|
||||
}) and node.?.mesh.visibilityMask != 0 and node.?.mesh.vertexCount != 0) {
|
||||
}) and node.?.mesh.visibilityMask != 0 and !node.?.mesh.isEmpty()) {
|
||||
try meshes.append(&node.?.mesh);
|
||||
}
|
||||
if(lod+1 != storageLists.len and node.?.mesh.generated) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user