Two pass transparency
This commit is contained in:
parent
9a095a09ac
commit
7920e8b473
5
TODO.md
5
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
|
||||
|
|
|
@ -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));
|
||||
}
|
BIN
resource/content/shaders/Voxel.fs.spv (Stored with Git LFS)
BIN
resource/content/shaders/Voxel.fs.spv (Stored with Git LFS)
Binary file not shown.
BIN
resource/content/shaders/Voxel.geo.fs.spv (Stored with Git LFS)
BIN
resource/content/shaders/Voxel.geo.fs.spv (Stored with Git LFS)
Binary file not shown.
BIN
resource/content/shaders/Voxel.geo.ins.fs.spv (Stored with Git LFS)
BIN
resource/content/shaders/Voxel.geo.ins.fs.spv (Stored with Git LFS)
Binary file not shown.
BIN
resource/content/shaders/Voxel.ins.fs.spv (Stored with Git LFS)
BIN
resource/content/shaders/Voxel.ins.fs.spv (Stored with Git LFS)
Binary file not shown.
BIN
resource/content/textures/1024-realistic/terrain/Water.dds (Stored with Git LFS)
BIN
resource/content/textures/1024-realistic/terrain/Water.dds (Stored with Git LFS)
Binary file not shown.
|
@ -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
|
||||
}*/
|
||||
}
|
BIN
resource/textures-src/1024-realistic/Water_002_COLOR.jpg (Stored with Git LFS)
BIN
resource/textures-src/1024-realistic/Water_002_COLOR.jpg (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
|
@ -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
|
||||
|
|
|
@ -137,18 +137,13 @@ void Client::run(server_handle* const localHandle) {
|
|||
reports.models_count = 0;
|
||||
reports.tris_count = 0;
|
||||
std::optional<geometry::Frustum> 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<glm::vec3> occlusion;
|
||||
if (options.culling > 0) {
|
||||
std::vector<glm::vec3> 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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) = 0;
|
||||
virtual void getModels(draw_call draw, const std::optional<geometry::Frustum>& 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<glm::vec3> &occlusion, const glm::llvec3 &offset, int density) = 0;
|
||||
virtual void getModels(draw_call draw, const glm::ifvec3 &from, float far, const std::vector<glm::vec3> &occlusion, const glm::llvec3 &offset, int density, bool solid) = 0;
|
||||
};
|
||||
}
|
|
@ -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<render::LodModel::LodData, render::LodModel::LodData> 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<area_<chunk_pos>, render::LodModel::LodData> out;
|
||||
std::pair<area_<chunk_pos>, std::pair<render::LodModel::LodData, render::LodModel::LodData>> out;
|
||||
TracyPlot("CtLoad", static_cast<int64_t>(loadQueue.size()));
|
||||
//MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance)
|
||||
TracyPlot("CtLoaded", static_cast<int64_t>(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<size_t>((1+lod_quality-distRatio)*levelMax*(1+lod_strength), 0, levelMax));
|
||||
const auto level = std::clamp<size_t>((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<render::VertexData> &tmp) const {
|
||||
void FlatDualMC::render(const surrounding::corners &surrounding, render::LodModel::LodData &out, std::vector<render::VertexData> &tmp, Layer layer) const {
|
||||
const int SIZE = CHUNK_LENGTH + 3;
|
||||
std::array<dualmc::DualMC<float>::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<geometry::Frustum> &frustum, const glm::llvec3& offset, int density) {
|
||||
void FlatDualMC::getModels(draw_call out, const std::optional<geometry::Frustum> &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<glm::vec3> &occlusion, const glm::llvec3 &offset, int density) {
|
||||
void FlatDualMC::getModels(draw_call out, const glm::ifvec3& from, float far, const std::vector<glm::vec3> &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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<geometry::Frustum> &frustum, const glm::llvec3 &offset, int density) override;
|
||||
void getModels(draw_call draw, const std::optional<geometry::Frustum> &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<glm::vec3> &occlusion, const glm::llvec3 &offset, int density) override;
|
||||
void getModels(draw_call draw, const glm::ifvec3 &from, float far, const std::vector<glm::vec3> &occlusion, const glm::llvec3 &offset, int density, bool solid) override;
|
||||
|
||||
protected:
|
||||
//FIXME: use unique_ptr
|
||||
robin_hood::unordered_map<area_id, robin_hood::pair<area_info, robin_hood::unordered_map<chunk_pos, render::LodModel*>>> buffers;
|
||||
robin_hood::unordered_map<area_id, robin_hood::pair<area_info, robin_hood::unordered_map<chunk_pos, std::pair<render::LodModel *, render::LodModel *>>>> buffers;
|
||||
|
||||
safe_priority_queue_map<area_<chunk_pos>, surrounding::corners, int, area_hash> loadQueue;
|
||||
safe_queue<std::pair<area_<chunk_pos>, render::LodModel::LodData>> loadedQueue;
|
||||
safe_queue<std::pair<area_<chunk_pos>, std::pair<render::LodModel::LodData, render::LodModel::LodData>>> loadedQueue;
|
||||
|
||||
bool running = true;
|
||||
std::vector<std::thread> workers;
|
||||
|
@ -62,6 +62,15 @@ namespace contouring {
|
|||
|
||||
std::vector<std::pair<float, float>> loadedLevels;
|
||||
|
||||
void render(const surrounding::corners &surrounding, render::LodModel::LodData& out, std::vector<render::VertexData>& tmp) const;
|
||||
enum class Layer {
|
||||
Solid = 1,
|
||||
Transparent = 2,
|
||||
Both = Solid | Transparent,
|
||||
};
|
||||
friend inline bool operator&&(Layer a, Layer b) {
|
||||
return static_cast<int>(a) & static_cast<int>(b);
|
||||
}
|
||||
|
||||
void render(const surrounding::corners &surrounding, render::LodModel::LodData& out, std::vector<render::VertexData>& tmp, Layer layer) const;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass() = 0;
|
||||
virtual std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass(bool solid) = 0;
|
||||
/// Get started entity program
|
||||
virtual std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> beginEntityPass() = 0;
|
||||
/// Draw cube indicator
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<Actions>(static_cast<int>(a) | static_cast<int>(b));
|
||||
|
|
|
@ -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<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> Renderer::beginWorldPass() {
|
||||
WorldPass->useIt();
|
||||
WorldPass->start(this);
|
||||
std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> 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<LodModel *const>(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<pass::WorldProgram>(options);
|
||||
EntityPass = std::make_unique<pass::EntityProgram>(options);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
}
|
||||
|
||||
void beginFrame() override;
|
||||
std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass() override;
|
||||
std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass(bool solid) override;
|
||||
std::function<size_t(render::Model *const, const std::vector<glm::mat4>&)> beginEntityPass() override;
|
||||
std::function<size_t(glm::mat4)> beginIndicatorPass() override;
|
||||
void postProcess() override;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -450,11 +450,13 @@ void Renderer::beginFrame() {
|
|||
}
|
||||
}
|
||||
|
||||
std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> Renderer::beginWorldPass() {
|
||||
std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> 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<render::vk::LodModel *const>(rBuffer);
|
||||
buffer->setLastUse(currentImage);
|
||||
|
|
|
@ -21,7 +21,7 @@ public:
|
|||
static _FORCE_INLINE_ Renderer *Get() { return static_cast<Renderer*>(render::Renderer::Get()); }
|
||||
|
||||
void beginFrame() override;
|
||||
std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass() override;
|
||||
std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass(bool solid) override;
|
||||
std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> beginEntityPass() override;
|
||||
std::function<size_t(glm::mat4)> beginIndicatorPass() override;
|
||||
void postProcess() override;
|
||||
|
|
Loading…
Reference in New Issue