mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 11:17:05 -04:00
render block drops.
This commit is contained in:
parent
1a3c1e56c9
commit
c1fac3ff3e
@ -222,4 +222,5 @@ void main() {
|
||||
}
|
||||
fragColor.rgb /= 4;
|
||||
position = vec4(mvVertexPos, 1);
|
||||
// TODO: Update the depth.
|
||||
}
|
||||
|
@ -4,8 +4,10 @@ in vec3 startPosition;
|
||||
in vec3 direction;
|
||||
in vec3 cameraSpacePos;
|
||||
flat in int faceNormal;
|
||||
flat in uint voxelModel;
|
||||
flat in uvec3 size;
|
||||
flat in int voxelModel;
|
||||
flat in int blockType;
|
||||
flat in uvec3 lower;
|
||||
flat in uvec3 upper;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out vec4 position;
|
||||
@ -19,14 +21,10 @@ struct Fog {
|
||||
uniform vec3 ambientLight;
|
||||
uniform mat4 projectionMatrix;
|
||||
uniform float sizeScale;
|
||||
uniform int time;
|
||||
|
||||
uniform Fog fog;
|
||||
|
||||
layout(std430, binding = 2) buffer _voxelModels
|
||||
{
|
||||
uint voxelModels[];
|
||||
};
|
||||
|
||||
const float[6] normalVariations = float[6](
|
||||
1.0, //vec3(0, 1, 0),
|
||||
0.80, //vec3(0, -1, 0),
|
||||
@ -36,11 +34,6 @@ const float[6] normalVariations = float[6](
|
||||
0.85 //vec3(0, 0, -1)
|
||||
);
|
||||
|
||||
uint getVoxel(uvec3 pos) {
|
||||
uint index = (pos.x | pos.y*size.x)*size.z | pos.z;
|
||||
return voxelModels[voxelModel + index];
|
||||
}
|
||||
|
||||
vec4 calcFog(vec3 pos, vec4 color, Fog fog) {
|
||||
float distance = length(pos);
|
||||
float fogFactor = 1.0/exp((distance*fog.density)*(distance*fog.density));
|
||||
@ -49,11 +42,207 @@ vec4 calcFog(vec3 pos, vec4 color, Fog fog) {
|
||||
return vec4(resultColor.xyz, color.w + 1 - fogFactor);
|
||||
}
|
||||
|
||||
// blockDrops ------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
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)
|
||||
);
|
||||
|
||||
#define modelSize 16
|
||||
struct VoxelModel {
|
||||
ivec4 minimum;
|
||||
ivec4 maximum;
|
||||
uint bitPackedData[modelSize*modelSize*modelSize/8];
|
||||
};
|
||||
|
||||
struct AnimationData {
|
||||
int frames;
|
||||
int time;
|
||||
};
|
||||
|
||||
layout(std430, binding = 0) buffer _animation
|
||||
{
|
||||
AnimationData animation[];
|
||||
};
|
||||
layout(std430, binding = 1) buffer _textureIndices
|
||||
{
|
||||
int textureIndices[][6];
|
||||
};
|
||||
layout(std430, binding = 4) buffer _blockVoxelModels
|
||||
{
|
||||
VoxelModel blockVoxelModels[];
|
||||
};
|
||||
uniform sampler2DArray texture_sampler;
|
||||
uniform sampler2DArray emissionSampler;
|
||||
|
||||
int getVoxel(int voxelIndex) {
|
||||
voxelIndex = (voxelIndex & 0xf) | (voxelIndex>>1 & 0xf0) | (voxelIndex>>2 & 0xf00);
|
||||
int shift = 4*(voxelIndex & 7);
|
||||
int arrayIndex = voxelIndex >> 3;
|
||||
return (int(blockVoxelModels[voxelModel].bitPackedData[arrayIndex])>>shift & 15) - 6;
|
||||
}
|
||||
|
||||
struct RayMarchResult {
|
||||
bool hitAThing;
|
||||
int normal;
|
||||
int textureDir;
|
||||
ivec3 voxelPosition;
|
||||
};
|
||||
|
||||
RayMarchResult rayMarching(vec3 startPosition, vec3 direction) { // TODO: Mipmapped voxel models. (or maybe just remove them when they are far enough away?)
|
||||
// Branchless implementation of "A Fast Voxel Traversal Algorithm for Ray Tracing" http://www.cse.yorku.ca/~amana/research/grid.pdf
|
||||
vec3 step = sign(direction);
|
||||
vec3 stepInIndex = step*vec3(1 << 10, 1 << 5, 1);
|
||||
int overflowMask = 1<<14 | 1<<9 | 1<<4;
|
||||
vec3 t1 = (floor(startPosition) - startPosition)/direction;
|
||||
vec3 tDelta = 1/(direction);
|
||||
vec3 t2 = t1 + tDelta;
|
||||
tDelta = abs(tDelta);
|
||||
vec3 tMax = max(t1, t2) - tDelta;
|
||||
if(direction.x == 0) tMax.x = 1.0/0.0;
|
||||
if(direction.y == 0) tMax.y = 1.0/0.0;
|
||||
if(direction.z == 0) tMax.z = 1.0/0.0;
|
||||
|
||||
ivec3 voxelPos = ivec3(floor(startPosition));
|
||||
int voxelIndex = voxelPos.x<<10 | voxelPos.y<<5 | voxelPos.z; // Stores the position as 0b0xxxx0yyyy0zzzz
|
||||
|
||||
int lastNormal = faceNormal;
|
||||
int block = getVoxel(voxelIndex);
|
||||
float total_tMax = 0;
|
||||
|
||||
int size = 16;
|
||||
ivec3 sizeMask = ivec3(size - 1);
|
||||
int it = 0;
|
||||
while(block > 0 && it < 48) {
|
||||
it++;
|
||||
vec3 tNext = tMax + block*tDelta;
|
||||
total_tMax = min(tNext.x, min(tNext.y, tNext.z));
|
||||
vec3 missingSteps = floor((total_tMax - tMax)/tDelta + 0.00001);
|
||||
voxelIndex += int(dot(missingSteps, stepInIndex));
|
||||
tMax += missingSteps*tDelta;
|
||||
if((voxelIndex & overflowMask) != 0)
|
||||
return RayMarchResult(false, 0, 0, ivec3(0, 0, 0));
|
||||
block = getVoxel(voxelIndex);
|
||||
}
|
||||
if(total_tMax != 0) {
|
||||
if(tMax.x > tMax.y) {
|
||||
if(tMax.x > tMax.z) {
|
||||
lastNormal = 2 + (1 + int(step.x))/2;
|
||||
} else {
|
||||
lastNormal = 4 + (1 + int(step.z))/2;
|
||||
}
|
||||
} else {
|
||||
if(tMax.y > tMax.z) {
|
||||
lastNormal = 0 + (1 + int(step.y))/2;
|
||||
} else {
|
||||
lastNormal = 4 + (1 + int(step.z))/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
voxelPos.x = voxelIndex>>10 & 15;
|
||||
voxelPos.y = voxelIndex>>5 & 15;
|
||||
voxelPos.z = voxelIndex & 15;
|
||||
int textureDir = -block;
|
||||
if(textureDir == 6) textureDir = lastNormal;
|
||||
vec3 modifiedCameraSpacePos = cameraSpacePos*(1 + total_tMax*sizeScale*length(direction)/length(cameraSpacePos));
|
||||
vec4 projection = projectionMatrix*vec4(modifiedCameraSpacePos, 1);
|
||||
float depth = projection.z/projection.w;
|
||||
gl_FragDepth = ((gl_DepthRange.diff * depth) + gl_DepthRange.near + gl_DepthRange.far)/2.0;
|
||||
return RayMarchResult(true, lastNormal, textureDir, voxelPos);
|
||||
}
|
||||
|
||||
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 varianceX = dFdx(direction);
|
||||
vec3 varianceY = dFdx(direction);
|
||||
varianceX += direction;
|
||||
varianceX = varianceX*length(direction)/length(varianceX);
|
||||
varianceX -= direction;
|
||||
varianceY += direction;
|
||||
varianceY = varianceY*length(direction)/length(varianceY);
|
||||
varianceY -= direction;
|
||||
vec3 variance = abs(varianceX) + abs(varianceY);
|
||||
return 8*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;
|
||||
}
|
||||
|
||||
void mainBlockDrop() {
|
||||
RayMarchResult result;
|
||||
float variance = perpendicularFwidth(direction);
|
||||
if(variance <= 4.0) {
|
||||
result = rayMarching(startPosition, direction);
|
||||
} else {
|
||||
result = RayMarchResult(true, faceNormal, faceNormal, ivec3(startPosition)); // At some point it doesn't make sense to even draw the model.
|
||||
}
|
||||
if(!result.hitAThing) discard;
|
||||
int textureIndex = textureIndices[blockType][result.textureDir];
|
||||
textureIndex = textureIndex + time / animation[textureIndex].time % animation[textureIndex].frames;
|
||||
float normalVariation = normalVariations[result.normal];
|
||||
float lod = getLod(result.voxelPosition, result.normal, direction, variance);
|
||||
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.
|
||||
|
||||
fragColor.rgb += mipMapSample(emissionSampler, textureCoords, textureIndex, lod).rgb;
|
||||
|
||||
if (fog.activ) {
|
||||
fragColor = calcFog(startPosition, fragColor, fog);
|
||||
}
|
||||
fragColor.rgb /= 4;
|
||||
position = vec4(startPosition, 1);
|
||||
}
|
||||
|
||||
// itemDrops -------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
layout(std430, binding = 2) buffer _itemVoxelModels
|
||||
{
|
||||
uint itemVoxelModels[];
|
||||
};
|
||||
|
||||
uint getVoxel(uvec3 pos) {
|
||||
uint index = (pos.x | pos.y*upper.x)*upper.z | pos.z;
|
||||
return itemVoxelModels[voxelModel + index];
|
||||
}
|
||||
|
||||
vec4 decodeColor(uint block) {
|
||||
return vec4(block >> 16 & uint(255), block >> 8 & uint(255), block & uint(255), block >> 24 & uint(255))/255.0;
|
||||
}
|
||||
|
||||
void main() {
|
||||
void mainItemDrop() {
|
||||
// Implementation of "A Fast Voxel Traversal Algorithm for Ray Tracing" http://www.cse.yorku.ca/~amana/research/grid.pdf
|
||||
ivec3 step = ivec3(sign(direction));
|
||||
vec3 t1 = (floor(startPosition) - startPosition)/direction;
|
||||
@ -70,7 +259,7 @@ void main() {
|
||||
uint block = getVoxel(voxelPosition);
|
||||
float total_tMax = 0;
|
||||
|
||||
uvec3 sizeMask = size - 1;
|
||||
uvec3 sizeMask = upper - 1;
|
||||
|
||||
while(block == 0) {
|
||||
if(tMax.x < tMax.y) {
|
||||
@ -127,3 +316,11 @@ void main() {
|
||||
fragColor.rgb /= 4;
|
||||
position = vec4(modifiedCameraSpacePos, 1);
|
||||
}
|
||||
|
||||
void main() {
|
||||
if(blockType != 0) {
|
||||
mainBlockDrop();
|
||||
} else {
|
||||
mainItemDrop();
|
||||
}
|
||||
}
|
||||
|
@ -6,36 +6,59 @@ out vec3 startPosition;
|
||||
out vec3 direction;
|
||||
out vec3 cameraSpacePos;
|
||||
flat out int faceNormal;
|
||||
flat out uint voxelModel;
|
||||
flat out uvec3 size;
|
||||
flat out int voxelModel;
|
||||
flat out int blockType;
|
||||
flat out uvec3 lower;
|
||||
flat out uvec3 upper;
|
||||
|
||||
uniform mat4 projectionMatrix;
|
||||
uniform mat4 viewMatrix;
|
||||
uniform mat4 modelMatrix;
|
||||
uniform int modelIndex;
|
||||
uniform int block;
|
||||
uniform float sizeScale;
|
||||
|
||||
layout(std430, binding = 2) buffer _voxelModels
|
||||
layout(std430, binding = 2) buffer _itemVoxelModels
|
||||
{
|
||||
uint voxelModels[];
|
||||
uint itemVoxelModels[];
|
||||
};
|
||||
|
||||
#define modelSize 16
|
||||
struct VoxelModel {
|
||||
ivec4 minimum;
|
||||
ivec4 maximum;
|
||||
uint bitPackedData[modelSize*modelSize*modelSize/8];
|
||||
};
|
||||
|
||||
layout(std430, binding = 4) buffer _blockVoxelModels
|
||||
{
|
||||
VoxelModel blockVoxelModels[];
|
||||
};
|
||||
|
||||
void main() {
|
||||
int x = positionAndNormals >> 2 & 1;
|
||||
int y = positionAndNormals >> 1 & 1;
|
||||
int z = positionAndNormals >> 0 & 1;
|
||||
ivec3 pos = ivec3 (
|
||||
positionAndNormals >> 2 & 1,
|
||||
positionAndNormals >> 1 & 1,
|
||||
positionAndNormals >> 0 & 1
|
||||
);
|
||||
faceNormal = positionAndNormals >> 3;
|
||||
uint voxelModelIndex = modelIndex;
|
||||
size.x = voxelModels[voxelModelIndex++];
|
||||
size.y = voxelModels[voxelModelIndex++];
|
||||
size.z = voxelModels[voxelModelIndex++];
|
||||
int voxelModelIndex = modelIndex;
|
||||
bool isBlock = block != 0;
|
||||
if(isBlock) {
|
||||
lower = uvec3(blockVoxelModels[voxelModelIndex].minimum.xyz);
|
||||
upper = uvec3(blockVoxelModels[voxelModelIndex].maximum.xyz);
|
||||
} else {
|
||||
upper.x = itemVoxelModels[voxelModelIndex++];
|
||||
upper.y = itemVoxelModels[voxelModelIndex++];
|
||||
upper.z = itemVoxelModels[voxelModelIndex++];
|
||||
lower = uvec3(0);
|
||||
}
|
||||
voxelModel = voxelModelIndex;
|
||||
blockType = block;
|
||||
|
||||
startPosition.x = float(size.x)*0.999*x;
|
||||
startPosition.y = float(size.y)*0.999*y;
|
||||
startPosition.z = float(size.z)*0.999*z;
|
||||
startPosition = lower + vec3(upper)*0.999*pos;
|
||||
|
||||
vec4 worldSpace = modelMatrix*vec4(vec3(x*size.x, y*size.y, z*size.z)*sizeScale + sizeScale/2, 1);
|
||||
vec4 worldSpace = modelMatrix*vec4(pos*(upper - lower)*sizeScale + sizeScale/2, 1);
|
||||
direction = (transpose(mat3(modelMatrix))*worldSpace.xyz).xyz;
|
||||
|
||||
vec4 cameraSpace = viewMatrix*worldSpace;
|
||||
|
@ -1,6 +1,7 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const blocks = @import("blocks.zig");
|
||||
const chunk_zig = @import("chunk.zig");
|
||||
const Chunk = chunk_zig.Chunk;
|
||||
const game = @import("game.zig");
|
||||
@ -560,7 +561,11 @@ pub const ItemDropRenderer = struct {
|
||||
@"fog.color": c_int,
|
||||
@"fog.density": c_int,
|
||||
modelIndex: c_int,
|
||||
block: c_int,
|
||||
sizeScale: c_int,
|
||||
time: c_int,
|
||||
texture_sampler: c_int,
|
||||
emissionSampler: c_int,
|
||||
} = undefined;
|
||||
|
||||
var itemModelSSBO: graphics.SSBO = undefined;
|
||||
@ -738,8 +743,11 @@ pub const ItemDropRenderer = struct {
|
||||
return (try voxelModels.findOrCreate(compareObject, ItemVoxelModel.init)).index;
|
||||
}
|
||||
|
||||
pub fn renderItemDrops(projMatrix: Mat4f, ambientLight: Vec3f, playerPos: Vec3d) !void {
|
||||
pub fn renderItemDrops(projMatrix: Mat4f, ambientLight: Vec3f, playerPos: Vec3d, time: u32) !void {
|
||||
itemShader.bind();
|
||||
c.glUniform1i(itemUniforms.texture_sampler, 0);
|
||||
c.glUniform1i(itemUniforms.emissionSampler, 1);
|
||||
c.glUniform1i(itemUniforms.time, @truncate(u31, time));
|
||||
c.glUniform1i(itemUniforms.@"fog.activ", if(game.fog.active) 1 else 0);
|
||||
c.glUniform3fv(itemUniforms.@"fog.color", 1, @ptrCast([*c]const f32, &game.fog.color));
|
||||
c.glUniform1f(itemUniforms.@"fog.density", game.fog.density);
|
||||
@ -769,9 +777,17 @@ pub const ItemDropRenderer = struct {
|
||||
modelMatrix = modelMatrix.mul(Mat4f.rotationY(-rot[1]));
|
||||
modelMatrix = modelMatrix.mul(Mat4f.rotationZ(-rot[2]));
|
||||
c.glUniformMatrix4fv(itemUniforms.modelMatrix, 1, c.GL_FALSE, @ptrCast([*c]const f32, &modelMatrix));
|
||||
const index = try getModelIndex(item);
|
||||
c.glUniform1i(itemUniforms.modelIndex, index);
|
||||
|
||||
if(item == .baseItem and item.baseItem.block != null) {
|
||||
const blockType = item.baseItem.block.?;
|
||||
const block = blocks.Block{.typ = blockType, .data = 0};
|
||||
c.glUniform1i(itemUniforms.modelIndex, block.mode().model(block).modelIndex);
|
||||
c.glUniform1i(itemUniforms.block, blockType);
|
||||
} else {
|
||||
const index = try getModelIndex(item);
|
||||
c.glUniform1i(itemUniforms.modelIndex, index);
|
||||
c.glUniform1i(itemUniforms.block, 0);
|
||||
}
|
||||
c.glBindVertexArray(itemVAO);
|
||||
c.glDrawElements(c.GL_TRIANGLES, 36, c.GL_UNSIGNED_INT, null);
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
|
||||
entity.ClientEntityManager.render(game.projectionMatrix, ambientLight, .{1, 0.5, 0.25}, playerPos);
|
||||
|
||||
try itemdrop.ItemDropRenderer.renderItemDrops(game.projectionMatrix, ambientLight, playerPos);
|
||||
try itemdrop.ItemDropRenderer.renderItemDrops(game.projectionMatrix, ambientLight, playerPos, time);
|
||||
|
||||
// // Render transparent chunk meshes:
|
||||
// NormalChunkMesh.bindTransparentShader(ambientLight, directionalLight.getDirection(), time);
|
||||
|
Loading…
x
Reference in New Issue
Block a user