Gets slang shaders mostly working
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -55,3 +55,6 @@
|
||||
[submodule "fgl_cmake_modules"]
|
||||
path = fgl_cmake_modules
|
||||
url = https://github.com/KJNeko/fgl_cmake_modules.git
|
||||
[submodule "dependencies/slang"]
|
||||
path = dependencies/slang
|
||||
url = https://github.com/shader-slang/slang.git
|
||||
|
||||
@@ -31,7 +31,7 @@ include(dependencies/glm)
|
||||
include(cmake_modules/dependencies/tracy.cmake)
|
||||
include(dependencies/vulkan)
|
||||
include(dependencies/catch2)
|
||||
include(dependencies/shaderc)
|
||||
includE(dependencies/slang)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#set(SPIRV-Headers_SOURCE_DIR ${CMAKE_SOURCE_DIR}/dependencies/SPIRV-Headers)
|
||||
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/dependencies/SPIRV-Headers)
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/dependencies/SPIRV-Tools)
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/dependencies/glslang)
|
||||
|
||||
set(SHADERC_SKIP_TESTS ON)
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/dependencies/shaderc)
|
||||
31
cmake_modules/dependencies/slang.cmake
Normal file
31
cmake_modules/dependencies/slang.cmake
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
set(SLANG_ENABLE_CUDA OFF)
|
||||
set(SLANG_ENABLE_OPTIX OFF)
|
||||
set(SLANG_ENABLE_NVAPI OFF)
|
||||
|
||||
set(SLANG_ENABLE_AFTERMATH OFF)
|
||||
set(SLANG_ENABLE_DX_ON_VK OFF)
|
||||
set(SLANG_EMBED_CORE_MODULE_SOURCE OFF)
|
||||
set(SLANG_EMBED_CORE_MODULE ON)
|
||||
|
||||
set(SLANG_ENABLE_DXIL OFF)
|
||||
set(SLANG_ENABLE_FULL_IR_VALIDATION ON)
|
||||
set(SLANG_ENABLE_IR_BREAK_ALLOC ON)
|
||||
|
||||
set(SLANG_ENABLE_PREBUILD_BINARIES OFF)
|
||||
set(SLANG_ENABLE_GFX OFF)
|
||||
|
||||
set(SLANG_ENABLE_SLANGD OFF)
|
||||
set(SLANG_ENABLE_SHANGC OFF)
|
||||
set(SLANG_ENABLE_TESTS OFF)
|
||||
set(SLANG_ENABLE_EXAMPLES OFF)
|
||||
|
||||
set(SLANG_ENABLE_GFX OFF)
|
||||
|
||||
set(SLANG_USE_SYSTEM_VULKAN_HEADERS ON)
|
||||
|
||||
set(SLANG_ENABLE_SPLIT_DEBUG_INFO OFF)
|
||||
set(SLANG_ENABLE_RELEASE_DEBUG_INFO ON)
|
||||
set(SLANG_ENABLE_RELEASE_LTO OFF)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/dependencies/slang)
|
||||
1
dependencies/slang
vendored
Submodule
1
dependencies/slang
vendored
Submodule
Submodule dependencies/slang added at 79aebc18d5
Submodule fgl_cmake_modules updated: 1deccb5318...821bda6d01
@@ -15,7 +15,7 @@ target_link_libraries(FGLEngine PUBLIC stdc++exp)
|
||||
include(dependencies/spdlog)
|
||||
include(dependencies/imgui)
|
||||
|
||||
target_link_libraries(FGLEngine PUBLIC Vulkan::Vulkan glm ImGui FGLLoader spdlog shaderc)
|
||||
target_link_libraries(FGLEngine PUBLIC Vulkan::Vulkan glm ImGui FGLLoader spdlog slang)
|
||||
target_link_libraries(FGLEngine PUBLIC glfw Tracy::TracyClient VMA)
|
||||
target_include_directories(FGLEngine PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
target_compile_features(FGLEngine PUBLIC cxx_std_23)
|
||||
@@ -38,8 +38,11 @@ endif ()
|
||||
|
||||
if (DEFINED FGL_ENABLE_TESTS AND FGL_ENABLE_TESTS)
|
||||
target_compile_definitions(FGLEngine PUBLIC FGL_TESTS=1)
|
||||
target_compile_definitions(FGLEngine PUBLIC FGL_ENABLE_TEST_ASSERT=1)
|
||||
target_link_libraries(FGLEngine PUBLIC Catch2::Catch2)
|
||||
else ()
|
||||
target_compile_definitions(FGLEngine PUBLIC FGL_TESTS=0)
|
||||
target_compile_definitions(FGLEngine PUBLIC FGL_ENABLE_TEST_ASSERT=0)
|
||||
endif ()
|
||||
|
||||
# Enable tracking for buffers, I need to find some way to disable this when trying to link
|
||||
|
||||
@@ -265,7 +265,7 @@ namespace fgl::engine
|
||||
{
|
||||
const auto& [ pos, scale, rotation ] = m_transform;
|
||||
|
||||
const auto rotation_matrix { rotation.mat() };
|
||||
const auto rotation_matrix { rotation.mat3() };
|
||||
|
||||
const glm::vec3 forward { rotation_matrix * glm::vec4( constants::WORLD_FORWARD, 0.0f ) };
|
||||
|
||||
@@ -346,6 +346,7 @@ namespace fgl::engine
|
||||
auto set { camera_descriptor_set.create() };
|
||||
set->bindUniformBuffer( 0, m_camera_frame_info[ i ] );
|
||||
set->update();
|
||||
set->setName( std::format( "Camera {} descriptor set {}", m_camera_idx, i ) );
|
||||
|
||||
m_camera_info_descriptors.emplace_back( std::move( set ) );
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ namespace fgl::engine
|
||||
|
||||
builder.setPushConstant( vk::ShaderStageFlagBits::eFragment, sizeof( CompositionControl ) );
|
||||
|
||||
builder.setVertexShader( Shader::loadVertex( "shaders/fullscreen.vert" ) );
|
||||
builder.setFragmentShader( Shader::loadFragment( "shaders/composition.frag" ) );
|
||||
builder.setVertexShader( Shader::loadVertex( "shaders/composition.slang" ) );
|
||||
builder.setFragmentShader( Shader::loadFragment( "shaders/composition.slang" ) );
|
||||
|
||||
builder.disableCulling();
|
||||
builder.disableVertexInput();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Shader.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
|
||||
#include "engine/debug/logging/logging.hpp"
|
||||
#include "engine/rendering/devices/Device.hpp"
|
||||
@@ -13,19 +14,35 @@
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
std::vector< std::byte > Shader::loadData( const std::filesystem::path& path )
|
||||
std::string entrypointName( const ShaderType type, vk::PipelineShaderStageCreateInfo& info )
|
||||
{
|
||||
std::string str {};
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case Vertex:
|
||||
str = "vertexMain";
|
||||
break;
|
||||
case Fragment:
|
||||
str = "fragmentMain";
|
||||
break;
|
||||
case Compute:
|
||||
str = "computeMain";
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error( "Invalid shader stage flags" );
|
||||
}
|
||||
|
||||
info.setPName( str.c_str() );
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
std::vector< std::byte > Shader::loadData( const std::filesystem::path& path, const ShaderType type )
|
||||
{
|
||||
if ( auto ifs = std::ifstream( path, std::ios::binary | std::ios::ate ); ifs )
|
||||
{
|
||||
std::vector< std::byte > data {};
|
||||
data.resize( ifs.tellg() );
|
||||
ifs.seekg( 0, std::ios::beg );
|
||||
|
||||
static_assert( sizeof( std::ifstream::char_type ) == sizeof( std::byte ) );
|
||||
|
||||
ifs.read( reinterpret_cast< std::ifstream::char_type* >( data.data() ), data.size() );
|
||||
|
||||
return compileShader( path.filename().string(), data );
|
||||
return compileShader( path, type );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -45,28 +62,32 @@ namespace fgl::engine
|
||||
return module_info;
|
||||
}
|
||||
|
||||
Shader::Shader( const std::filesystem::path& path, const vk::PipelineShaderStageCreateInfo& info ) :
|
||||
m_path( path ),
|
||||
shader_data( loadData( m_path ) ),
|
||||
module_create_info( createModuleInfo() ),
|
||||
Shader::Shader( std::filesystem::path path, const vk::PipelineShaderStageCreateInfo& info, const ShaderType type ) :
|
||||
m_type( type ),
|
||||
stage_info( info ),
|
||||
m_entrypoint_name( entrypointName( type, stage_info ) ),
|
||||
m_path( std::move( path ) ),
|
||||
shader_data( loadData( m_path, type ) ),
|
||||
module_create_info( createModuleInfo() ),
|
||||
shader_module( Device::getInstance()->createShaderModule( module_create_info ) )
|
||||
{
|
||||
FGL_ASSERT( stage_info.pName == m_entrypoint_name.c_str(), "Entry point name mismatch" );
|
||||
log::debug( "Created shader {}", stage_info.pName );
|
||||
stage_info.module = shader_module;
|
||||
}
|
||||
|
||||
std::shared_ptr< Shader > Shader::
|
||||
loadShader( std::filesystem::path path, const vk::ShaderStageFlagBits stage_flags )
|
||||
std::shared_ptr< Shader > Shader::loadShader(
|
||||
const std::filesystem::path& path, const vk::ShaderStageFlagBits stage_flags, const ShaderType type )
|
||||
{
|
||||
std::filesystem::path full_path { std::filesystem::current_path() / path };
|
||||
|
||||
vk::PipelineShaderStageCreateInfo stage_info {};
|
||||
stage_info.stage = stage_flags;
|
||||
stage_info.flags = {};
|
||||
stage_info.pName = "main";
|
||||
stage_info.pName = nullptr;
|
||||
stage_info.pSpecializationInfo = VK_NULL_HANDLE;
|
||||
|
||||
auto shader { std::make_shared< Shader >( path, stage_info ) };
|
||||
auto shader { std::make_shared< Shader >( path, stage_info, type ) };
|
||||
|
||||
return shader;
|
||||
}
|
||||
@@ -74,7 +95,7 @@ namespace fgl::engine
|
||||
void Shader::reload()
|
||||
{
|
||||
log::debug( "Reloading shader at {}", m_path.string() );
|
||||
shader_data = loadData( m_path );
|
||||
shader_data = loadData( m_path, m_type );
|
||||
module_create_info = createModuleInfo();
|
||||
shader_module = Device::getInstance()->createShaderModule( module_create_info );
|
||||
stage_info.module = shader_module;
|
||||
|
||||
@@ -8,22 +8,26 @@
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "shaders/Compiler.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
struct Shader
|
||||
{
|
||||
ShaderType m_type;
|
||||
vk::PipelineShaderStageCreateInfo stage_info;
|
||||
std::string m_entrypoint_name;
|
||||
std::filesystem::path m_path;
|
||||
std::vector< std::byte > shader_data;
|
||||
vk::ShaderModuleCreateInfo module_create_info;
|
||||
vk::PipelineShaderStageCreateInfo stage_info;
|
||||
|
||||
vk::raii::ShaderModule shader_module;
|
||||
|
||||
static std::vector< std::byte > loadData( const std::filesystem::path& );
|
||||
static std::vector< std::byte > loadData( const std::filesystem::path&, ShaderType type );
|
||||
vk::ShaderModuleCreateInfo createModuleInfo() const;
|
||||
|
||||
Shader( const std::filesystem::path& path, const vk::PipelineShaderStageCreateInfo& info );
|
||||
Shader( std::filesystem::path path, const vk::PipelineShaderStageCreateInfo& info, ShaderType type );
|
||||
|
||||
Shader( const Shader& other ) = delete;
|
||||
|
||||
@@ -33,16 +37,17 @@ namespace fgl::engine
|
||||
|
||||
Shader& operator=( Shader&& other ) = delete;
|
||||
|
||||
static std::shared_ptr< Shader > loadShader( std::filesystem::path path, vk::ShaderStageFlagBits stage_flags );
|
||||
static std::shared_ptr< Shader >
|
||||
loadShader( const std::filesystem::path& path, vk::ShaderStageFlagBits stage_flags, ShaderType type );
|
||||
|
||||
inline static std::shared_ptr< Shader > loadVertex( std::filesystem::path path )
|
||||
static std::shared_ptr< Shader > loadVertex( const std::filesystem::path& path )
|
||||
{
|
||||
return loadShader( path, vk::ShaderStageFlagBits::eVertex );
|
||||
return loadShader( path, vk::ShaderStageFlagBits::eVertex, ShaderType::Vertex );
|
||||
}
|
||||
|
||||
inline static std::shared_ptr< Shader > loadFragment( std::filesystem::path path )
|
||||
static std::shared_ptr< Shader > loadFragment( const std::filesystem::path& path )
|
||||
{
|
||||
return loadShader( path, vk::ShaderStageFlagBits::eFragment );
|
||||
return loadShader( path, vk::ShaderStageFlagBits::eFragment, ShaderType::Fragment );
|
||||
}
|
||||
|
||||
//! Reloads the shader from disk
|
||||
|
||||
@@ -6,200 +6,161 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <slang-com-ptr.h>
|
||||
|
||||
#include "engine/FGL_DEFINES.hpp"
|
||||
#include "engine/constants.hpp"
|
||||
#include "engine/debug/logging/logging.hpp"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Weffc++"
|
||||
#include <shaderc/shaderc.hpp>
|
||||
#pragma GCC diagnostic pop
|
||||
#include "rendering/pipelines/Shader.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
inline static std::unique_ptr< shaderc::Compiler > compiler;
|
||||
|
||||
shaderc::Compiler& getInstance()
|
||||
void checkDiag( Slang::ComPtr< slang::IBlob >& diag )
|
||||
{
|
||||
if ( !compiler )
|
||||
{
|
||||
compiler = std::make_unique< shaderc::Compiler >();
|
||||
}
|
||||
if ( !diag ) return;
|
||||
|
||||
FGL_ASSERT( compiler, "Compiler invalid!" );
|
||||
|
||||
return *compiler;
|
||||
log::error( static_cast< const char* >( diag->getBufferPointer() ) );
|
||||
throw std::logic_error( "unexpected diagnostic" );
|
||||
}
|
||||
|
||||
shaderc_shader_kind getShaderKindFromName( const std::string_view str )
|
||||
{
|
||||
if ( str.ends_with( ".frag" ) ) return shaderc_shader_kind::shaderc_fragment_shader;
|
||||
if ( str.ends_with( ".vert" ) ) return shaderc_shader_kind::shaderc_vertex_shader;
|
||||
struct ShaderVertexFlags
|
||||
{};
|
||||
|
||||
throw std::runtime_error( "Unknown shader type!" );
|
||||
}
|
||||
struct ShaderFragmentFlags
|
||||
{};
|
||||
|
||||
class Includer : public shaderc::CompileOptions::IncluderInterface
|
||||
using ShaderLayoutFlags = std::variant< ShaderVertexFlags, ShaderFragmentFlags >;
|
||||
|
||||
std::vector< std::byte > compileShader( const std::filesystem::path& path, const ShaderType type )
|
||||
{
|
||||
struct DataHolder
|
||||
{
|
||||
std::filesystem::path source_path {};
|
||||
std::vector< char > content {};
|
||||
using namespace slang;
|
||||
|
||||
Slang::ComPtr< IGlobalSession > global_session {};
|
||||
SlangGlobalSessionDesc global_desc {};
|
||||
|
||||
global_desc.enableGLSL = true;
|
||||
|
||||
createGlobalSession( &global_desc, global_session.writeRef() );
|
||||
|
||||
SessionDesc session_desc {};
|
||||
|
||||
std::array< CompilerOptionEntry, 1 > options {
|
||||
{ { CompilerOptionName::VulkanUseEntryPointName,
|
||||
{ .kind = CompilerOptionValueKind::Int, .intValue0 = 1 } } }
|
||||
};
|
||||
|
||||
shaderc_include_result* GetInclude(
|
||||
const char* requested_source,
|
||||
shaderc_include_type type,
|
||||
const char* requesting_source,
|
||||
size_t include_depth ) override;
|
||||
session_desc.compilerOptionEntries = options.data();
|
||||
session_desc.compilerOptionEntryCount = options.size();
|
||||
|
||||
void ReleaseInclude( shaderc_include_result* data ) override;
|
||||
};
|
||||
TargetDesc target_desc {};
|
||||
target_desc.format = SLANG_SPIRV;
|
||||
target_desc.profile = global_session->findProfile( "glsl_450" );
|
||||
|
||||
shaderc_include_result* Includer::GetInclude(
|
||||
const char* requested_source,
|
||||
[[maybe_unused]] shaderc_include_type type,
|
||||
const char* requesting_source,
|
||||
[[maybe_unused]] size_t include_depth )
|
||||
{
|
||||
const std::string_view requsted { requested_source };
|
||||
const std::string_view requster { requesting_source };
|
||||
FGL_ASSERT( target_desc.profile != SLANG_PROFILE_UNKNOWN, "Invalid profile" );
|
||||
|
||||
std::vector< char > file_data {};
|
||||
session_desc.targets = &target_desc;
|
||||
session_desc.targetCount = 1;
|
||||
|
||||
const auto path { std::filesystem::current_path() / "shaders" / requsted };
|
||||
const auto search_path { std::filesystem::path() / "shaders" };
|
||||
const std::string search_path_str { search_path.string() };
|
||||
const char* const search_pathr_str_ptr { search_path_str.data() };
|
||||
session_desc.searchPaths = &search_pathr_str_ptr;
|
||||
session_desc.searchPathCount = 1;
|
||||
|
||||
if ( std::ifstream ifs( path ); ifs )
|
||||
Slang::ComPtr< ISession > session {};
|
||||
global_session->createSession( session_desc, session.writeRef() );
|
||||
|
||||
const auto module_name { path.filename().string() };
|
||||
|
||||
Slang::ComPtr< IBlob > diagnostics;
|
||||
IModule* module { session->loadModule( module_name.c_str(), diagnostics.writeRef() ) };
|
||||
|
||||
checkDiag( diagnostics );
|
||||
|
||||
FGL_ASSERT( module != nullptr, "Invalid module" );
|
||||
|
||||
std::string entry_point_name {};
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
file_data.resize( std::filesystem::file_size( path ) );
|
||||
|
||||
ifs.read( file_data.data(), file_data.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
log::error( "Failed to find include {} for {}", path, requster );
|
||||
//throw std::runtime_error( std::format( "Failed to open include file {} for file {}", requsted, requster ) );
|
||||
|
||||
auto error_return { new shaderc_include_result() };
|
||||
error_return->user_data = nullptr;
|
||||
error_return->source_name = "";
|
||||
error_return->source_name_length = 0;
|
||||
error_return->content = "Failed to find include for requsted file";
|
||||
|
||||
return error_return;
|
||||
}
|
||||
|
||||
auto* data_holder { new DataHolder( path, std::move( file_data ) ) };
|
||||
|
||||
auto data { new shaderc_include_result() };
|
||||
data->user_data = data_holder;
|
||||
data->content = data_holder->content.data();
|
||||
data->content_length = data_holder->content.size();
|
||||
data->source_name = data_holder->source_path.c_str();
|
||||
data->source_name_length = data_holder->source_path.string().size();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void Includer::ReleaseInclude( shaderc_include_result* data )
|
||||
{
|
||||
delete static_cast< DataHolder* >( data->user_data );
|
||||
delete data;
|
||||
}
|
||||
|
||||
std::vector< std::byte > compileShader( const std::string_view input_name, const std::vector< std::byte >& input )
|
||||
{
|
||||
shaderc::CompileOptions options {};
|
||||
|
||||
options.SetTargetEnvironment( shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_3 );
|
||||
|
||||
options.SetIncluder( std::make_unique< Includer >() );
|
||||
|
||||
#ifndef NDEBUG
|
||||
options.SetOptimizationLevel( shaderc_optimization_level_zero );
|
||||
#else
|
||||
options.SetOptimizationLevel( shaderc_optimization_level_performance );
|
||||
#endif
|
||||
|
||||
options.SetVulkanRulesRelaxed( false );
|
||||
|
||||
// Add macro defs to the shader
|
||||
options.AddMacroDefinition( "INVALID_TEXTURE_ID", std::to_string( constants::INVALID_TEXTURE_ID ) );
|
||||
options.AddMacroDefinition( "NEAR_PLANE", std::to_string( constants::NEAR_PLANE ) );
|
||||
options.AddMacroDefinition( "FAR_PLANE", std::to_string( constants::FAR_PLANE ) );
|
||||
|
||||
// Helpful constants
|
||||
options.AddMacroDefinition( "PI", std::to_string( std::numbers::pi_v< float > ) );
|
||||
|
||||
const shaderc_shader_kind kind { getShaderKindFromName( input_name ) };
|
||||
|
||||
const auto preprocessed_source { getInstance().PreprocessGlsl(
|
||||
reinterpret_cast< const char* >( input.data() ), input.size(), kind, input_name.data(), options ) };
|
||||
|
||||
const auto result { getInstance().CompileGlslToSpv(
|
||||
reinterpret_cast< const char* >( input.data() ), input.size(), kind, input_name.data(), options ) };
|
||||
|
||||
switch ( result.GetCompilationStatus() )
|
||||
{
|
||||
case shaderc_compilation_status_success:
|
||||
case ShaderType::Compute:
|
||||
entry_point_name = "computeMain";
|
||||
break;
|
||||
case Vertex:
|
||||
entry_point_name = "vertexMain";
|
||||
break;
|
||||
case Fragment:
|
||||
entry_point_name = "fragmentMain";
|
||||
break;
|
||||
case shaderc_compilation_status_compilation_error:
|
||||
log::critical(
|
||||
"Compilation error when compiling shader {} with error: {}", input_name, result.GetErrorMessage() );
|
||||
throw std::runtime_error( "Failed to compile shader" );
|
||||
default:
|
||||
[[fallthrough]];
|
||||
case shaderc_compilation_status_internal_error:
|
||||
log::critical(
|
||||
"internal error while compiling shader {} with error: {}", input_name, result.GetErrorMessage() );
|
||||
throw std::runtime_error( "Failed to compile shader" );
|
||||
[[fallthrough]];
|
||||
case shaderc_compilation_status_null_result_object:
|
||||
log::critical(
|
||||
"null result object when compiling shader {} with error: {}",
|
||||
input_name,
|
||||
result.GetErrorMessage() );
|
||||
throw std::runtime_error( "Failed to compile shader" );
|
||||
[[fallthrough]];
|
||||
case shaderc_compilation_status_invalid_assembly:
|
||||
log::critical( "Failed to compile shader {} with error: {}", input_name, result.GetErrorMessage() );
|
||||
throw std::runtime_error( "Failed to compile shader" );
|
||||
[[fallthrough]];
|
||||
case shaderc_compilation_status_validation_error:
|
||||
log::critical( "Failed to compile shader {} with error: {}", input_name, result.GetErrorMessage() );
|
||||
throw std::runtime_error( "Failed to compile shader" );
|
||||
case shaderc_compilation_status_transformation_error:
|
||||
log::critical( "Failed to compile shader {} with error: {}", input_name, result.GetErrorMessage() );
|
||||
throw std::runtime_error( "Failed to compile shader" );
|
||||
case shaderc_compilation_status_invalid_stage:
|
||||
log::critical( "Failed to compile shader {} with error: {}", input_name, result.GetErrorMessage() );
|
||||
throw std::runtime_error( "Failed to compile shader" );
|
||||
case shaderc_compilation_status_configuration_error:
|
||||
log::critical( "Failed to compile shader {} with error: {}", input_name, result.GetErrorMessage() );
|
||||
throw std::runtime_error( "Failed to compile shader" );
|
||||
break;
|
||||
throw std::logic_error( "Invalid shader type" );
|
||||
}
|
||||
|
||||
log::debug( "Compiled shader {}", input_name );
|
||||
Slang::ComPtr< IEntryPoint > entry_point {};
|
||||
module->findEntryPointByName( entry_point_name.c_str(), entry_point.writeRef() );
|
||||
|
||||
std::vector< std::byte > output {};
|
||||
output.reserve( result.cend() - result.cbegin() );
|
||||
std::array< IComponentType*, 2 > components { module, entry_point };
|
||||
Slang::ComPtr< IComponentType > program;
|
||||
session->createCompositeComponentType(
|
||||
components.data(), components.size(), program.writeRef(), diagnostics.writeRef() );
|
||||
checkDiag( diagnostics );
|
||||
|
||||
Slang::ComPtr< IComponentType > linked_program {};
|
||||
|
||||
program->link( linked_program.writeRef(), diagnostics.writeRef() );
|
||||
checkDiag( diagnostics );
|
||||
|
||||
const auto parent_path { path.parent_path() };
|
||||
|
||||
for ( const auto& word : result )
|
||||
{
|
||||
output.insert(
|
||||
output.end(),
|
||||
reinterpret_cast< const std::byte* >( &word ),
|
||||
reinterpret_cast< const std::byte* >( &word ) + sizeof( std::remove_reference_t< decltype( word ) > ) );
|
||||
slang::ProgramLayout* layout { linked_program->getLayout() };
|
||||
|
||||
Slang::ComPtr< IBlob > json_glob {};
|
||||
layout->toJson( json_glob.writeRef() );
|
||||
|
||||
log::debug(
|
||||
"Shader layout: {}",
|
||||
std::string_view(
|
||||
static_cast< const char* >( json_glob->getBufferPointer() ), json_glob->getBufferSize() ) );
|
||||
|
||||
/*
|
||||
if ( std::ofstream
|
||||
ofs( path.parent_path()
|
||||
/ std::format( "{}-{}.json", path.filename().string(), entry_point_name ) );
|
||||
ofs )
|
||||
{
|
||||
ofs.write( static_cast< const char* >( json_glob->getBufferPointer() ), json_glob->getBufferSize() );
|
||||
}
|
||||
*/
|
||||
|
||||
FGL_ASSERT( layout != nullptr, "Layout must be valid" );
|
||||
}
|
||||
|
||||
// Should be a multiple of 4
|
||||
assert( output.size() % 4 == 0 );
|
||||
assert( output.size() > 0 );
|
||||
int entry_index { 0 };
|
||||
int target_index { 0 };
|
||||
|
||||
return output;
|
||||
Slang::ComPtr< IBlob > kernel_blob {};
|
||||
linked_program->getEntryPointCode( entry_index, target_index, kernel_blob.writeRef(), diagnostics.writeRef() );
|
||||
checkDiag( diagnostics );
|
||||
|
||||
FGL_ASSERT( kernel_blob != nullptr, "Kernel blob is not valid" );
|
||||
|
||||
log::debug( "Compiled shader {} with a length of {}", path.filename().string(), kernel_blob->getBufferSize() );
|
||||
|
||||
// if ( std::ofstream ofs( parent_path / std::format( "{}-{}.bin", path.filename().string(), entry_point_name ) );
|
||||
// ofs )
|
||||
// {
|
||||
// ofs.write(
|
||||
// static_cast< const std::ostream::char_type* >( kernel_blob->getBufferPointer() ),
|
||||
// kernel_blob->getBufferSize() );
|
||||
// }
|
||||
|
||||
std::vector< std::byte > compiled_code {};
|
||||
compiled_code.resize( kernel_blob->getBufferSize() );
|
||||
std::memcpy( compiled_code.data(), kernel_blob->getBufferPointer(), kernel_blob->getBufferSize() );
|
||||
|
||||
return compiled_code;
|
||||
}
|
||||
|
||||
} // namespace fgl::engine
|
||||
|
||||
@@ -3,19 +3,18 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <string_view>
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
namespace shaderc
|
||||
{
|
||||
class Compiler;
|
||||
}
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
enum ShaderType
|
||||
{
|
||||
Vertex,
|
||||
Fragment,
|
||||
Compute
|
||||
};
|
||||
|
||||
shaderc::Compiler& getInstance();
|
||||
|
||||
std::vector< std::byte > compileShader( const std::string_view input_name, const std::vector< std::byte >& input );
|
||||
std::vector< std::byte > compileShader( const std::filesystem::path& input_name, ShaderType type );
|
||||
|
||||
} // namespace fgl::engine
|
||||
@@ -25,8 +25,8 @@ namespace fgl::engine
|
||||
builder.setAttributeDescriptions( SimpleVertex::getAttributeDescriptions() );
|
||||
builder.setBindingDescriptions( SimpleVertex::getBindingDescriptions() );
|
||||
|
||||
builder.setVertexShader( Shader::loadVertex( "shaders/fullscreen.vert" ) );
|
||||
builder.setFragmentShader( Shader::loadFragment( "shaders/gui-compose.frag" ) );
|
||||
builder.setVertexShader( Shader::loadVertex( "shaders/gui-compose.slang" ) );
|
||||
builder.setFragmentShader( Shader::loadFragment( "shaders/gui-compose.slang" ) );
|
||||
|
||||
builder.addColorAttachment().setFormat( pickPresentFormat() ).finish();
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace fgl::engine
|
||||
{
|
||||
ZoneScoped;
|
||||
|
||||
/*
|
||||
{
|
||||
// PipelineConfigInfo standard_info { render_pass };
|
||||
// PipelineConfigInfo::addGBufferAttachmentsConfig( standard_info );
|
||||
@@ -42,6 +43,7 @@ namespace fgl::engine
|
||||
|
||||
m_standard_pipeline->setDebugName( "Standard entity pipeline" );
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
// PipelineConfigInfo textured_info { render_pass };
|
||||
@@ -55,8 +57,8 @@ namespace fgl::engine
|
||||
builder.addDescriptorSet( Texture::getDescriptorLayout() );
|
||||
builder.addDescriptorSet( Material::getDescriptorLayout() );
|
||||
|
||||
builder.setFragmentShader( Shader::loadFragment( "shaders/textured-gbuffer.frag" ) );
|
||||
builder.setVertexShader( Shader::loadVertex( "shaders/textured-gbuffer.vert" ) );
|
||||
builder.setFragmentShader( Shader::loadFragment( "shaders/textured.slang" ) );
|
||||
builder.setVertexShader( Shader::loadVertex( "shaders/textured.slang" ) );
|
||||
|
||||
builder.setAttributeDescriptions( ModelVertex::getAttributeDescriptions() );
|
||||
builder.setBindingDescriptions( ModelVertex::getBindingDescriptions() );
|
||||
|
||||
@@ -37,8 +37,8 @@ namespace fgl::engine
|
||||
|
||||
builder.setTopology( vk::PrimitiveTopology::eLineList );
|
||||
|
||||
builder.setVertexShader( Shader::loadVertex( "shaders/line.vert" ) );
|
||||
builder.setFragmentShader( Shader::loadFragment( "shaders/line.frag" ) );
|
||||
builder.setVertexShader( Shader::loadVertex( "shaders/line.slang" ) );
|
||||
builder.setFragmentShader( Shader::loadFragment( "shaders/line.slang" ) );
|
||||
|
||||
builder.addDynamicState( vk::DynamicState::eLineWidth );
|
||||
|
||||
|
||||
16
src/shaders/camera.slang
Normal file
16
src/shaders/camera.slang
Normal file
@@ -0,0 +1,16 @@
|
||||
#version 450
|
||||
|
||||
module camera;
|
||||
|
||||
public struct CameraData
|
||||
{
|
||||
public mat4x4 projection : CAMERA_PROJECTION;
|
||||
public mat4x4 view : CAMERA_VIEW;
|
||||
public mat4x4 inverse_view : CAMERA_INVERSE_VIEW;
|
||||
|
||||
public vec3 getPos()
|
||||
{
|
||||
return vec3( inverse_view[ 3 ][ 0 ], inverse_view[ 3 ][ 1 ], inverse_view[ 3 ][ 2 ] );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
#version 450
|
||||
|
||||
layout (input_attachment_index = 0, binding = 0) uniform subpassInput i_color;
|
||||
layout (input_attachment_index = 1, binding = 1) uniform subpassInput i_position;
|
||||
layout (input_attachment_index = 2, binding = 2) uniform subpassInput i_normal;
|
||||
layout (input_attachment_index = 3, binding = 3) uniform subpassInput i_metallic;
|
||||
//layout (input_attachment_index = 4, binding = 4) uniform subpassInput i_specular;
|
||||
layout (input_attachment_index = 4, binding = 4) uniform subpassInput i_emissive;
|
||||
|
||||
layout (location = 0) in vec2 in_uv;
|
||||
|
||||
layout (location = 0) out vec4 out_color;
|
||||
|
||||
layout (set = 1, binding = 0) uniform CameraInfo {
|
||||
mat4 projection;
|
||||
mat4 view;
|
||||
mat4 inverse_view;
|
||||
} camera_info;
|
||||
|
||||
layout(push_constant) uniform Constants {
|
||||
uint flags;
|
||||
} push;
|
||||
|
||||
//TODO: uniform binding with sun information
|
||||
|
||||
vec3 getCameraPosition()
|
||||
{
|
||||
return vec3(
|
||||
camera_info.inverse_view[3][0],
|
||||
camera_info.inverse_view[3][1],
|
||||
camera_info.inverse_view[3][2]
|
||||
);
|
||||
}
|
||||
|
||||
vec3 sun_dir = normalize(vec3(-1.0, -1.0, -1.0));
|
||||
|
||||
// GGX/Towbridge-Reitz normal distribution function.
|
||||
// Uses Disney's reparametrization of alpha = roughness^2.
|
||||
float ndfGGX(float cosLh, float roughness)
|
||||
{
|
||||
float alpha = roughness * roughness;
|
||||
float alphaSq = alpha * alpha;
|
||||
|
||||
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||
return alphaSq / (PI * denom * denom);
|
||||
}
|
||||
|
||||
// Single term for separable Schlick-GGX below.
|
||||
float gaSchlickG1(float cosTheta, float k)
|
||||
{
|
||||
return cosTheta / (cosTheta * (1.0 - k) + k);
|
||||
}
|
||||
|
||||
// Schlick-GGX approximation of geometric attenuation function using Smith's method.
|
||||
float gaSchlickGGX(float cosLi, float cosLo, float roughness)
|
||||
{
|
||||
float r = roughness + 1.0;
|
||||
float k = (r * r) / 8.0;// Epic suggests using this roughness remapping for analytic lights.
|
||||
return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k);
|
||||
}
|
||||
|
||||
//TODO: Apparently this can be gotten from a texture instead?
|
||||
vec3 schlick(vec3 F0, float cosTheta)
|
||||
{
|
||||
return F0 + (vec3(1.0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
const vec3 albedo = subpassLoad(i_color).xyz;
|
||||
|
||||
const vec3 position = subpassLoad(i_position).xyz;
|
||||
const vec3 normal = subpassLoad(i_normal).xyz;
|
||||
|
||||
// metallic, roughness, occlusion
|
||||
// r, g, b
|
||||
const vec3 metallic_comb = subpassLoad(i_metallic).xyz;
|
||||
|
||||
// split the channels of ease of use
|
||||
const float metallic_value = metallic_comb.r;
|
||||
const float roughness_value = metallic_comb.g;
|
||||
const float occlusion = metallic_comb.b;
|
||||
|
||||
const vec3 camera_pos = getCameraPosition();
|
||||
|
||||
// Calculate the vector from the world position to the camera
|
||||
const vec3 Lo = normalize(camera_pos - position);
|
||||
const vec3 N = normalize(normal);
|
||||
|
||||
float cosLo = max(dot(N, Lo), 0.0);
|
||||
|
||||
// Specular reflection
|
||||
// vec3 Lr = 2.0 * cosLo * N - Lo;
|
||||
vec3 Lr = reflect(-Lo, N);
|
||||
|
||||
const vec3 fresnel_factor = vec3(0.04);
|
||||
|
||||
// Fresnel
|
||||
vec3 F0 = mix(fresnel_factor, albedo, metallic_value);
|
||||
|
||||
vec3 direct_lighting = vec3(0.0);
|
||||
|
||||
// Do this for each light
|
||||
// {
|
||||
vec3 Li = -sun_dir;
|
||||
vec3 Lradiance = vec3(1.0);// color?
|
||||
|
||||
// half vector
|
||||
vec3 Lh = normalize(Li + Lo);
|
||||
|
||||
float cosLi = max(dot(N, Li), 0.0);
|
||||
float cosLh = max(dot(N, Lh), 0.0);
|
||||
|
||||
//float cosTheta = max(dot(Lh, Lo), 0.0);
|
||||
float cosTheta = dot(Li, N);
|
||||
|
||||
vec3 F = schlick(F0, cosTheta);
|
||||
float D = ndfGGX(cosLh, roughness_value);
|
||||
float G = gaSchlickGGX(cosLi, cosLo, roughness_value);
|
||||
|
||||
vec3 kb = mix(vec3(1.0) - F, vec3(0.0), metallic_value);
|
||||
vec3 diffuse_BRDF = kb * albedo;
|
||||
vec3 specular_BRDF = (F * D * G) / max(0.04, 4.0 * cosLi * cosLo);
|
||||
|
||||
direct_lighting = (diffuse_BRDF + specular_BRDF) * Lradiance * cosLi;
|
||||
// }
|
||||
|
||||
vec3 ambient_lighting = albedo * 0.1;
|
||||
|
||||
switch (push.flags)
|
||||
{
|
||||
case 0:
|
||||
out_color = vec4(direct_lighting + ambient_lighting, 1.0);
|
||||
return;
|
||||
case 1:
|
||||
out_color = vec4(direct_lighting, 1.0);
|
||||
return;
|
||||
case 2:
|
||||
out_color = vec4(ambient_lighting, 1.0);
|
||||
return;
|
||||
}
|
||||
|
||||
out_color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
151
src/shaders/composition.slang
Normal file
151
src/shaders/composition.slang
Normal file
@@ -0,0 +1,151 @@
|
||||
#version 450
|
||||
|
||||
import camera;
|
||||
|
||||
struct Vertex {
|
||||
vec2 uv;
|
||||
vec4 position : SV_Position;
|
||||
};
|
||||
|
||||
[shader("vertex")]
|
||||
Vertex vertexMain( uint index : SV_VertexID )
|
||||
{
|
||||
Vertex vertex;
|
||||
vertex.uv = vec2( ( index << 1 ) & 2, index & 2 );
|
||||
vertex.position = vec4( vertex.uv * 2.0 - 1.0f, 0.0f, 0.0f );
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
struct CompositeFragment {
|
||||
vec4 color;
|
||||
}
|
||||
|
||||
struct GBufferInput {
|
||||
SubpassInput<vec4> color : COLOR;
|
||||
SubpassInput<vec4> position : POSITION;
|
||||
SubpassInput<vec4> normal : NORMAL;
|
||||
SubpassInput<vec4> metallic : METALLIC;
|
||||
SubpassInput<vec4> emissive : EMISSIVE;
|
||||
};
|
||||
|
||||
// SubpassInput< vec4 > test : TEST;
|
||||
|
||||
ParameterBlock<GBufferInput> gbuffer : GBUFFER;
|
||||
|
||||
// SubpassInput<vec4> color : COLOR;
|
||||
// SubpassInput<vec4> position : POSITION;
|
||||
// SubpassInput<vec4> normal : NORMAL;
|
||||
// SubpassInput<vec4> metallic : METALLIC;
|
||||
// SubpassInput<vec4> emissive : EMISSIVE;
|
||||
|
||||
[[vk::binding(0,1)]]
|
||||
ParameterBlock< CameraData > camera : CAMERA;
|
||||
|
||||
//TODO: constant flags
|
||||
|
||||
vec3 sun_dir = normalize(vec3(-1.0, -1.0, -1.0));
|
||||
|
||||
// GGX/Towbridge-Reitz normal distribution function.
|
||||
// Uses Disney's reparametrization of alpha = roughness^2.
|
||||
float ndfGGX(float cosLh, float roughness)
|
||||
{
|
||||
float alpha = roughness * roughness;
|
||||
float alphaSq = alpha * alpha;
|
||||
|
||||
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||
return alphaSq / (3.145 * denom * denom);
|
||||
}
|
||||
|
||||
// Single term for separable Schlick-GGX below.
|
||||
float gaSchlickG1(float cosTheta, float k)
|
||||
{
|
||||
return cosTheta / (cosTheta * (1.0 - k) + k);
|
||||
}
|
||||
|
||||
// Schlick-GGX approximation of geometric attenuation function using Smith's method.
|
||||
float gaSchlickGGX(float cosLi, float cosLo, float roughness)
|
||||
{
|
||||
float r = roughness + 1.0;
|
||||
float k = (r * r) / 8.0;// Epic suggests using this roughness remapping for analytic lights.
|
||||
return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k);
|
||||
}
|
||||
|
||||
//TODO: Apparently this can be gotten from a texture instead?
|
||||
vec3 schlick(vec3 F0, float cosTheta)
|
||||
{
|
||||
return F0 + (vec3(1.0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
|
||||
}
|
||||
|
||||
|
||||
[shader("fragment")]
|
||||
CompositeFragment fragmentMain( Vertex vertex )
|
||||
{
|
||||
// const vec3 test_sample = test.SubpassLoad().xyz;
|
||||
// const vec3 albedo = gbuffer.color.SubpassLoad().xyz * test_sample;
|
||||
const vec3 albedo = gbuffer.color.SubpassLoad().xyz;
|
||||
|
||||
const vec3 position = gbuffer.position.SubpassLoad().xyz;
|
||||
const vec3 normal = gbuffer.normal.SubpassLoad().xyz;
|
||||
|
||||
// metallic, roughness, occlusion
|
||||
// r, g, b
|
||||
const vec3 metallic_comb = gbuffer.metallic.SubpassLoad().xyz;
|
||||
|
||||
/*
|
||||
const vec3 albedo = color.SubpassLoad().xyz;
|
||||
|
||||
const vec3 position = position.SubpassLoad().xyz;
|
||||
const vec3 normal = normal.SubpassLoad().xyz;
|
||||
|
||||
// metallic, roughness, occlusion
|
||||
// r, g, b
|
||||
const vec3 metallic_comb = metallic.SubpassLoad().xyz;
|
||||
*/
|
||||
|
||||
const float metallic = metallic_comb.r;
|
||||
const float roughness = metallic_comb.g;
|
||||
const float occlusion = metallic_comb.b;
|
||||
|
||||
const vec3 camera_pos = camera.getPos();
|
||||
|
||||
const vec3 Lo = normalize( camera_pos - position );
|
||||
const vec3 N = normalize( normal );
|
||||
|
||||
float cosLo = max(dot(N, Lo), 0.0);
|
||||
|
||||
vec3 Lr = reflect( -Lo, N );
|
||||
|
||||
const vec3 fresnel_factor = vec3( 0.04 );
|
||||
|
||||
vec3 F0 = mix( fresnel_factor, albedo, metallic );
|
||||
|
||||
vec3 direct_lighting = vec3( 0.0 );
|
||||
|
||||
vec3 Li = -sun_dir;
|
||||
vec3 Lradiance = vec3(1.0);
|
||||
|
||||
vec3 Lh = normalize( Li + Lo );
|
||||
|
||||
float cosLi = max( dot( N, Li ), 0.0 );
|
||||
float cosLh = max( dot( N, Lh ), 0.0 );
|
||||
|
||||
float cosTheta = dot( Li, N );
|
||||
|
||||
vec3 F = schlick( F0, cosTheta );
|
||||
float D = ndfGGX( cosLh, roughness );
|
||||
float G = gaSchlickGGX( cosLi, cosLo, roughness );
|
||||
|
||||
vec3 kb = mix( vec3( 1.0 ) - F, vec3( 0.0 ), metallic );
|
||||
vec3 diffuse_BRDF = kb * albedo;
|
||||
vec3 specular_BRDF = ( F * D * G ) / max( 0.04, 4.0 * cosLi * cosLo );
|
||||
|
||||
direct_lighting = ( diffuse_BRDF + specular_BRDF ) * Lradiance * cosLi;
|
||||
|
||||
vec3 ambient_lighting = albedo * 0.1;
|
||||
|
||||
CompositeFragment frag;
|
||||
frag.color = vec4( direct_lighting + ambient_lighting, 1.0 );
|
||||
|
||||
return frag;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#version 450
|
||||
|
||||
// This vertex shader is meant to draw a single triangle on the entire screen butter so we can do full-screen effects.
|
||||
// There *might* be a better way to do this. But it works for now.
|
||||
|
||||
layout (location = 0) out vec2 out_uv;
|
||||
|
||||
out gl_PerVertex
|
||||
{
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
gl_Position = vec4(out_uv * 2.0f - 1.0f, 0.0f, 1.0f);
|
||||
}
|
||||
13
src/shaders/gbuffer.slang
Normal file
13
src/shaders/gbuffer.slang
Normal file
@@ -0,0 +1,13 @@
|
||||
#version 450
|
||||
|
||||
module gbuffer;
|
||||
|
||||
public struct GBufferFragment
|
||||
{
|
||||
public vec4 color : COLOR;
|
||||
public vec3 position : POSITION;
|
||||
public vec4 normal : NORMAL;
|
||||
public vec3 metallic : METALLIC;
|
||||
public vec3 emissive : EMISSIVE;
|
||||
};
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#version 450
|
||||
|
||||
//layout (input_attachment_index = 0, binding = 0) uniform subpassInput i_composite;
|
||||
|
||||
layout (location = 0) in vec2 in_uv;
|
||||
|
||||
layout (location = 0) out vec4 out_color;
|
||||
|
||||
void main() {
|
||||
// vec4 composite = subpassLoad(i_composite).xyzw;
|
||||
//
|
||||
// out_color = composite;
|
||||
out_color = vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
39
src/shaders/gui-compose.slang
Normal file
39
src/shaders/gui-compose.slang
Normal file
@@ -0,0 +1,39 @@
|
||||
#version 450
|
||||
|
||||
struct Vertex {
|
||||
vec2 uv;
|
||||
vec4 position : SV_Position;
|
||||
};
|
||||
|
||||
[shader("vertex")]
|
||||
Vertex vertexMain( uint index : SV_VertexID )
|
||||
{
|
||||
Vertex vertex;
|
||||
vertex.uv = vec2( ( index << 1 ) & 2, index & 2 );
|
||||
vertex.position = vec4( vertex.uv * 2.0 - 1.0f, 0.0f, 0.0f );
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
struct FragOut {
|
||||
vec4 color;
|
||||
}
|
||||
|
||||
[shader("fragment")]
|
||||
FragOut fragmentMain( Vertex vertex )
|
||||
{
|
||||
FragOut frag;
|
||||
|
||||
frag.color = vec4( 0.0f, 0.0f, 0.0f, 0.0f );
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 in_color;
|
||||
|
||||
#include "include/gbuffer_out.glsl"
|
||||
|
||||
void main() {
|
||||
out_color = vec4(in_color, 1.0f);
|
||||
out_normal = vec4(1.0f);
|
||||
out_position = gl_FragCoord.xyz;
|
||||
out_metallic = vec3(0.0, 0.0, 0.0);
|
||||
}
|
||||
42
src/shaders/line.slang
Normal file
42
src/shaders/line.slang
Normal file
@@ -0,0 +1,42 @@
|
||||
#version 450
|
||||
|
||||
import camera;
|
||||
import gbuffer;
|
||||
|
||||
struct LineVertex
|
||||
{
|
||||
float3 position : POSITION;
|
||||
float3 color : COLOR;
|
||||
};
|
||||
|
||||
struct VertexOut
|
||||
{
|
||||
float4 position : SV_Position;
|
||||
float3 color;
|
||||
};
|
||||
|
||||
[ [ vk::binding( 0, 1 ) ] ]
|
||||
ParameterBlock< CameraData > camera : CAMERA;
|
||||
|
||||
[shader("vertex")]
|
||||
VertexOut vertexMain( LineVertex vertex )
|
||||
{
|
||||
VertexOut out;
|
||||
|
||||
out.position = camera.projection * camera.view * vec4( vertex.position, 1.0 );
|
||||
out.color = vertex.color;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
[shader("fragment")]
|
||||
GBufferFragment fragmentMain( VertexOut vertex )
|
||||
{
|
||||
GBufferFragment fragment;
|
||||
fragment.color = vec4( vertex.color, 1.0f );
|
||||
fragment.normal = vec4( 1.0f, 1.0f, 1.0f, 1.0f );
|
||||
fragment.position = vertex.position.xyz;
|
||||
fragment.metallic = vec3( 0.0f, 0.0f, 0.0f );
|
||||
|
||||
return fragment;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 in_pos;
|
||||
layout(location = 1) in vec3 in_color;
|
||||
|
||||
#include "include/camera.glsl"
|
||||
|
||||
layout(location = 0) out vec3 out_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = ubo.projection * ubo.view * vec4(in_pos, 1.0);
|
||||
out_color = in_color;
|
||||
}
|
||||
71
src/shaders/material.slang
Normal file
71
src/shaders/material.slang
Normal file
@@ -0,0 +1,71 @@
|
||||
#version 450
|
||||
|
||||
module material;
|
||||
|
||||
public static const uint INVALID_TEXTURE_ID = 0;
|
||||
|
||||
public struct Albedo {
|
||||
public uint texture_id;
|
||||
public vec4 factors;
|
||||
|
||||
public bool isTexture()
|
||||
{
|
||||
return texture_id != INVALID_TEXTURE_ID;
|
||||
}
|
||||
};
|
||||
|
||||
public struct Metallic
|
||||
{
|
||||
public uint texture_id;
|
||||
public float metallic_factor;
|
||||
public float roughness_factor;
|
||||
|
||||
public bool isTexture()
|
||||
{
|
||||
return texture_id != INVALID_TEXTURE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
public struct Normal
|
||||
{
|
||||
public uint texture_id;
|
||||
public float scale;
|
||||
|
||||
public bool isTexture()
|
||||
{
|
||||
return texture_id != INVALID_TEXTURE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
public struct Occlusion
|
||||
{
|
||||
public uint texture_id;
|
||||
public float strength;
|
||||
|
||||
public bool isTexture()
|
||||
{
|
||||
return texture_id != INVALID_TEXTURE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
public struct Emissive
|
||||
{
|
||||
public uint texture_id;
|
||||
public vec3 factors;
|
||||
|
||||
public bool isTexture()
|
||||
{
|
||||
return texture_id != INVALID_TEXTURE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct Material
|
||||
{
|
||||
public Albedo color;
|
||||
public Metallic metallic;
|
||||
public Normal normal;
|
||||
public Occlusion occlusion;
|
||||
public Emissive emissive;
|
||||
}
|
||||
|
||||
20
src/shaders/model/vertex.slang
Normal file
20
src/shaders/model/vertex.slang
Normal file
@@ -0,0 +1,20 @@
|
||||
#version 450
|
||||
|
||||
module vertex;
|
||||
|
||||
public struct SimpleVertex
|
||||
{
|
||||
public vec3 position;
|
||||
public vec3 color;
|
||||
public vec3 normal;
|
||||
public vec2 uv;
|
||||
};
|
||||
|
||||
public struct ModelVertex
|
||||
{
|
||||
public SimpleVertex simple;
|
||||
public mat4x4 model_matrix;
|
||||
public uint material_id;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
#version 450
|
||||
#extension GL_EXT_nonuniform_qualifier: enable
|
||||
#extension GL_EXT_debug_printf: enable
|
||||
|
||||
layout (location = 0) in vec3 in_normal;
|
||||
layout (location = 1) in vec2 in_uv;
|
||||
layout (location = 2) in vec3 in_world_pos;
|
||||
layout (location = 3) in flat uint in_material_id;
|
||||
|
||||
#include "include/gbuffer_out.glsl"
|
||||
|
||||
layout (set = 1, binding = 0) uniform CameraInfo {
|
||||
mat4 projection;
|
||||
mat4 view;
|
||||
mat4 inverse_view;
|
||||
} camera_info;
|
||||
|
||||
layout (set = 2, binding = 0) uniform sampler2D tex[];
|
||||
|
||||
#include "include/material.glsl"
|
||||
|
||||
// Include all helper functions for glsl.
|
||||
#include "include/pbr.glsl"
|
||||
|
||||
float linearDepth(float depth)
|
||||
{
|
||||
float z = depth * 2.0f - 1.0f;
|
||||
return (2.0f * NEAR_PLANE * FAR_PLANE) / (FAR_PLANE + NEAR_PLANE - z * (FAR_PLANE - NEAR_PLANE));
|
||||
}
|
||||
|
||||
vec3 error_color = vec3(0.475, 0.0, 0.686);
|
||||
|
||||
float MIN_ROUGHNESS = 0.04;
|
||||
|
||||
void main()
|
||||
{
|
||||
out_position = in_world_pos;
|
||||
|
||||
vec3 diffuse_color;
|
||||
vec4 base_color;
|
||||
|
||||
vec3 f0 = vec3(0.04);
|
||||
|
||||
uint mat_id = in_material_id;
|
||||
|
||||
if (mat_id == INVALID_TEXTURE_ID)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
// The Vulkan-glTF-PBR example does some alpha mask stuff. I'm not exactly sure what it's used for
|
||||
// So for now we will just set the base_color to be the texture color
|
||||
uint color_texture_id = materials[mat_id].color_texture_id;
|
||||
if (color_texture_id != INVALID_TEXTURE_ID)
|
||||
{
|
||||
// Load the texture and multiply it against the color factors
|
||||
vec4 color = texture(tex[color_texture_id], in_uv).rgba;
|
||||
vec4 factors = materials[mat_id].color_factors;
|
||||
out_color = color * factors;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we have no color texture, Simply use the color factors as our color
|
||||
out_color = materials[mat_id].color_factors;
|
||||
}
|
||||
|
||||
float metallic_scalar = 0.0;
|
||||
float roughness_scalar = 0.0;
|
||||
|
||||
uint metallic_id = materials[mat_id].metallic_texture_id;
|
||||
if (metallic_id != INVALID_TEXTURE_ID)// If the metallic texture is assigned, Then we should use it. Otherwise we want to use the metallic factor
|
||||
{
|
||||
vec4 tex_sample = texture(tex[metallic_id], in_uv).rgba;
|
||||
// r channel is for occlusion data (optional)
|
||||
// g channel is for roughnes factor
|
||||
// b channel is for metallic factor
|
||||
metallic_scalar = tex_sample.b * materials[mat_id].metallic_factor;
|
||||
roughness_scalar = tex_sample.g * materials[mat_id].roughness_factor;
|
||||
}
|
||||
else // Texture was not present, So we instead use the factor values as our values
|
||||
{
|
||||
metallic_scalar = clamp(materials[mat_id].metallic_factor, MIN_ROUGHNESS, 1.0);
|
||||
roughness_scalar = clamp(materials[mat_id].roughness_factor, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// The example does some magic here that I don't understand?
|
||||
// https://github.com/SaschaWillems/Vulkan-glTF-PBR/blob/master/data/shaders/material_pbr.frag#L242
|
||||
float occlusion_scalar = 0.0;
|
||||
|
||||
out_metallic = vec3(metallic_scalar, roughness_scalar, occlusion_scalar);
|
||||
|
||||
|
||||
const uint normal_texture_id = materials[mat_id].normal_texture_id;
|
||||
if (normal_texture_id != INVALID_TEXTURE_ID)
|
||||
{
|
||||
vec3 tex_sample = texture(tex[normal_texture_id], in_uv).xyz;
|
||||
|
||||
out_normal = vec4(tex_sample * vec3(materials[mat_id].normal_scale), 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
out_normal = vec4(in_normal, 1.0);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#version 450
|
||||
#extension GL_EXT_debug_printf: enable
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
#include "include/vertex.glsl"
|
||||
|
||||
layout (location = 0) out vec3 out_normal;
|
||||
layout (location = 1) out vec2 out_tex_coord;
|
||||
layout (location = 2) out vec3 out_world_pos;
|
||||
layout (location = 3) out flat uint out_material_id;
|
||||
|
||||
#include "include/camera.glsl"
|
||||
|
||||
void main() {
|
||||
vec4 position_world = instance_model_matrix * vec4(position, 1.0);
|
||||
|
||||
gl_Position = ubo.projection * ubo.view * position_world;
|
||||
out_world_pos = vec3(position_world);
|
||||
|
||||
mat3 normal_matrix = transpose(inverse(mat3(instance_model_matrix)));
|
||||
|
||||
out_normal = normalize(normal_matrix * normal);
|
||||
|
||||
out_tex_coord = uv;
|
||||
|
||||
out_material_id = in_material_id;
|
||||
}
|
||||
106
src/shaders/textured.slang
Normal file
106
src/shaders/textured.slang
Normal file
@@ -0,0 +1,106 @@
|
||||
#version 450
|
||||
|
||||
import model.vertex;
|
||||
import camera;
|
||||
import gbuffer;
|
||||
import material;
|
||||
|
||||
struct Vertex {
|
||||
vec3 normal;
|
||||
vec2 tex_coord;
|
||||
vec3 world_pos;
|
||||
uint material_id;
|
||||
}
|
||||
|
||||
[ [ vk::binding( 0, 1 ) ] ]
|
||||
ParameterBlock< CameraData > camera : CAMERA;
|
||||
|
||||
[shader("vertex")]
|
||||
Vertex vertexMain( ModelVertex in_vertex )
|
||||
{
|
||||
Vertex out_vertex;
|
||||
|
||||
vec4 world_pos = in_vertex.model_matrix * vec4(in_vertex.simple.position, 1.0);
|
||||
|
||||
out_vertex.world_pos = (camera.projection * camera.view * world_pos).xyz;
|
||||
|
||||
mat3 normal_matrix = transpose( inverse( mat3( in_vertex.model_matrix ) ) );
|
||||
|
||||
out_vertex.normal = normalize( normal_matrix * in_vertex.simple.normal );
|
||||
out_vertex.tex_coord = in_vertex.simple.uv;
|
||||
out_vertex.material_id = in_vertex.material_id;
|
||||
|
||||
return out_vertex;
|
||||
}
|
||||
|
||||
[[vk::binding(0,3)]]
|
||||
ParameterBlock<Material> materials[] : MATERIALS;
|
||||
|
||||
[[vk::binding(0,2)]]
|
||||
Sampler2D[ ] tex : TEXTURES;
|
||||
|
||||
static const float MIN_ROUGHNESS = 0.04;
|
||||
|
||||
[shader("fragment")]
|
||||
GBufferFragment fragmentMain( Vertex vertex : Vertex )
|
||||
{
|
||||
GBufferFragment frag;
|
||||
frag.position = vertex.world_pos;
|
||||
|
||||
vec3 diffuse_color;
|
||||
vec4 base_color;
|
||||
|
||||
vec3 f0 = vec3( 0.04 );
|
||||
|
||||
if ( vertex.material_id == INVALID_TEXTURE_ID )
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
Material material = materials[vertex.material_id];
|
||||
|
||||
if ( material.color.isTexture() )
|
||||
{
|
||||
vec4 color = texture( tex[ material.color.texture_id ], vertex.tex_coord );
|
||||
vec4 factors = material.color.factors;
|
||||
frag.color = color * factors;
|
||||
}
|
||||
else
|
||||
{
|
||||
frag.color = material.color.factors;
|
||||
}
|
||||
|
||||
float metallic_scalar = 0.0;
|
||||
float roughness_scalar = 0.0;
|
||||
|
||||
var metallic = material.metallic;
|
||||
if ( metallic.isTexture() )
|
||||
{
|
||||
vec4 sample = texture( tex[ metallic.texture_id ], vertex.tex_coord );
|
||||
|
||||
metallic_scalar = sample.b * metallic.metallic_factor;
|
||||
roughness_scalar = sample.g * metallic.roughness_factor;
|
||||
}
|
||||
else
|
||||
{
|
||||
metallic_scalar = clamp( metallic.roughness_factor, MIN_ROUGHNESS, 1.0 );
|
||||
roughness_scalar = clamp( metallic.roughness_factor, 0.0, 1.0 );
|
||||
}
|
||||
|
||||
float occlusion_scalar = 0.0;
|
||||
|
||||
frag.metallic = vec3( metallic_scalar, roughness_scalar, occlusion_scalar );
|
||||
|
||||
var normal = material.normal;
|
||||
if ( normal.isTexture() )
|
||||
{
|
||||
vec3 sample = texture( tex[ normal.texture_id ], vertex.tex_coord ).rgb;
|
||||
frag.normal = vec4( sample * vec3( normal.scale ), 1.0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
frag.normal = vec4( vertex.normal, 1.0 );
|
||||
}
|
||||
|
||||
return frag;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#version 450
|
||||
#extension GL_EXT_nonuniform_qualifier: enable
|
||||
#extension GL_EXT_debug_printf: enable
|
||||
|
||||
layout (location = 0) in vec3 in_normal;
|
||||
layout (location = 1) in vec2 in_tex_coord;
|
||||
layout (location = 2) in vec3 in_world_pos;
|
||||
layout (location = 3) in vec3 in_color;
|
||||
|
||||
layout (location = 0) out vec4 out_position;
|
||||
layout (location = 1) out vec4 out_normal;
|
||||
layout (location = 2) out vec4 out_albedo;
|
||||
|
||||
layout (set = 1, binding = 0) uniform CameraInfo {
|
||||
mat4 projection;
|
||||
mat4 view;
|
||||
mat4 inverse_view;
|
||||
} ubo;
|
||||
|
||||
float linearDepth(float depth)
|
||||
{
|
||||
float z = depth * 2.0f - 1.0f;
|
||||
return (2.0f * NEAR_PLANE * FAR_PLANE) / (FAR_PLANE + NEAR_PLANE - z * (FAR_PLANE - NEAR_PLANE));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
out_position = vec4(in_world_pos, 1.0f);
|
||||
|
||||
vec3 N = normalize(in_normal);
|
||||
|
||||
out_normal = vec4(N, 1.0);
|
||||
|
||||
out_position.a = linearDepth(out_position.z);
|
||||
|
||||
out_albedo = vec4(in_color, 1.0);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#version 450
|
||||
#extension GL_EXT_debug_printf: enable
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
#include "include/vertex.glsl"
|
||||
|
||||
layout (location = 0) out vec3 out_normal;
|
||||
layout (location = 1) out vec2 out_tex_coord;
|
||||
layout (location = 2) out vec3 out_world_pos;
|
||||
layout (location = 3) out vec3 out_color;
|
||||
|
||||
layout (set = 1, binding = 0) uniform CameraInfo {
|
||||
mat4 projection;
|
||||
mat4 view;
|
||||
mat4 inverse_view;
|
||||
} ubo;
|
||||
|
||||
void main() {
|
||||
vec4 position_world = instance_model_matrix * vec4(position, 1.0);
|
||||
|
||||
gl_Position = ubo.projection * ubo.view * position_world;
|
||||
out_world_pos = vec3(gl_Position);
|
||||
|
||||
mat3 normal_matrix = transpose(inverse(mat3(instance_model_matrix)));
|
||||
|
||||
out_normal = normalize(normal_matrix * normal);
|
||||
|
||||
out_tex_coord = uv;
|
||||
|
||||
out_color = color;
|
||||
}
|
||||
Reference in New Issue
Block a user