1
0
Fork 0

World pass VK and GL Mipmap load

tmp
May B. 2020-10-17 14:49:00 +02:00
parent 15f5b090b5
commit 623cbb8724
106 changed files with 580 additions and 533 deletions

BIN
resource/content/shaders/Color.fs.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Color.vs.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Sky.fs.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Sky.vs.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Tris.fs.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Tris.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Tris.vs.spv (Stored with Git LFS)

Binary file not shown.

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)

Binary file not shown.

BIN
resource/content/shaders/Voxel.geo.gs.spv (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
resource/content/shaders/Voxel.geo.vs.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Voxel.ins.fs.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Voxel.ins.vs.spv (Stored with Git LFS)

Binary file not shown.

BIN
resource/content/shaders/Voxel.vs.spv (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -9,4 +9,5 @@ layout(location = 0) out vec4 color;
void main(){
color = texture(Texture, UV);
color = pow(color, vec4(2.2)); //TODO: Space brightness option
}

View File

@ -43,7 +43,7 @@ layout (location = 0) in VertexData
float Depth;
} vs;
layout(location = 0) out vec3 color;
layout(location = 0) out vec4 color;
vec3 expand(vec3 v) {
return (v - 0.5) * 2;
@ -124,7 +124,7 @@ vec3 getTriTexture(sampler2DArray smpl, vec2 crdx, vec2 crdy, vec2 crdz, vec3 we
void main() {
float texScale = 1. / UNIT_SIZE;
vec3 tex, texN, worldNormal, texHOS;
vec3 tex, worldNormal, texHOS;
if(TRIPLANAR) {
// Triplanar
@ -138,7 +138,7 @@ if(TRIPLANAR) {
vec2 UVy = vs.Position_modelspace.zx * texScale;
vec2 UVz = vs.Position_modelspace.xy * texScale;
vec3 tex = getTriTexture(TextureAtlas, UVx, UVy, UVz, blendWeights);
tex = getTriTexture(TextureAtlas, UVx, UVy, UVz, blendWeights);
if(PBR) {
// Whiteout normal blend
@ -150,9 +150,9 @@ if(PBR) {
texNy = vec3(texNy.xy + vs.FaceNormal_worldspace.xz, abs(texNy.z) * vs.FaceNormal_worldspace.y);
texNz = vec3(texNz.xy + vs.FaceNormal_worldspace.xy, abs(texNz.z) * vs.FaceNormal_worldspace.z);
// Swizzle tangent normals to match world orientation and triblend
vec3 worldNormal = normalize(texNx.zyx * blendWeights.x + texNy.xzy * blendWeights.y +texNz.xyz * blendWeights.z);
worldNormal = normalize(texNx.zyx * blendWeights.x + texNy.xzy * blendWeights.y +texNz.xyz * blendWeights.z);
vec3 texHOS = getTriTexture(HOSAtlas, UVx, UVy, UVz, blendWeights);
texHOS = getTriTexture(HOSAtlas, UVx, UVy, UVz, blendWeights);
}
} else {
// Cheap planar
@ -160,16 +160,16 @@ 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;
vec3 tex = getTexture(TextureAtlas, UV).rgb;
tex = getTexture(TextureAtlas, UV).rgb;
if(PBR) {
vec3 texN = expand(getTexture(NormalAtlas, UV).rgb);
// Swizzle world normals into tangent space and apply Whiteout blend
// Swizzle tangent normals to match world orientation and triblend
vec3 worldNormal = normalize(vec3(texN.xy + vs.FaceNormal_worldspace.zy, abs(texN.z) * vs.FaceNormal_worldspace.x).zyx * blendWeights.x +
worldNormal = normalize(vec3(texN.xy + vs.FaceNormal_worldspace.zy, abs(texN.z) * vs.FaceNormal_worldspace.x).zyx * blendWeights.x +
vec3(texN.xy + vs.FaceNormal_worldspace.xz, abs(texN.z) * vs.FaceNormal_worldspace.y).xzy * blendWeights.y +
vec3(texN.xy + vs.FaceNormal_worldspace.xy, abs(texN.z) * vs.FaceNormal_worldspace.z).xyz * blendWeights.z);
vec3 texHOS = getTexture(HOSAtlas, UV).rgb;
texHOS = getTexture(HOSAtlas, UV).rgb;
}
}
@ -213,22 +213,21 @@ if(PBR) {
// MAYBE: shadow
color =
tex =
// 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);
} else {
color = tex;
}
if(FOG) {
float ratio = exp(vs.Depth * 0.69)-1;
color = mix(color, pow(UBO.fog.rgb, vec3(2.2)), clamp(ratio, 0, 1));
tex = mix(tex, UBO.fog.rgb, clamp(ratio, 0, 1));
}
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
}
//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
}*/
}

View File

@ -33,13 +33,15 @@ layout (location = 0) out GeometryData {
} gs;
void main() {
for(int j = 0; j < 3; j++) {
gs.Textures[j] = vs_in[j].Texture;
}
for(int i = 0; i < gl_in.length(); i++) {
gl_Position = gl_in[i].gl_Position;
gs.Position_modelspace = vs_in[i].Position_modelspace;
gs.FaceNormal_modelspace = vs_in[i].FaceNormal_modelspace;
gs.Textures[i] = vs_in[i].Texture;
switch(int(mod(i,3))) {
case 0:
gs.TextureRatio = vec3(1,0,0);
@ -60,9 +62,6 @@ if(PBR) {
gs.EyeDirection_cameraspace = vs_in[i].EyeDirection_cameraspace;
gs.LightDirection_cameraspace = vs_in[i].LightDirection_cameraspace;
}
#ifdef SHADOW
gs.ShadowCoord = vs_in[i].ShadowCoord;
#endif
if(FOG) {
gs.Depth = vs_in[i].Depth;
}

BIN
resource/shaders-src/frag.spv (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/textures-src/1024-realistic/Debug.cube.back.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/textures-src/1024-realistic/Debug.cube.bottom.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/textures-src/1024-realistic/Debug.cube.front.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/textures-src/1024-realistic/Debug.cube.left.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/textures-src/1024-realistic/Debug.cube.right.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resource/textures-src/1024-realistic/Debug.cube.top.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -37,6 +37,12 @@ Stone_Wall_008_NORM.jpg terrain/Stone_wall.nrm.dds
Water_002_COLOR.jpg 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
Debug.cube.bottom.png sky/Debug.cube.bottom.dds
Debug.cube.front.png sky/Debug.cube.front.dds
Debug.cube.left.png sky/Debug.cube.left.dds
Debug.cube.right.png sky/Debug.cube.right.dds
Debug.cube.top.png sky/Debug.cube.top.dds
Space_orange.cube.back.png sky/Space_orange.cube.back.dds
Space_orange.cube.bottom.png sky/Space_orange.cube.bottom.dds
Space_orange.cube.front.png sky/Space_orange.cube.front.dds

View File

@ -55,7 +55,7 @@ void Client::run(server_handle* const localHandle) {
}
camera.update();
pipeline->lookFrom(camera);
pipeline->LightInvDir = glm::vec3(glm::rotate(glm::mat4(1), deltaTime * .1f, glm::vec3(1, .5, .1)) * glm::vec4(pipeline->LightInvDir, 0));
pipeline->LightInvDir = glm::vec3(glm::rotate(glm::mat4(1), deltaTime * .5f, glm::vec3(1, .5, .1)) * glm::vec4(pipeline->LightInvDir, 0));
{
const auto ray_result = world->raycast(camera.getRay() * options.voxel_density);
@ -101,7 +101,7 @@ void Client::run(server_handle* const localHandle) {
pipeline->reloadShaders(options.renderer.voxel);
}
if(actions && render::UI::Actions::RendererTextures) {
pipeline->reloadTextures(options.renderer.textures, options.renderer.mipMapLOD, options.renderer.anisotropy);
pipeline->reloadTextures(options.renderer.textures, options.renderer.getMipmapLodBias(), options.renderer.getAnisotropy());
}
if(actions && render::UI::Actions::World) {
//FIXME: server options world->setOptions(options.world);
@ -159,10 +159,13 @@ void Client::run(server_handle* const localHandle) {
};*/
//world->getEntitiesModels(draw, frustum, offset, options.voxel_density);
}
if(state.look_at.has_value()) { // Indicator
const auto model = glm::scale(glm::translate(glm::scale(glm::mat4(1), 1.f / glm::vec3(options.voxel_density)), glm::vec3(state.look_at.value().pos.second + state.look_at.value().offset - offset * glm::llvec3(options.voxel_density)) - glm::vec3(.5 + options.editor.tool.radius)), glm::vec3(1 + options.editor.tool.radius * 2));
reports.models_count++;
reports.tris_count += pipeline->drawIndicatorCube(model);
{
const auto pass = pipeline->beginIndicatorPass();
if(state.look_at.has_value()) { // Indicator
const auto model = glm::scale(glm::translate(glm::scale(glm::mat4(1), 1.f / glm::vec3(options.voxel_density)), glm::vec3(state.look_at.value().pos.second + state.look_at.value().offset - offset * glm::llvec3(options.voxel_density)) - glm::vec3(.5 + options.editor.tool.radius)), glm::vec3(1 + options.editor.tool.radius * 2));
reports.models_count++;
reports.tris_count += pass(model);
}
}
pipeline->postProcess();
render::UI::Get()->render();

View File

@ -35,8 +35,8 @@ public:
preferVulkan = config["render"]["prefer_vulkan"].value_or(preferVulkan);
renderer.textures = config["render"]["textures"].value_or(renderer.textures);
renderer.mipMapLOD = config["render"]["texture_quality"].value_or(renderer.mipMapLOD);
renderer.anisotropy = config["render"]["texture_angular_quality"].value_or(renderer.anisotropy);
renderer.textureQuality = config["render"]["texture_quality"].value_or(renderer.textureQuality);
renderer.textureSharpness = config["render"]["texture_angular_quality"].value_or(renderer.textureSharpness);
renderer.voxel.pbr = config["render"]["pbr"].value_or(renderer.voxel.pbr);
renderer.voxel.triplanar = config["render"]["triplanar"].value_or(renderer.voxel.triplanar);
renderer.voxel.stochastic = config["render"]["stochastic"].value_or(renderer.voxel.stochastic);
@ -103,8 +103,8 @@ public:
config.insert_or_assign("render", toml::table({
{"prefer_vulkan", preferVulkan},
{"textures", renderer.textures},
{"texture_quality", renderer.mipMapLOD},
{"texture_angular_quality", renderer.anisotropy},
{"texture_quality", renderer.textureQuality},
{"texture_angular_quality", renderer.textureSharpness},
{"pbr", renderer.voxel.pbr},
{"triplanar", renderer.voxel.triplanar},
{"stochastic", renderer.voxel.stochastic},

View File

@ -22,7 +22,7 @@ struct passOptions {
/// Transform texture UV
bool stochastic = false;
/// Active geometry pass
bool geometry = false;
bool geometry = true;
/// Blend voxel with mixed materials (requires geometry)
bool blend = true;
/// Depth fog
@ -44,14 +44,17 @@ struct renderOptions {
/// Texture pack name
std::string textures = "1024-realistic";
/// Textures quality
float mipMapLOD = -.5;
int textureQuality = 100;
/// Textures anisotropic mapping
int anisotropy = 0;
int textureSharpness = 0;
/// Depth color
glm::vec4 clear_color;
/// Parallel processing frames
/// Incease FPS but also a bit latency (Vulkan only)
int inFlightFrames = 2;
constexpr float getMipmapLodBias() const { return 1 - (textureQuality / 100.f); }
constexpr int getAnisotropy() const { return textureSharpness >= 1 ? (1 << (textureSharpness - 1)) : 0; }
};
/// Rendering plateform interface
@ -69,7 +72,7 @@ public:
/// Get started entity program
virtual std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> beginEntityPass() = 0;
/// Draw cube indicator
virtual size_t drawIndicatorCube(glm::mat4 model) = 0;
virtual std::function<size_t(glm::mat4)> beginIndicatorPass() = 0;
/// Apply postprocessing
virtual void postProcess() = 0;
/// Finalise frame

View File

@ -106,10 +106,12 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons
actions |= Actions::FillMode;
}
ImGui::Text("Textures '%s'", options.renderer.textures.c_str()); // MAYBE: select
if (ImGui::SliderFloat("LOD", &options.renderer.mipMapLOD, -1, 1) |
ImGui::SliderInt("Anisotropy", &options.renderer.anisotropy, 0, 8)) {
if (ImGui::SliderInt("Quality", &options.renderer.textureQuality, 0, 200, "%d%%") |
ImGui::SliderInt("Sharpness", &options.renderer.textureSharpness, 0, 8)) {
actions |= Actions::RendererTextures;
}
if(ImGui::IsItemHovered())
ImGui::SetTooltip("Better texture quality especially at low angles");
ImGui::End();
}

View File

@ -14,7 +14,7 @@ std::unique_ptr<TextureArray> (*TextureArray::loadFunc)(const std::vector<std::s
#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
std::optional<Image::properties> Image::Read(const std::string& imagepath, std::vector<unsigned char>& data) {
std::optional<Image::properties> Image::Read(const std::string& imagepath, std::vector<unsigned char>& data, bool srgb) {
unsigned char header[124];
properties info;
@ -56,15 +56,18 @@ std::optional<Image::properties> Image::Read(const std::string& imagepath, std::
switch(fourCC)
{
case FOURCC_DXT3:
info.format = Format::BC2;
info.format = srgb ? Format::BC2 : Format::BC2_UNORM;
break;
case FOURCC_DXT5:
info.format = Format::BC3;
info.format = srgb ? Format::BC3 : Format::BC3_UNORM;
break;
//MAYBE: VK_FORMAT_BC6H_SFLOAT_BLOCK
default:
return {};
}
//FIXME: miplevels with size < block size (2 last) are corrupted
const uint maxMipmapLevels = 1 + std::floor(std::log2(std::max(info.size.height, info.size.width))) - 2;
info.mipmapLevels = std::min(maxMipmapLevels, info.mipmapLevels);
return info;
}

View File

@ -20,8 +20,10 @@ public:
enum class Format {
/// DXT3 RGBA SRGB
BC2 = 136,
BC2_UNORM = 135,
/// DXT5 RGBA SRGB
BC3 = 138,
BC3_UNORM = 137,
// MAYBE: R8G8B8A8
// MAYBE: For HDR BC6H_SFLOAT = 144,
};
@ -93,7 +95,7 @@ public:
return requirement(props, Layout::SHADER_READ_ONLY, Usage::SAMPLED, Aspect::COLOR, 1, arraySize, cube); }
};
static std::optional<properties> Read(const std::string&, std::vector<unsigned char>& data);
static std::optional<properties> Read(const std::string&, std::vector<unsigned char>& data, bool srgb = true);
};
/// Const image (single texture2D) with sampler
@ -112,6 +114,7 @@ public:
Wrap wrap = Wrap::MIRRORED_REPEAT;
int anisotropy = 0;
bool mipmap = true;
float mipmapLod = 0;
};
/// Only supports dds files

View File

@ -14,6 +14,9 @@ using namespace render::gl;
constexpr auto GL_MAJOR = 4;
constexpr auto GL_MINOR = 6;
#define CONTENT_DIR "content/"
#define TEXTURES_DIR CONTENT_DIR "textures/"
Renderer::Renderer(const renderOptions& options):
IndicatorCubeBuffer(Indicator::CUBE.first, Indicator::CUBE.second) {
glGenVertexArrays(1, &VertexArrayID);
@ -25,7 +28,7 @@ Renderer::Renderer(const renderOptions& options):
IndicatorPass = std::make_unique<pass::ColorProgram>();
FogColor = glm::vec3(options.clear_color.x, options.clear_color.y, options.clear_color.z);
loadTextures(options.textures, options.mipMapLOD, options.anisotropy);
loadTextures(options.textures, options.getMipmapLodBias(), options.getAnisotropy());
}
Renderer::~Renderer() {
@ -107,10 +110,12 @@ std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> Rend
};
}
size_t Renderer::drawIndicatorCube(glm::mat4 model) {
std::function<size_t(glm::mat4)> Renderer::beginIndicatorPass() {
IndicatorPass->useIt();
IndicatorPass->setup(this, model);
return IndicatorCubeBuffer.draw();
return [&](glm::mat4 model) {
IndicatorPass->setup(this, model);
return IndicatorCubeBuffer.draw();
};
}
void Renderer::postProcess() {
@ -136,21 +141,25 @@ void Renderer::reloadTextures(const std::string& texturePath, float mipMapLOD, f
}
void Renderer::unloadTextures() {
glDeleteTextures(1, &HOSAtlas);
glDeleteTextures(1, &NormalAtlas);
glDeleteTextures(1, &TextureAtlas);
HOSAtlas.reset();
NormalAtlas.reset();
TextureAtlas.reset();
}
void Renderer::loadTextures(const std::string& texturePath, float mipMapLOD, float anisotropy) {
std::vector<std::string> terrainTextures;
for(const auto& texture: world::materials::textures) {
terrainTextures.emplace_back(texturePath + "/terrain/" + texture);
}
const auto ani = anisotropy >= 1 ? (1 << (static_cast<int>(anisotropy)-1)) : 0;
TextureAtlas = pass::Program::loadTextureArray(terrainTextures, "", mipMapLOD, ani);
NormalAtlas = pass::Program::loadTextureArray(terrainTextures, ".nrm", mipMapLOD, ani);
HOSAtlas = pass::Program::loadTextureArray(terrainTextures, ".hos", mipMapLOD, ani);
auto makePaths = [&](const std::string& suffix) {
terrainTextures.clear();
for(const auto& texture: world::materials::textures) {
terrainTextures.emplace_back(TEXTURES_DIR + texturePath + "/terrain/" + texture + suffix + ".dds");
}
return terrainTextures;
};
auto sampling = Texture::sampling{true, true, Texture::Wrap::REPEAT, anisotropy, true, mipMapLOD};
TextureAtlas = TextureArray::LoadFromFiles(makePaths(""), sampling);
NormalAtlas = TextureArray::LoadFromFiles(makePaths(".nrm"), sampling);
HOSAtlas = TextureArray::LoadFromFiles(makePaths(".hos"), sampling);
Skybox = pass::Program::loadTextureCube(texturePath + "/sky/Space_tray");
Skybox = TextureCube::LoadFromFiles(TEXTURES_DIR + texturePath + "/sky/Space_tray.cube", {});
}
void Renderer::lookFrom(const Camera& camera) {

View File

@ -7,6 +7,7 @@
#include "pass/SkyProgram.hpp"
#include "pass/ColorProgram.hpp"
#include "api/Models.hpp"
#include "api/Images.hpp"
namespace render::gl {
@ -28,22 +29,22 @@ public:
}
GLuint getTextureAtlas() const {
return TextureAtlas;
return TextureAtlas->getId();
}
GLuint getNormalAtlas() const {
return NormalAtlas;
return NormalAtlas->getId();
}
GLuint getHOSAtlas() const {
return HOSAtlas;
return HOSAtlas->getId();
}
GLuint getSkyTexture() const {
return Skybox;
return Skybox->getId();
}
void beginFrame() override;
std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass() override;
std::function<size_t(render::Model *const, const std::vector<glm::mat4>&)> beginEntityPass() override;
size_t drawIndicatorCube(glm::mat4 model) override;
std::function<size_t(glm::mat4)> beginIndicatorPass() override;
void postProcess() override;
void endFrame() override;
void swapBuffer(Window&) override;
@ -73,10 +74,10 @@ private:
glm::mat4 ProjectionMatrix;
glm::mat4 ViewMatrix;
GLuint TextureAtlas;
GLuint NormalAtlas;
GLuint HOSAtlas;
GLuint Skybox;
std::unique_ptr<TextureArray> TextureAtlas;
std::unique_ptr<TextureArray> NormalAtlas;
std::unique_ptr<TextureArray> HOSAtlas;
std::unique_ptr<TextureCube> Skybox;
/// Draw skybox
bool SkyEnable;

View File

@ -1,9 +0,0 @@
#include "Texture.hpp"
#include "texture.hpp"
using namespace render::gl;
GLuint Texture::CreatePtr(const std::string &name, bool linear) {
return loadDDS("content/textures/" + name + ".dds", linear);
}

View File

@ -1,13 +0,0 @@
#pragma once
#include <string>
#include <GLFW/glfw3.h>
namespace render::gl {
class Texture {
public:
static GLuint CreatePtr(const std::string &name, bool linear);
};
}

View File

@ -4,7 +4,7 @@
#include <GL/gl3w.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include "Texture.hpp"
#include <string>
using namespace render::gl;
@ -12,7 +12,7 @@ UI::UI(GLFWwindow *window): render::UI() {
// Setup Platform/Renderer bindings
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 130");
aim = Texture::CreatePtr("ui/Aim", false);
aim = Texture::LoadFromFile("content/textures/ui/Aim.dds", {false, false, Texture::Wrap::MIRRORED_REPEAT, 0, false});
}
UI::~UI() {
ImGui_ImplGlfw_Shutdown();
@ -22,7 +22,7 @@ UI::~UI() {
UI::Actions UI::draw(config::client::options &o, state::state &s, const state::reports &r) {
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
return render::UI::draw(o, s, r, aim);
return render::UI::draw(o, s, r, aim->getId());
}
void UI::render() {
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

View File

@ -1,6 +1,7 @@
#pragma once
#include "../UI.hpp"
#include "api/Images.hpp"
struct GLFWwindow;
class Window;
@ -19,6 +20,6 @@ public:
void render() override;
private:
intptr_t aim;
std::unique_ptr<Texture> aim;
};
}

View File

@ -0,0 +1,189 @@
#include "Images.hpp"
#include "../../../../core/utils/logger.hpp"
#include <algorithm>
#include <string>
using namespace render::gl;
Image::~Image() {
glDeleteTextures(1, &id);
}
GLenum getGLFormat(render::Image::Format format) {
switch (format) {
case render::Image::Format::BC2:
case render::Image::Format::BC2_UNORM:
return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
case render::Image::Format::BC3:
case render::Image::Format::BC3_UNORM:
return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
default:
return 0;
}
}
GLuint createImage(const Image::requirement& req, render::data_view data) {
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glTextureParameteri(textureID, GL_TEXTURE_MAX_LEVEL, req.mipmapLevels-1);
GLenum format = getGLFormat(req.format);
unsigned int blockSize = /*(format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) ? 8 :*/ 16;
unsigned int offset = 0;
int width = req.size.width;
int height = req.size.height;
/* load the mipmaps */
for (unsigned int level = 0; level < req.mipmapLevels && (width || height); ++level) {
unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize;
assert(data.size >= offset + size);
glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, size, static_cast<const uint8_t*>(data.ptr) + offset);
offset += size;
width /= 2;
height /= 2;
// Deal with Non-Power-Of-Two textures. This code is not included in the webpage to reduce clutter.
if(width < 1) width = 1;
if(height < 1) height = 1;
}
return textureID;
}
void applySampler(GLuint textureID, const Texture::sampling& props) {
auto getFilter = [](bool linear, bool mipmap) { return linear ?
(mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) : (mipmap ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST); };
auto wrap = [](Texture::Wrap wrap) {
switch (wrap) {
case Texture::Wrap::CLAMP_TO_EDGE:
return GL_CLAMP_TO_EDGE;
case Texture::Wrap::CLAMP_TO_BORDER:
return GL_CLAMP_TO_BORDER;
case Texture::Wrap::MIRRORED_REPEAT:
return GL_MIRRORED_REPEAT;
case Texture::Wrap::REPEAT:
default:
return GL_REPEAT;
}
}(props.wrap);
glTextureParameteri(textureID, GL_TEXTURE_MAG_FILTER, getFilter(props.magLinear, props.mipmap));
glTextureParameteri(textureID, GL_TEXTURE_MIN_FILTER, getFilter(props.minLinear, props.mipmap));
glTextureParameterf(textureID, GL_TEXTURE_LOD_BIAS, props.mipmapLod);
glTextureParameterf(textureID, GL_TEXTURE_MAX_ANISOTROPY, props.anisotropy);
glTextureParameteri(textureID, GL_TEXTURE_WRAP_S, wrap);
glTextureParameteri(textureID, GL_TEXTURE_WRAP_T, wrap);
glTextureParameteri(textureID, GL_TEXTURE_WRAP_R, wrap);
}
std::unique_ptr<Texture> Texture::LoadFromFile(const std::string& path, const sampling& props) {
std::vector<unsigned char> data;
auto header = [&] {
if (auto header = render::Image::Read(path, data)) {
return header.value();
}
FATAL("Cannot read texture");
}();
auto id = createImage(requirement::Texture(header), data);
if(!id) {
FATAL("Cannot create texture image");
}
applySampler(id, props);
return std::unique_ptr<Texture>(new Texture(id));
}
std::unique_ptr<TextureCube> TextureCube::LoadFromFiles(const std::array<std::string, 6>& paths, const sampling& props) {
std::vector<unsigned char> data;
auto header = [&] {
if (auto header = render::Image::Read(paths.front(), data)) {
return header.value();
}
FATAL("Cannot read first texture");
}();
auto req = requirement::Texture(header);
GLuint textureID;
{
GLenum format = getGLFormat(header.format);
glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &textureID);
glTextureStorage2D(textureID, 1, format, header.size.width, header.size.height);
ushort layer = 0;
for (auto imagepath = paths.begin(); imagepath != paths.end(); ++imagepath, ++layer) {
data.clear();
if (!render::Image::Read(*imagepath, data).has_value()) {
FATAL("Cannot read texture");
}
GLuint subTextureID = createImage(req, data);
glCopyImageSubData(subTextureID, GL_TEXTURE_2D, 0, 0, 0, 0, textureID, GL_TEXTURE_CUBE_MAP, 0, 0, 0, layer, header.size.width, header.size.height, 1);
glDeleteTextures(1, &subTextureID);
}
}
glTextureParameteri(textureID, GL_TEXTURE_MAX_LEVEL, header.mipmapLevels-1);
applySampler(textureID, props);
return std::unique_ptr<TextureCube>(new TextureCube(textureID));
}
std::unique_ptr<TextureCube> TextureCube::LoadFromFiles(const std::string& prefix, const sampling& props) {
const std::array<std::string, 6> faces {
"right",
"left",
"top",
"bottom",
"front",
"back"
};
std::array<std::string, 6> paths;
std::transform(faces.begin(), faces.end(), paths.begin(),
[prefix](const std::string &face) -> std::string { return prefix + "." + face + ".dds"; });
return LoadFromFiles(paths, props);
}
std::unique_ptr<TextureArray> TextureArray::LoadFromFiles(const std::vector<std::string>& paths, const sampling& props) {
std::vector<unsigned char> data;
auto header = [&] {
if (auto header = render::Image::Read(paths.front(), data)) {
return header.value();
}
FATAL("Cannot read first texture");
}();
auto req = requirement::Texture(header);
GLuint textureID;
{
GLenum format = getGLFormat(header.format);
glCreateTextures(GL_TEXTURE_2D_ARRAY, 1, &textureID);
glTextureStorage3D(textureID, header.mipmapLevels, format, header.size.width, header.size.height, paths.size());
ushort layer = 0;
for (auto imagepath = paths.begin(); imagepath != paths.end(); ++imagepath, ++layer) {
data.clear();
if (!render::Image::Read(*imagepath, data).has_value()) {
FATAL("Cannot read texture");
}
GLuint subTextureID = createImage(req, data);
auto width = header.size.width;
auto height = header.size.height;
for (uint level = 0; level < header.mipmapLevels; level++) {
glCopyImageSubData(subTextureID, GL_TEXTURE_2D, level, 0, 0, 0, textureID, GL_TEXTURE_2D_ARRAY, level, 0, 0, layer, width, height, 1);
width /= 2;
height /= 2;
if(width < 1) width = 1;
if(height < 1) height = 1;
}
glDeleteTextures(1, &subTextureID);
}
}
glTextureParameteri(textureID, GL_TEXTURE_MAX_LEVEL, header.mipmapLevels-1);
applySampler(textureID, props);
return std::unique_ptr<TextureArray>(new TextureArray(paths.size(), textureID));
}

View File

@ -0,0 +1,45 @@
#pragma once
#include "../../api/Images.hpp"
#include <GL/gl3w.h>
namespace render::gl {
class Image: public render::Image {
public:
virtual ~Image();
constexpr GLuint getId() const { return id; }
protected:
Image(GLuint id): id(id) { }
GLuint id;
};
class Texture: public render::Texture, public Image {
public:
static std::unique_ptr<Texture> LoadFromFile(const std::string&, const sampling&);
protected:
Texture(GLuint id): gl::Image(id) { }
};
class TextureCube: public render::TextureCube, public Texture {
public:
/// Looks for .right.dds, .left.dds, .top.dds, .bottom.dds, .front.dds, .back.dds
static std::unique_ptr<TextureCube> LoadFromFiles(const std::string& prefix, const sampling&);
static std::unique_ptr<TextureCube> LoadFromFiles(const std::array<std::string, 6>& paths, const sampling&);
protected:
TextureCube(GLuint id): Texture(id) { }
};
class TextureArray: public render::TextureArray, public Texture {
public:
static std::unique_ptr<TextureArray> LoadFromFiles(const std::vector<std::string>&, const sampling&);
protected:
TextureArray(uint32_t size, GLuint id): render::TextureArray(size), Texture(id) { }
};
}

View File

@ -2,7 +2,7 @@
#include <algorithm>
#include <stdexcept>
#include "../texture.hpp"
#include "../api/Images.hpp"
#define CONTENT_DIR "content/"
#define SHADER_DIR CONTENT_DIR "shaders/"
@ -45,28 +45,27 @@ void Program::useIt() {
glUseProgram(ProgramID);
}
/*
GLuint Program::loadTexture(const std::string& name, bool linear) {
return loadDDS(TEXTURES_DIR + name + ".dds", linear);
auto img = render::gl::Texture::LoadFromFile(TEXTURES_DIR + name + ".dds", {linear, linear});
auto id = img->getId();
std::free(img.release());
return id;
}
GLuint Program::loadTextureArray(const std::vector<std::string> &names, const std::string& suffix, float mipMapLOD, float anisotropy) {
std::vector<std::string> paths;
std::transform(names.begin(), names.end(), std::back_inserter(paths),
[suffix](const std::string &name) -> std::string { return TEXTURES_DIR + name + suffix + ".dds"; });
return loadDDSArray(paths, mipMapLOD, anisotropy);
auto img = render::gl::TextureArray::LoadFromFiles(paths, {true, true, render::Texture::Wrap::REPEAT, anisotropy, true, mipMapLOD});
auto id = img->getId();
std::free(img.release());
return id;
}
GLuint Program::loadTextureCube(const std::string &name) {
std::array<std::string, 6> faces {
"right",
"left",
"top",
"bottom",
"front",
"back"
};
std::array<std::string, 6> paths;
std::transform(faces.begin(), faces.end(), paths.begin(),
[name](const std::string &face) -> std::string { return TEXTURES_DIR + name + ".cube." + face + ".dds"; });
return loadDDSCube(paths);
}
auto img = render::gl::TextureCube::LoadFromFiles(TEXTURES_DIR + name + ".cube", {});
auto id = img->getId();
std::free(img.release());
return id;
}*/

View File

@ -23,10 +23,6 @@ namespace pass {
/// Bind program
void useIt();
static GLuint loadTexture(const std::string &name, bool linear = true);
static GLuint loadTextureArray(const std::vector<std::string> &names, const std::string &suffix = "", float mipMapLOD = 0, float anisotropy = 0);
static GLuint loadTextureCube(const std::string &name);
protected:
/// Get shaders name prefix
virtual std::string getName() const = 0;

View File

@ -1,261 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <cassert>
#include <cmath>
#include <vector>
#include <iostream>
#include <array>
#include <GL/gl3w.h>
#include <GLFW/glfw3.h>
#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII
#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
GLuint loadDDS(const std::string& imagepath, bool linear){
unsigned char header[124];
FILE *fp;
/* try to open the file */
fp = fopen(imagepath.c_str(), "rb");
if (fp == NULL){
printf("%s could not be opened.\n", imagepath.c_str()); getchar();
return 0;
}
/* verify the type of file */
char filecode[4];
fread(filecode, 1, 4, fp);
if (strncmp(filecode, "DDS ", 4) != 0) {
fclose(fp);
return 0;
}
/* get the surface desc */
fread(&header, 124, 1, fp);
unsigned int height = *(unsigned int*)&(header[8 ]);
unsigned int width = *(unsigned int*)&(header[12]);
unsigned int linearSize = *(unsigned int*)&(header[16]);
unsigned int mipMapCount = *(unsigned int*)&(header[24]);
unsigned int fourCC = *(unsigned int*)&(header[80]);
unsigned char * buffer;
unsigned int bufsize;
/* how big is it going to be including all mipmaps? */
bufsize = mipMapCount > 1 ? linearSize * 2 : linearSize;
buffer = (unsigned char*)malloc(bufsize * sizeof(unsigned char));
fread(buffer, 1, bufsize, fp);
/* close the file pointer */
fclose(fp);
unsigned int format;
switch(fourCC)
{
case FOURCC_DXT1:
format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
break;
case FOURCC_DXT3:
format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
break;
case FOURCC_DXT5:
format = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
break;
default:
free(buffer);
return 0;
}
// Create one OpenGL texture
GLuint textureID;
glGenTextures(1, &textureID);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, textureID);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
unsigned int blockSize = (format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) ? 8 : 16;
unsigned int offset = 0;
/* load the mipmaps */
for (unsigned int level = 0; level < mipMapCount && (width || height); ++level)
{
unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize;
glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height,
0, size, buffer + offset);
offset += size;
width /= 2;
height /= 2;
// Deal with Non-Power-Of-Two textures. This code is not included in the webpage to reduce clutter.
if(width < 1) width = 1;
if(height < 1) height = 1;
}
free(buffer);
glTextureParameteri(textureID, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
glTextureParameteri(textureID, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST);
glGenerateTextureMipmap(textureID);
return textureID;
}
GLuint loadDDSArray(const std::vector<std::string>& imagepaths, float mipMapLOD, float anisotropy) {
unsigned char header[124];
auto imagepath = imagepaths.begin();
FILE *fp;
/* try to open the file */
fp = fopen(imagepath->c_str(), "rb");
if (fp == NULL)
{
printf("%s could not be opened.\n", imagepath->c_str());
getchar();
return 0;
}
/* verify the type of file */
char filecode[4];
fread(filecode, 1, 4, fp);
if (strncmp(filecode, "DDS ", 4) != 0)
{
fclose(fp);
return 0;
}
/* get the surface desc */
fread(&header, 124, 1, fp);
unsigned int mainHeight = *(unsigned int *)&(header[8]);
unsigned int mainWidth = *(unsigned int *)&(header[12]);
unsigned int mainFourCC = *(unsigned int *)&(header[80]);
fclose(fp);
unsigned int mainFormat;
switch (mainFourCC)
{
case FOURCC_DXT1:
mainFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
break;
case FOURCC_DXT3:
mainFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
break;
case FOURCC_DXT5:
mainFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
break;
default:
return 0;
}
// Create one OpenGL texture array
GLuint textureID;
glCreateTextures(GL_TEXTURE_2D_ARRAY, 1, &textureID);
glTextureStorage3D(textureID, 1 + std::floor(std::log2(std::max(mainWidth, mainHeight))), mainFormat, mainWidth, mainHeight, imagepaths.size());
ushort layer = 0;
for (imagepath = imagepaths.begin(); imagepath != imagepaths.end(); ++imagepath, ++layer)
{
GLuint subTextureID = loadDDS(*imagepath, false);
glCopyImageSubData(subTextureID, GL_TEXTURE_2D, 0, 0, 0, 0, textureID, GL_TEXTURE_2D_ARRAY, 0, 0, 0, layer, mainWidth, mainHeight, 1);
glDeleteTextures(1, &subTextureID);
}
glTextureParameteri(textureID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameteri(textureID, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTextureParameterf(textureID, GL_TEXTURE_LOD_BIAS, mipMapLOD);
glTextureParameterf(textureID, GL_TEXTURE_MAX_ANISOTROPY, anisotropy);
glGenerateTextureMipmap(textureID);
return textureID;
}
GLuint loadDDSCube(const std::array<std::string, 6>& imagepaths) {
unsigned char header[124];
auto imagepath = imagepaths.begin();
FILE *fp;
/* try to open the file */
fp = fopen(imagepath->c_str(), "rb");
if (fp == NULL)
{
printf("%s could not be opened.\n", imagepath->c_str());
getchar();
return 0;
}
/* verify the type of file */
char filecode[4];
fread(filecode, 1, 4, fp);
if (strncmp(filecode, "DDS ", 4) != 0)
{
fclose(fp);
return 0;
}
/* get the surface desc */
fread(&header, 124, 1, fp);
unsigned int mainHeight = *(unsigned int *)&(header[8]);
unsigned int mainWidth = *(unsigned int *)&(header[12]);
unsigned int mainFourCC = *(unsigned int *)&(header[80]);
fclose(fp);
unsigned int mainFormat;
switch (mainFourCC)
{
case FOURCC_DXT1:
mainFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
break;
case FOURCC_DXT3:
mainFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
break;
case FOURCC_DXT5:
mainFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
break;
default:
return 0;
}
// Create one OpenGL texture array
GLuint textureID;
glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &textureID);
glTextureStorage2D(textureID, 1, mainFormat, mainWidth, mainHeight);
ushort layer = 0;
for (imagepath = imagepaths.begin(); imagepath != imagepaths.end(); ++imagepath, ++layer)
{
GLuint subTextureID = loadDDS(*imagepath, false);
glCopyImageSubData(subTextureID, GL_TEXTURE_2D, 0, 0, 0, 0, textureID, GL_TEXTURE_CUBE_MAP, 0, 0, 0, layer, mainWidth, mainHeight, 1);
glDeleteTextures(1, &subTextureID);
}
glTextureParameteri(textureID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTextureParameteri(textureID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameteri(textureID, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(textureID, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureParameteri(textureID, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glGenerateTextureMipmap(textureID);
return textureID;
}

View File

@ -1,12 +0,0 @@
#pragma once
#include <string.h>
#include <vector>
#include <array>
// Load a .DDS file using GLFW's own loader
GLuint loadDDS(const std::string& imagepath, bool linear = true);
// Load a list of .DDS files
GLuint loadDDSArray(const std::vector<std::string> &imagepaths, float mipMapLOD, float anisotropy);
// Load a .DDS cubemap
GLuint loadDDSCube(const std::array<std::string, 6> &imagepaths);

View File

@ -41,7 +41,7 @@ CommandCenter::CommandCenter(VkDevice device, const PhysicalDeviceInfo &info, co
LOG_D("Samples: " << colorSamples);
depthFormat = info.findDepthFormat();
loadAtlases(opt.textures);
loadAtlases(opt.textures, opt.getAnisotropy(), opt.getMipmapLodBias());
}
CommandCenter::~CommandCenter() {
if(!freed)
@ -50,7 +50,7 @@ CommandCenter::~CommandCenter() {
vkDestroyCommandPool(device, graphicsPool, ALLOC);
}
#include "../../../core/world/materials.hpp"
void CommandCenter::loadAtlases(const std::string& textures) {
void CommandCenter::loadAtlases(const std::string& textures, int anisotropy, float lodBias) {
voxelTextureAtlas.reset();
voxelNormalAtlas.reset();
voxelHOSAtlas.reset();
@ -64,9 +64,10 @@ void CommandCenter::loadAtlases(const std::string& textures) {
}
return paths;
};
voxelTextureAtlas = TextureArray::LoadFromFiles(makePaths(""), {}); //TODO: anisotropy/mipmap options
voxelNormalAtlas = TextureArray::LoadFromFiles(makePaths(".nrm"), {});
voxelHOSAtlas = TextureArray::LoadFromFiles(makePaths(".hos"), {});
const auto sampling = Texture::sampling{true, true, Texture::Wrap::REPEAT, anisotropy, true, lodBias};
voxelTextureAtlas = TextureArray::LoadFromFiles(makePaths(""), sampling);
voxelNormalAtlas = TextureArray::LoadFromFiles(makePaths(".nrm"), sampling, false);
voxelHOSAtlas = TextureArray::LoadFromFiles(makePaths(".hos"), sampling);
if(!(voxelTextureAtlas && voxelNormalAtlas && voxelHOSAtlas)) {
FATAL("Failed to load texture pack!");
@ -174,7 +175,7 @@ void CommandCenter::allocate(const std::vector<VkImageView>& views, const Pipeli
bufferInfo.offset = 0;
bufferInfo.range = sizeof(VoxelUBO);
std::array<VkWriteDescriptorSet, 2> descriptorWrites{};
std::array<VkWriteDescriptorSet, 4> descriptorWrites{};
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[0].dstSet = voxelDescriptorSets[i];
descriptorWrites[0].dstBinding = 0;
@ -288,7 +289,7 @@ void CommandCenter::startWorldPass(uint32_t idx, const Subpass &worldPass) {
vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, worldPass.layout, 0, 1, &voxelDescriptorSets[idx], 0, nullptr);
}
size_t CommandCenter::recordModel(uint32_t i, const Subpass &worldPass, const UniqueCurvaturePush& push, const LodModel *const modelBuffer) {
vkCmdPushConstants(graphicsBuffers[i], worldPass.layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(push), &push);
vkCmdPushConstants(graphicsBuffers[i], worldPass.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push), &push);
VkBuffer vertexBuffers[] = {modelBuffer->getVertex()};
VkDeviceSize offsets[] = {0};
@ -299,11 +300,12 @@ size_t CommandCenter::recordModel(uint32_t i, const Subpass &worldPass, const Un
return size;
}
void CommandCenter::startEntityPass(uint32_t) { }
void CommandCenter::recordIndicator(uint32_t idx, const Subpass& indicPass, glm::mat4 model) {
void CommandCenter::startIndicPass(uint32_t idx, const Subpass& indicPass) {
vkCmdNextSubpass(graphicsBuffers[idx], VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, indicPass.pipeline);
vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, indicPass.layout, 0, 1, &indicDescriptorSets[idx], 0, nullptr);
}
size_t CommandCenter::recordIndicator(uint32_t idx, const Subpass& indicPass, glm::mat4 model) {
ModelPush push{model};
vkCmdPushConstants(graphicsBuffers[idx], indicPass.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push), &push);
@ -311,6 +313,7 @@ void CommandCenter::recordIndicator(uint32_t idx, const Subpass& indicPass, glm:
VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(graphicsBuffers[idx], 0, 1, vertexBuffers, offsets);
vkCmdDraw(graphicsBuffers[idx], indicCubeBuffer->size, 1, 0, 0);
return indicCubeBuffer->size;
}
void CommandCenter::recordPostprocess(uint32_t idx, const Subpass& skyPass, bool skybox) {
vkCmdNextSubpass(graphicsBuffers[idx], VK_SUBPASS_CONTENTS_INLINE);

View File

@ -21,7 +21,8 @@ public:
void startWorldPass(uint32_t idx, const Subpass&);
size_t recordModel(uint32_t idx, const Subpass &worldPass, const UniqueCurvaturePush&, const LodModel *const);
void startEntityPass(uint32_t idx);
void recordIndicator(uint32_t idx, const Subpass&, glm::mat4 model);
void startIndicPass(uint32_t idx, const Subpass&);
size_t recordIndicator(uint32_t idx, const Subpass&, glm::mat4 model);
void recordPostprocess(uint32_t idx, const Subpass&, bool skybox);
void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence);
@ -29,7 +30,7 @@ public:
void free();
private:
void loadAtlases(const std::string &texturePath);
void loadAtlases(const std::string &texturePath, int anisotropy, float lodBias);
VkDevice device;

View File

@ -4,7 +4,6 @@
#include "../../../core/data/file.hpp"
#include "../Renderer.hpp"
#include "api/Models.hpp"
#include <map>
#define CONTENT_DIR "content/"
#define SHADER_DIR CONTENT_DIR "shaders/"
@ -187,27 +186,6 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
}
}
// Common pipeline settings
auto makeSpecialization = [](const std::map<uint32_t, data_view>& constants, std::vector<unsigned char>& speData, std::vector<VkSpecializationMapEntry>& speIndex) {
//MAYBE: create class
VkSpecializationInfo specialization;
speData.resize(0);
speIndex.resize(0);
speData.reserve(constants.size()); //NOTE: Lower bound
speIndex.reserve(constants.size());
for(auto& constant: constants) {
VkSpecializationMapEntry entry;
entry.constantID = constant.first;
entry.size = constant.second.size;
entry.offset = speData.size();
speData.resize(speData.size() + entry.size);
memcpy(speData.data() + entry.offset, static_cast<const uint8_t*>(constant.second.ptr), entry.size);
}
specialization.dataSize = speData.size();
specialization.pData = speData.data();
specialization.mapEntryCount = speIndex.size();
specialization.pMapEntries = speIndex.data();
return specialization;
};
auto setShaders = [&](Subpass &pass, const std::string &shaderName, bool geometry = false, const VkSpecializationInfo* specialization = nullptr) -> std::vector<VkPipelineShaderStageCreateInfo>
{
auto createShaderModule = [&](const data::file_content &code) {
@ -242,9 +220,9 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
if (geometry) {
VkPipelineShaderStageCreateInfo geomShaderStageInfo{};
geomShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
geomShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
data::file_content fsFile({SHADER_DIR + shaderName + ".gs.spv"});
geomShaderStageInfo.module = pass.fsShader = createShaderModule(fsFile);
geomShaderStageInfo.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
data::file_content gsFile({SHADER_DIR + shaderName + ".gs.spv"});
geomShaderStageInfo.module = pass.gsShader = createShaderModule(gsFile);
geomShaderStageInfo.pName = "main";
geomShaderStageInfo.pSpecializationInfo = specialization;
@ -354,25 +332,61 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
{ // World pipeline
VkPushConstantRange pushRange{};
pushRange.offset = 0;
pushRange.size = sizeof(ModelPush);
pushRange.size = sizeof(UniqueCurvaturePush);
pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
setLayout(worldPass, {voxelDescriptorSet}, {pushRange});
auto unitSize = 1; //TODO: load from world.voxel_density
std::vector<unsigned char> speData;
std::vector<VkSpecializationMapEntry> speIndex;
auto specialization = makeSpecialization({
{0, data_view(&options.voxel.fog, sizeof(bool))},
{1, data_view(&options.voxel.pbr, sizeof(bool))},
{2, data_view(&options.voxel.triplanar, sizeof(bool))},
{3, data_view(&options.voxel.stochastic, sizeof(bool))},
{4, data_view(&options.voxel.blend, sizeof(bool))},
{5, data_view(&options.voxel.curvature, sizeof(bool))},
{6, data_view(&options.voxel.curv_depth, sizeof(bool))},
{16, data_view(&unitSize, sizeof(int))}}, speData, speIndex);
struct SpeData {
bool fog;
bool pbr;
bool triplanar;
bool stochastic;
bool blend;
bool curvature;
bool curv_depth;
int32_t unitSize;
} speData;
std::array<VkSpecializationMapEntry, 8> speIndex;
speData.fog = options.voxel.fog;
speIndex[0].constantID = 0;
speIndex[0].offset = offsetof(SpeData, fog);
speIndex[0].size = sizeof(SpeData::fog);
speData.pbr = options.voxel.pbr;
speIndex[1].constantID = 1;
speIndex[1].offset = offsetof(SpeData, pbr);
speIndex[1].size = sizeof(SpeData::pbr);
speData.triplanar = options.voxel.triplanar;
speIndex[2].constantID = 2;
speIndex[2].offset = offsetof(SpeData, triplanar);
speIndex[2].size = sizeof(SpeData::triplanar);
speData.stochastic = options.voxel.stochastic;
speIndex[3].constantID = 3;
speIndex[3].offset = offsetof(SpeData, stochastic);
speIndex[3].size = sizeof(SpeData::stochastic);
speData.blend = options.voxel.blend;
speIndex[4].constantID = 4;
speIndex[4].offset = offsetof(SpeData, blend);
speIndex[4].size = sizeof(SpeData::blend);
speData.curvature = options.voxel.curvature;
speIndex[5].constantID = 5;
speIndex[5].offset = offsetof(SpeData, curvature);
speIndex[5].size = sizeof(SpeData::curvature);
speData.curv_depth = options.voxel.curv_depth;
speIndex[6].constantID = 6;
speIndex[6].offset = offsetof(SpeData, curv_depth);
speIndex[6].size = sizeof(SpeData::curv_depth);
speData.unitSize = 8; //TODO: load from world.voxel_density
speIndex[7].constantID = 16;
speIndex[7].offset = offsetof(SpeData, unitSize);
speIndex[7].size = sizeof(SpeData::unitSize);
VkSpecializationInfo specialization{};
specialization.dataSize = sizeof(SpeData);
specialization.pData = &speData;
specialization.mapEntryCount = speIndex.size();
specialization.pMapEntries = speIndex.data();
auto withGeometry = options.voxel.geometry; //MAYBE: && features.geometry
auto shaderStages = setShaders(worldPass, withGeometry ? "Tris.geo" : "Tris", withGeometry, &specialization);
auto withGeometry = options.voxel.geometry && info.features.geometryShader;
auto shaderStages = setShaders(worldPass, withGeometry ? "Voxel.geo" : "Voxel", withGeometry, &specialization);
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
@ -496,6 +510,9 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
}
Pipeline::~Pipeline() {
auto destroy = [&](Subpass &pass) {
if(pass.gsShader)
vkDestroyShaderModule(device, pass.gsShader, ALLOC);
vkDestroyShaderModule(device, pass.fsShader, ALLOC);
vkDestroyShaderModule(device, pass.vsShader, ALLOC);
vkDestroyPipeline(device, pass.pipeline, ALLOC);
@ -503,6 +520,7 @@ Pipeline::~Pipeline() {
};
destroy(worldPass);
destroy(indicPass);
destroy(skyPass);
vkDestroyDescriptorSetLayout(device, voxelDescriptorSet, ALLOC);

View File

@ -6,6 +6,7 @@ namespace render::vk {
struct Subpass {
VkShaderModule vsShader;
VkShaderModule gsShader = nullptr;
VkShaderModule fsShader;
VkPipelineLayout layout;
VkPipeline pipeline;

Some files were not shown because too many files have changed in this diff Show More