diff --git a/TODO.md b/TODO.md index 5d0ec96..ccaebcf 100644 --- a/TODO.md +++ b/TODO.md @@ -29,7 +29,7 @@ - [~] Occlusion Culling - [ ] Iterator ray - [ ] Cast from chunk center - - [ ] Transparency + - [x] Transparency - [ ] Entities ## Hello universe @@ -64,6 +64,7 @@ ## Hello darkness - [ ] Slash screen + - [ ] Start/Pause menu - [ ] QUIC protocal - [ ] Use in memory protocol (to replace server_handle) - [ ] Octree @@ -88,3 +89,5 @@ - [ ] Deferred - [ ] Cascaded shadow maps - [ ] Ray Tracing + - [ ] Translucency + - Back face Depth based diff --git a/resource/content/shaders/Voxel.fs b/resource/content/shaders/Voxel.fs index 6070f7e..76be3be 100644 --- a/resource/content/shaders/Voxel.fs +++ b/resource/content/shaders/Voxel.fs @@ -3,7 +3,7 @@ #define UNIT_SIZE 8 // Ouput data -layout(location = 0) out vec3 color; +layout(location = 0) out vec4 color; uniform sampler2DArray TextureAtlas; uniform sampler2DArray NormalAtlas; @@ -107,10 +107,10 @@ vec4 getTexture(sampler2DArray sample, vec2 UV) { #endif } -vec3 getTriTexture(sampler2DArray sample, vec2 crdx, vec2 crdy, vec2 crdz, vec3 weights) { - return getTexture(sample, crdx).rgb * weights.x + - getTexture(sample, crdy).rgb * weights.y + - getTexture(sample, crdz).rgb * weights.z; +vec4 getTriTexture(sampler2DArray sample, vec2 crdx, vec2 crdy, vec2 crdz, vec3 weights) { + return getTexture(sample, crdx) * weights.x + + getTexture(sample, crdy) * weights.y + + getTexture(sample, crdz) * weights.z; } void main() { @@ -127,7 +127,7 @@ void main() { vec2 UVy = vs.Position_modelspace.zx * texScale; vec2 UVz = vs.Position_modelspace.xy * texScale; - vec3 tex = getTriTexture(TextureAtlas, UVx, UVy, UVz, blendWeights); + vec4 tex = getTriTexture(TextureAtlas, UVx, UVy, UVz, blendWeights); #ifdef PBR // Whiteout normal blend @@ -141,7 +141,7 @@ void main() { // Swizzle tangent normals to match world orientation and triblend vec3 worldNormal = normalize(texNx.zyx * blendWeights.x + texNy.xzy * blendWeights.y +texNz.xyz * blendWeights.z); - vec3 texHOS = getTriTexture(HOSAtlas, UVx, UVy, UVz, blendWeights); + vec3 texHOS = getTriTexture(HOSAtlas, UVx, UVy, UVz, blendWeights).rgb; #endif #else // Cheap planar @@ -149,7 +149,7 @@ void main() { vec3 nrm = normalize(pow(blendWeights, vec3(80 / sqrt(UNIT_SIZE)))); vec2 UV = (vec2(vs.Position_modelspace.xy * nrm.z) + vec2(vs.Position_modelspace.yz * nrm.x) + vec2(vs.Position_modelspace.zx * nrm.y)) * texScale; - vec3 tex = getTexture(TextureAtlas, UV).rgb; + vec4 tex = getTexture(TextureAtlas, UV); #ifdef PBR vec3 texN = expand(getTexture(NormalAtlas, UV).rgb); // Swizzle world normals into tangent space and apply Whiteout blend @@ -165,7 +165,7 @@ void main() { // Colors #ifdef PBR // Texture properties - vec3 TextureDiffuseColor = tex; + vec3 TextureDiffuseColor = vec3(tex); vec3 TextureAmbientColor = vec3(.1) * TextureDiffuseColor * texHOS.y; vec3 TextureSpecularColor = vec3(.8) * texHOS.z; @@ -202,22 +202,21 @@ void main() { // MAYBE: shadow - color = + color = vec4( // Ambient : simulates indirect lighting TextureAmbientColor + // Diffuse : "color" of the object visibility * TextureDiffuseColor * LightColor * LightPower * cosTheta / (distance * distance) + // Specular : reflective highlight, like a mirror - visibility * TextureSpecularColor * LightColor * LightPower * pow(cosAlpha,5) / (distance * distance); + visibility * TextureSpecularColor * LightColor * LightPower * pow(cosAlpha,5) / (distance * distance), + // Restore alpha + tex.a); #else color = tex; #endif #if FOG float ratio = exp(vs.Depth * 0.69)-1; - color = mix(color, pow(FogColor, vec3(2.2)), clamp(ratio, 0, 1)); + color = mix(color, vec4(pow(FogColor, vec3(2.2)), 1), clamp(ratio, 0, 1)); #endif - color = pow(color, vec3(1.0 / 2.2)); - if(color.r > 1 || color.g > 1 || color.b > 1) { - color = vec3(1, 0, 0); //TODO: bloom - } + color = pow(color, vec4(vec3(1.0 / 2.2), 1)); } \ No newline at end of file diff --git a/resource/content/shaders/Voxel.fs.spv b/resource/content/shaders/Voxel.fs.spv index 2849d93..ff6cd13 100644 --- a/resource/content/shaders/Voxel.fs.spv +++ b/resource/content/shaders/Voxel.fs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4eb04e772acac70382a5220eff25139d263859a91a44ecf81ebb043f980ea26a -size 16756 +oid sha256:6887118bdf9fb9d2a6b00588618569de724df7c34e124748a32bec141a0fe5e3 +size 16868 diff --git a/resource/content/shaders/Voxel.geo.fs.spv b/resource/content/shaders/Voxel.geo.fs.spv index 0194484..f97052d 100644 --- a/resource/content/shaders/Voxel.geo.fs.spv +++ b/resource/content/shaders/Voxel.geo.fs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fdd9299db56b2760b432e2115dcae667e2d6b82f8e82b032d37d7f455b279239 -size 19868 +oid sha256:8188855c5be7c36d0cdd6e259567ac8e825ac1593d1b024215d1b19847e96951 +size 19948 diff --git a/resource/content/shaders/Voxel.geo.ins.fs.spv b/resource/content/shaders/Voxel.geo.ins.fs.spv index 0194484..f97052d 100644 --- a/resource/content/shaders/Voxel.geo.ins.fs.spv +++ b/resource/content/shaders/Voxel.geo.ins.fs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fdd9299db56b2760b432e2115dcae667e2d6b82f8e82b032d37d7f455b279239 -size 19868 +oid sha256:8188855c5be7c36d0cdd6e259567ac8e825ac1593d1b024215d1b19847e96951 +size 19948 diff --git a/resource/content/shaders/Voxel.ins.fs.spv b/resource/content/shaders/Voxel.ins.fs.spv index 2849d93..ff6cd13 100644 --- a/resource/content/shaders/Voxel.ins.fs.spv +++ b/resource/content/shaders/Voxel.ins.fs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4eb04e772acac70382a5220eff25139d263859a91a44ecf81ebb043f980ea26a -size 16756 +oid sha256:6887118bdf9fb9d2a6b00588618569de724df7c34e124748a32bec141a0fe5e3 +size 16868 diff --git a/resource/content/textures/1024-realistic/terrain/Water.dds b/resource/content/textures/1024-realistic/terrain/Water.dds index 15003d1..abe8d97 100644 --- a/resource/content/textures/1024-realistic/terrain/Water.dds +++ b/resource/content/textures/1024-realistic/terrain/Water.dds @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d50d69c2d67a4c0251b18dca746afd360f157098271b1e96576c5b91a141a11d +oid sha256:295df28613d038c84bd645adcb80728b6f5fc338c37eab897977cf522e5448ab size 1398256 diff --git a/resource/shaders-src/Voxel.frag b/resource/shaders-src/Voxel.frag index 8b8c4ce..19b2662 100644 --- a/resource/shaders-src/Voxel.frag +++ b/resource/shaders-src/Voxel.frag @@ -116,15 +116,16 @@ if(BLEND) { #endif } -vec3 getTriTexture(sampler2DArray smpl, vec2 crdx, vec2 crdy, vec2 crdz, vec3 weights) { - return getTexture(smpl, crdx).rgb * weights.x + - getTexture(smpl, crdy).rgb * weights.y + - getTexture(smpl, crdz).rgb * weights.z; +vec4 getTriTexture(sampler2DArray smpl, vec2 crdx, vec2 crdy, vec2 crdz, vec3 weights) { + return getTexture(smpl, crdx) * weights.x + + getTexture(smpl, crdy) * weights.y + + getTexture(smpl, crdz) * weights.z; } void main() { float texScale = 1. / UNIT_SIZE; - vec3 tex, worldNormal, texHOS; + vec4 tex; + vec3 worldNormal, texHOS; if(TRIPLANAR) { // Triplanar @@ -152,7 +153,7 @@ if(PBR) { // Swizzle tangent normals to match world orientation and triblend worldNormal = normalize(texNx.zyx * blendWeights.x + texNy.xzy * blendWeights.y +texNz.xyz * blendWeights.z); - texHOS = getTriTexture(HOSAtlas, UVx, UVy, UVz, blendWeights); + texHOS = getTriTexture(HOSAtlas, UVx, UVy, UVz, blendWeights).rgb; } } else { // Cheap planar @@ -160,7 +161,7 @@ if(PBR) { vec3 nrm = normalize(pow(blendWeights, vec3(80 / sqrt(UNIT_SIZE)))); vec2 UV = (vec2(vs.Position_modelspace.xy * nrm.z) + vec2(vs.Position_modelspace.yz * nrm.x) + vec2(vs.Position_modelspace.zx * nrm.y)) * texScale; - tex = getTexture(TextureAtlas, UV).rgb; + tex = getTexture(TextureAtlas, UV); if(PBR) { vec3 texN = expand(getTexture(NormalAtlas, UV).rgb); // Swizzle world normals into tangent space and apply Whiteout blend @@ -176,7 +177,7 @@ if(PBR) { // Colors if(PBR) { // Texture properties - vec3 TextureDiffuseColor = tex; + vec3 TextureDiffuseColor = tex.rgb; vec3 TextureAmbientColor = vec3(.1) * TextureDiffuseColor * texHOS.y; vec3 TextureSpecularColor = vec3(.8) * texHOS.z; @@ -213,21 +214,20 @@ if(PBR) { // MAYBE: shadow - tex = + color = vec4( // Ambient : simulates indirect lighting TextureAmbientColor + // Diffuse : "color" of the object visibility * TextureDiffuseColor * LightColor * LightPower * cosTheta / (distance * distance) + // Specular : reflective highlight, like a mirror - visibility * TextureSpecularColor * LightColor * LightPower * pow(cosAlpha,5) / (distance * distance); + visibility * TextureSpecularColor * LightColor * LightPower * pow(cosAlpha,5) / (distance * distance), + // Restore alpha + tex.a); +} else { + color = tex; } if(FOG) { float ratio = exp(vs.Depth * 0.69)-1; - tex = mix(tex, UBO.fog.rgb, clamp(ratio, 0, 1)); + color = mix(color, vec4(UBO.fog.rgb, 1), clamp(ratio, 0, 1)); } - //TODO: check gamma color = pow(color, vec3(1.0 / 2.2)); - color = vec4(tex, 1); - /*if(color.r > 1 || color.g > 1 || color.b > 1) { - color = vec4(1, 0, 0, 1); //TODO: bloom - }*/ } \ No newline at end of file diff --git a/resource/textures-src/1024-realistic/Water_002_COLOR.jpg b/resource/textures-src/1024-realistic/Water_002_COLOR.jpg deleted file mode 100644 index 1e2ce6f..0000000 --- a/resource/textures-src/1024-realistic/Water_002_COLOR.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:43ff30cebd9b2d2dac943096cc70891c44d21b11c8afec29b2ff1bee14fa88fe -size 9744 diff --git a/resource/textures-src/1024-realistic/Water_002_COLOR.png b/resource/textures-src/1024-realistic/Water_002_COLOR.png new file mode 100644 index 0000000..ca8e358 --- /dev/null +++ b/resource/textures-src/1024-realistic/Water_002_COLOR.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9888de8b8385c2e7300fb84758933bd5fec85660a3a5715f3913d3d38e3a5ad1 +size 6914 diff --git a/resource/textures-src/1024-realistic/index.txt b/resource/textures-src/1024-realistic/index.txt index 191b7a6..f3637f6 100644 --- a/resource/textures-src/1024-realistic/index.txt +++ b/resource/textures-src/1024-realistic/index.txt @@ -34,7 +34,7 @@ Stone_Path_004_normal.jpg terrain/Stone_path.nrm.dds Stone_Wall_008_COLOR.jpg terrain/Stone_wall.dds Stone_Wall_008_HOS.jpg terrain/Stone_wall.hos.dds Stone_Wall_008_NORM.jpg terrain/Stone_wall.nrm.dds -Water_002_COLOR.jpg terrain/Water.dds +Water_002_COLOR.png terrain/Water.dds Water_002_HOS.jpg terrain/Water.hos.dds Water_002_NORM.jpg terrain/Water.nrm.dds Debug.cube.back.png sky/Debug.cube.back.dds diff --git a/src/client/Client.cpp b/src/client/Client.cpp index a1388e9..6119b1f 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -137,18 +137,13 @@ void Client::run(server_handle* const localHandle) { reports.models_count = 0; reports.tris_count = 0; std::optional frustum; - if(options.culling >= 0) { + if(options.culling <= 0) { frustum = {camera.getFrustum()}; } const auto offset = state.position.raw_as_long(); { // Chunks - const auto pass = pipeline->beginWorldPass(); - const auto draw = [&](glm::mat4 model, render::LodModel *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) { - reports.models_count++; - reports.tris_count += pass(buffer, model, glm::vec4(pos, std::get<1>(area)), std::get<2>(area)); - }; + std::vector occlusion; if (options.culling > 0) { - std::vector occlusion; const auto ratio = options.culling * 2; occlusion.reserve(glm::pow2(ratio * 2 - 1)); const auto [ch, cv] = player.getAngles(); @@ -160,9 +155,30 @@ void Client::run(server_handle* const localHandle) { occlusion.emplace_back(cos(v) * sin(h), sin(v), cos(v) * cos(h)); } } - state.contouring->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density); - } else { - state.contouring->getModels(draw, frustum, offset, options.voxel_density); + } + { // Solid + const auto pass = pipeline->beginWorldPass(true); + const auto draw = [&](glm::mat4 model, render::LodModel *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) { + reports.models_count++; + reports.tris_count += pass(buffer, model, glm::vec4(pos, std::get<1>(area)), std::get<2>(area)); + }; + if (options.culling > 0) { + state.contouring->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density, true); + } else { + state.contouring->getModels(draw, frustum, offset, options.voxel_density, true); + } + } + if (options.renderer.voxel.transparency) { + const auto pass = pipeline->beginWorldPass(false); + const auto draw = [&](glm::mat4 model, render::LodModel *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) { + reports.models_count++; + reports.tris_count += pass(buffer, model, glm::vec4(pos, std::get<1>(area)), std::get<2>(area)); + }; + if (options.culling > 0) { + state.contouring->getModels(draw, player.position, options.camera.far, occlusion, offset, options.voxel_density, false); + } else { + state.contouring->getModels(draw, frustum, offset, options.voxel_density, false); + } } } { // Entities diff --git a/src/client/config.hpp b/src/client/config.hpp index 9481985..dd84e7a 100644 --- a/src/client/config.hpp +++ b/src/client/config.hpp @@ -49,6 +49,7 @@ public: renderer.skybox = config["render"]["skybox"].value_or(renderer.skybox); renderer.voxel.curvature = config["render"]["curvature"].value_or(renderer.voxel.curvature); renderer.voxel.curv_depth = config["render"]["curvature_depth"].value_or(renderer.voxel.curv_depth); + renderer.voxel.transparency = config["render"]["transparency"].value_or(renderer.voxel.transparency); culling = config["render"]["culling"].value_or(culling); contouring = config["contouring"].value_or(std::string("")); @@ -120,6 +121,7 @@ public: {"skybox", renderer.skybox}, {"curvature", renderer.voxel.curvature}, {"curvature_depth", renderer.voxel.curv_depth}, + {"transparency", renderer.voxel.transparency}, {"culling", culling} })); config.insert_or_assign("contouring", contouring); @@ -191,7 +193,7 @@ public: windowOptions window; - bool preferVulkan = true; + bool preferVulkan = false; render::renderOptions renderer; int culling = 0; diff --git a/src/client/contouring/Abstract.hpp b/src/client/contouring/Abstract.hpp index de8f776..09d6135 100644 --- a/src/client/contouring/Abstract.hpp +++ b/src/client/contouring/Abstract.hpp @@ -39,9 +39,9 @@ namespace contouring { /// Get buffers in frustum with model matrices /// @note buffers invalidated after update - virtual void getModels(draw_call draw, const std::optional& frustum, const glm::llvec3& offset, int density) = 0; + virtual void getModels(draw_call draw, const std::optional& frustum, const glm::llvec3& offset, int density, bool solid) = 0; /// Get buffers hitting occlusion rays with model matrices /// @note buffers invalidated after update - virtual void getModels(draw_call draw, const glm::ifvec3 &from, float far, const std::vector &occlusion, const glm::llvec3 &offset, int density) = 0; + virtual void getModels(draw_call draw, const glm::ifvec3 &from, float far, const std::vector &occlusion, const glm::llvec3 &offset, int density, bool solid) = 0; }; } \ No newline at end of file diff --git a/src/client/contouring/FlatDualMC.cpp b/src/client/contouring/FlatDualMC.cpp index 13ce463..76c8b21 100644 --- a/src/client/contouring/FlatDualMC.cpp +++ b/src/client/contouring/FlatDualMC.cpp @@ -47,8 +47,13 @@ namespace contouring { loadQueue.wait(); if (loadQueue.pop(ctx)) { ZoneScopedN("ProcessContouring"); - render::LodModel::LodData data; - render(ctx.second, data, tmp); + std::pair data; + if (transparency) { + render(ctx.second, data.first, tmp, Layer::Solid); + render(ctx.second, data.second, tmp, Layer::Transparent); + } else { + render(ctx.second, data.first, tmp, Layer::Both); + } //TODO: direct upload with vulkan loadedQueue.emplace(ctx.first, data); } @@ -68,7 +73,8 @@ namespace contouring { //TODO: prefer unique_ptr for(auto& buffer: buffers) { for(auto& val: buffer.second.second) { - delete val.second; + delete val.second.first; + delete val.second.second; } } } @@ -129,20 +135,24 @@ namespace contouring { void FlatDualMC::update(const voxel_pos& pos, const world::client::area_map& areas) { ZoneScopedN("Ct"); - std::pair, render::LodModel::LodData> out; + std::pair, std::pair> out; TracyPlot("CtLoad", static_cast(loadQueue.size())); //MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance) TracyPlot("CtLoaded", static_cast(loadedQueue.size())); for(auto handle = loadedQueue.extractor(); handle.first(out);) { - const auto buffer = out.second.first.empty() ? NULL : render::LodModel::Create(out.second).release(); + const auto bufferSolid = out.second.first.first.empty() ? NULL : render::LodModel::Create(out.second.first).release(); + const auto bufferTrans = out.second.second.first.empty() ? NULL : render::LodModel::Create(out.second.second).release(); auto &bfs = buffers[out.first.first].second; //NOTE: buffer.first uninitialized (will be set in clear()) if (const auto it = bfs.find(out.first.second); it != bfs.end()) { - if(it->second != NULL) - delete it->second; + if (it->second.first != NULL) + delete it->second.first; + if (it->second.second != NULL) + delete it->second.second; - it->second = buffer; + it->second.first = bufferSolid; + it->second.second = bufferTrans; } else { - bfs.emplace(out.first.second, buffer); + bfs.emplace(out.first.second, std::make_pair(bufferSolid, bufferTrans)); } } size_t buffer_count = 0; @@ -165,13 +175,20 @@ namespace contouring { auto it = bfs.begin(); while(it != bfs.end()) { if (const auto distRatio = glm::length(glm::dvec3(center - it->first)) / keepDistance; distRatio > 1) { - if(it->second != NULL) - delete it->second; + if(it->second.first != NULL) + delete it->second.first; + if (it->second.second != NULL) + delete it->second.second; it = bfs.erase(it); } else { - if(it->second != NULL) { - it->second->setLevel(std::clamp((1+lod_quality-distRatio)*levelMax*(1+lod_strength), 0, levelMax)); + const auto level = std::clamp((1 + lod_quality - distRatio) * levelMax * (1 + lod_strength), 0, levelMax); + if (it->second.first != NULL) { + it->second.first->setLevel(level); + buffer_count++; + } + if (it->second.second != NULL) { + it->second.second->setLevel(level); buffer_count++; } ++it; @@ -180,8 +197,10 @@ namespace contouring { ++it_a; } else { for(auto& buffer: it_a->second.second) { - if(buffer.second != NULL) - delete buffer.second; + if (buffer.second.first != NULL) + delete buffer.second.first; + if(buffer.second.second != NULL) + delete buffer.second.second; } it_a = buffers.erase(it_a); } @@ -220,7 +239,7 @@ namespace contouring { } } - void FlatDualMC::render(const surrounding::corners &surrounding, render::LodModel::LodData &out, std::vector &tmp) const { + void FlatDualMC::render(const surrounding::corners &surrounding, render::LodModel::LodData &out, std::vector &tmp, Layer layer) const { const int SIZE = CHUNK_LENGTH + 3; std::array::Point, SIZE * SIZE * SIZE> grid; { @@ -228,7 +247,9 @@ namespace contouring { const auto setCell = [&](int x, int y, int z, const world::Voxel &voxel) { auto &cell = grid[((z * SIZE) + y) * SIZE + x]; cell.w = voxel.material(); - cell.x = voxel.density_ratio() * (!world::materials::invisibility[cell.w] && (transparency || !world::materials::transparency[cell.w])); + cell.x = voxel.density_ratio() * (!world::materials::invisibility[cell.w] && + ((world::materials::transparency[cell.w] && (layer && Layer::Transparent)) || + (!world::materials::transparency[cell.w] && (layer && Layer::Solid)))); }; for (int z = 0; z < SIZE; z++) { for (int y = 0; y < SIZE; y++) { @@ -303,18 +324,19 @@ namespace contouring { } } - void FlatDualMC::getModels(draw_call out, const std::optional &frustum, const glm::llvec3& offset, int density) { + void FlatDualMC::getModels(draw_call out, const std::optional &frustum, const glm::llvec3& offset, int density, bool solid) { const auto scaling = glm::scale(glm::mat4(1), glm::vec3(1.f / density)); for (const auto [_, area] : buffers) { - for (const auto [pos, buffer] : area.second) { + for (const auto [pos, buf] : area.second) { const auto vPos = glm::multiply(pos); const glm::vec3 fPos = (glm::vec3(std::get<0>(area.first).raw_as_long() + vPos - offset * glm::llvec3(density)) + std::get<0>(area.first).offset) / glm::vec3(density); + const auto buffer = solid ? buf.first : buf.second; if (buffer != NULL && (!frustum.has_value() || frustum.value().contains(geometry::Box::fromMin(fPos, glm::vec3(CHUNK_LENGTH / (float)density))))) out(glm::translate(scaling, fPos * (float)density), buffer, area.first, vPos); }} } - void FlatDualMC::getModels(draw_call out, const glm::ifvec3& from, float far, const std::vector &occlusion, const glm::llvec3 &offset, int density) { + void FlatDualMC::getModels(draw_call out, const glm::ifvec3& from, float far, const std::vector &occlusion, const glm::llvec3 &offset, int density, bool solid) { const auto scaling = glm::scale(glm::mat4(1), glm::vec3(1.f / density)); const auto start = glm::ifvec3(glm::divide(from.as_voxel(density))); const auto dist = far * density / CHUNK_LENGTH; @@ -327,10 +349,11 @@ namespace contouring { ray.grid(points); for(auto& point: points) { auto it = area.second.find(glm::lvec3(point) - area_offset); - if(it != area.second.end() && it->second != NULL && done.insert(it->first).second) { + const auto buffer = solid ? it->second.first : it->second.second; + if(it != area.second.end() && buffer != NULL && done.insert(it->first).second) { const auto vPos = glm::multiply(it->first); const glm::vec3 fPos = glm::vec3(std::get<0>(area.first).raw_as_long() + vPos - offset * glm::llvec3(density)) + std::get<0>(area.first).offset; - out(glm::translate(scaling, fPos), it->second, area.first, vPos); + out(glm::translate(scaling, fPos), buffer, area.first, vPos); break; } } diff --git a/src/client/contouring/FlatDualMC.hpp b/src/client/contouring/FlatDualMC.hpp index add65f0..271186e 100644 --- a/src/client/contouring/FlatDualMC.hpp +++ b/src/client/contouring/FlatDualMC.hpp @@ -33,17 +33,17 @@ namespace contouring { /// Get buffers in frustum with model matrices /// @note buffers invalidated after update - void getModels(draw_call draw, const std::optional &frustum, const glm::llvec3 &offset, int density) override; + void getModels(draw_call draw, const std::optional &frustum, const glm::llvec3 &offset, int density, bool solid) override; /// Get buffers hitting occlusion rays with model matrices /// @note buffers invalidated after update - void getModels(draw_call draw, const glm::ifvec3 &from, float far, const std::vector &occlusion, const glm::llvec3 &offset, int density) override; + void getModels(draw_call draw, const glm::ifvec3 &from, float far, const std::vector &occlusion, const glm::llvec3 &offset, int density, bool solid) override; protected: //FIXME: use unique_ptr - robin_hood::unordered_map>> buffers; + robin_hood::unordered_map>>> buffers; safe_priority_queue_map, surrounding::corners, int, area_hash> loadQueue; - safe_queue, render::LodModel::LodData>> loadedQueue; + safe_queue, std::pair>> loadedQueue; bool running = true; std::vector workers; @@ -62,6 +62,15 @@ namespace contouring { std::vector> loadedLevels; - void render(const surrounding::corners &surrounding, render::LodModel::LodData& out, std::vector& tmp) const; + enum class Layer { + Solid = 1, + Transparent = 2, + Both = Solid | Transparent, + }; + friend inline bool operator&&(Layer a, Layer b) { + return static_cast(a) & static_cast(b); + } + + void render(const surrounding::corners &surrounding, render::LodModel::LodData& out, std::vector& tmp, Layer layer) const; }; } diff --git a/src/client/render/Renderer.hpp b/src/client/render/Renderer.hpp index 8fd5146..fe3015f 100644 --- a/src/client/render/Renderer.hpp +++ b/src/client/render/Renderer.hpp @@ -31,6 +31,8 @@ struct passOptions { bool curvature = true; /// Keep depth in sphere bool curv_depth = true; + /// Alpha blend + bool transparency = false; }; /// Rendering options @@ -68,7 +70,7 @@ public: virtual void beginFrame() = 0; /// Get started world program /// (vertex buffer, model matrix, sphereProj, curvature) - virtual std::function beginWorldPass() = 0; + virtual std::function beginWorldPass(bool solid) = 0; /// Get started entity program virtual std::function &)> beginEntityPass() = 0; /// Draw cube indicator diff --git a/src/client/render/UI.cpp b/src/client/render/UI.cpp index 8982e5e..10424e9 100644 --- a/src/client/render/UI.cpp +++ b/src/client/render/UI.cpp @@ -109,6 +109,8 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons ImGui::TextDisabled("Depth"); } + changeRenderer |= ImGui::Checkbox("Transparency", &options.renderer.voxel.transparency); + changeRenderer |= ImGui::Checkbox("Fog", &options.renderer.voxel.fog); ImGui::SameLine(); ImGui::Checkbox("Skybox", &options.renderer.skybox); diff --git a/src/client/render/UI.hpp b/src/client/render/UI.hpp index b0bfbcc..0e9775c 100644 --- a/src/client/render/UI.hpp +++ b/src/client/render/UI.hpp @@ -37,6 +37,7 @@ public: Control = 1 << 7, FillMode = 1 << 8, Message = 1 << 9, + Transparency = 1 << 10, }; friend inline void operator|=(Actions& a, Actions b) { a = static_cast(static_cast(a) | static_cast(b)); diff --git a/src/client/render/gl/Renderer.cpp b/src/client/render/gl/Renderer.cpp index 5737d51..962bfaf 100644 --- a/src/client/render/gl/Renderer.cpp +++ b/src/client/render/gl/Renderer.cpp @@ -72,6 +72,9 @@ bool Renderer::Load(Window& window, const renderOptions& opt, const windowOption glEnable(GL_CULL_FACE); glCullFace(GL_BACK); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + GLint smp; glGetIntegerv(GL_SAMPLES, &smp); if (smp > 0) { @@ -98,9 +101,11 @@ void Renderer::beginFrame() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -std::function Renderer::beginWorldPass() { - WorldPass->useIt(); - WorldPass->start(this); +std::function Renderer::beginWorldPass(bool solid) { + if (solid) { + WorldPass->useIt(); + WorldPass->start(this); + } return [&](render::LodModel *const buf, glm::mat4 model, glm::vec4 sph, float curv) { WorldPass->setup(model, sph, curv); return dynamic_cast(buf)->draw(); @@ -138,6 +143,11 @@ void Renderer::swapBuffer(Window& w) { } void Renderer::reloadShaders(const pass::VoxelProgram::options& options) { + if (options.transparency) { + glEnable(GL_BLEND); + } else { + glDisable(GL_BLEND); + } WorldPass = std::make_unique(options); EntityPass = std::make_unique(options); } diff --git a/src/client/render/gl/Renderer.hpp b/src/client/render/gl/Renderer.hpp index a2159f2..2f65561 100644 --- a/src/client/render/gl/Renderer.hpp +++ b/src/client/render/gl/Renderer.hpp @@ -43,7 +43,7 @@ public: } void beginFrame() override; - std::function beginWorldPass() override; + std::function beginWorldPass(bool solid) override; std::function&)> beginEntityPass() override; std::function beginIndicatorPass() override; void postProcess() override; diff --git a/src/client/render/vk/Pipeline.cpp b/src/client/render/vk/Pipeline.cpp index 0ad3c45..6342c7a 100644 --- a/src/client/render/vk/Pipeline.cpp +++ b/src/client/render/vk/Pipeline.cpp @@ -8,8 +8,6 @@ #define CONTENT_DIR "content/" #define SHADER_DIR CONTENT_DIR "shaders/" -constexpr auto BLENDING = false; - using namespace render::vk; Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const renderOptions &options): device(device) { @@ -297,24 +295,24 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render depthStencil.stencilTestEnable = VK_FALSE; // Stencil options front/back - VkPipelineColorBlendAttachmentState colorBlendAttachment{}; - colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - if constexpr (BLENDING) { - colorBlendAttachment.blendEnable = VK_TRUE; - colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; - colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; - } else { - colorBlendAttachment.blendEnable = VK_FALSE; - } + VkPipelineColorBlendAttachmentState solidColorBlendAttachment{}; + solidColorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + solidColorBlendAttachment.blendEnable = VK_FALSE; + + VkPipelineColorBlendAttachmentState blendColorBlendAttachment{}; + blendColorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + blendColorBlendAttachment.blendEnable = VK_TRUE; + blendColorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + blendColorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendColorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; + blendColorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + blendColorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + blendColorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; VkPipelineColorBlendStateCreateInfo colorBlending{}; colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; colorBlending.attachmentCount = 1; //NOTE: For multitarget - colorBlending.pAttachments = &colorBlendAttachment; + colorBlending.pAttachments = options.voxel.transparency ? &blendColorBlendAttachment : &solidColorBlendAttachment; colorBlending.logicOpEnable = VK_FALSE; colorBlending.logicOp = VK_LOGIC_OP_COPY; colorBlending.blendConstants[0] = 0.0f; diff --git a/src/client/render/vk/Renderer.cpp b/src/client/render/vk/Renderer.cpp index 5df2f83..b899b65 100644 --- a/src/client/render/vk/Renderer.cpp +++ b/src/client/render/vk/Renderer.cpp @@ -450,11 +450,13 @@ void Renderer::beginFrame() { } } -std::function Renderer::beginWorldPass() { +std::function Renderer::beginWorldPass(bool solid) { assert(currentImage < swapChain->getImageViews().size()); auto& pass = pipeline->getWorldPass(); - commandCenter->startWorldPass(currentImage, pass); + if (solid) { + commandCenter->startWorldPass(currentImage, pass); + } return [&](render::LodModel *const rBuffer, glm::mat4 model, glm::vec4 sphere, float curv) { auto buffer = dynamic_cast(rBuffer); buffer->setLastUse(currentImage); diff --git a/src/client/render/vk/Renderer.hpp b/src/client/render/vk/Renderer.hpp index e654445..ae14b2b 100644 --- a/src/client/render/vk/Renderer.hpp +++ b/src/client/render/vk/Renderer.hpp @@ -21,7 +21,7 @@ public: static _FORCE_INLINE_ Renderer *Get() { return static_cast(render::Renderer::Get()); } void beginFrame() override; - std::function beginWorldPass() override; + std::function beginWorldPass(bool solid) override; std::function &)> beginEntityPass() override; std::function beginIndicatorPass() override; void postProcess() override;