From e577c14039dc8e6a6128d45ab6c017ac5480f80e Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Tue, 22 Sep 2026 14:53:28 +0000 Subject: [PATCH 01/83] Add CLI argument to specify additional include directories for the shader compiler --- shadercompiler/CachingIncludeHandler.cpp | 63 ++++++++++++++++++------ shadercompiler/CachingIncludeHandler.h | 11 ++++- shadercompiler/HLSLScanner.re | 19 +++---- shadercompiler/ModifiedTime.cpp | 2 +- shadercompiler/ParserState.cpp | 4 +- shadercompiler/ParserState.h | 3 +- shadercompiler/ShaderCompiler.cpp | 17 ++++++- 7 files changed, 87 insertions(+), 32 deletions(-) diff --git a/shadercompiler/CachingIncludeHandler.cpp b/shadercompiler/CachingIncludeHandler.cpp index 7f2150290..00f89401e 100644 --- a/shadercompiler/CachingIncludeHandler.cpp +++ b/shadercompiler/CachingIncludeHandler.cpp @@ -85,37 +85,62 @@ CachingIncludeHandler::~CachingIncludeHandler() // used for resolving relative paths // rootPath - Custom root path for resolving relative paths // -------------------------------------------------------------------------------------- -std::optional CachingIncludeHandler::Open( const char* fileName, const char* parentData, const char* rootPath ) +std::optional CachingIncludeHandler::Open( const char* fileName, IncludeType includeType, const char* parentData, const char* rootPath ) { std::lock_guard scope( m_cs ); std::string fullPath; if( PathIsRelative( fileName ) ) { - std::string parentPath; - if( parentData == nullptr ) - { - parentPath = rootPath ? rootPath : m_rootPath; - } - else - { - auto parent = m_pathFromFile.find( parentData - 1 ); - if( parent != m_pathFromFile.end() ) + auto FindLocalPath = [&]() -> bool { + std::string parentPath; + if( parentData == nullptr ) { - parentPath = parent->second; + parentPath = rootPath ? rootPath : m_rootPath; } else { - parentPath = ""; + auto parent = m_pathFromFile.find( parentData - 1 ); + if( parent != m_pathFromFile.end() ) + { + parentPath = parent->second; + } + else + { + parentPath = ""; + } } - } - if( auto joined = JoinPath( parentPath.c_str(), fileName ) ) + if( auto joined = JoinPath( parentPath.c_str(), fileName ) ) + { + fullPath = *joined; + return true; + } + return false; + }; + auto FindSystemPath = [&]() -> bool { + for( auto it = m_systemIncludePaths.begin(); it != m_systemIncludePaths.end(); ++it ) + { + if( auto joined = JoinPath( it->c_str(), fileName ) ) + { + fullPath = *joined; + return true; + } + } + return false; + }; + if( includeType == IncludeLocal ) { - fullPath = *joined; + if( !FindLocalPath() && !FindSystemPath() ) + { + return std::nullopt; + } } else { - return std::nullopt; + if( !FindSystemPath() && !FindLocalPath() ) + { + return std::nullopt; + } } } else @@ -221,6 +246,12 @@ std::optional CachingIncludeHandler::AddPre return info; } +void CachingIncludeHandler::AddSystemIncludePath( const char* path ) +{ + std::lock_guard scope( m_cs ); + m_systemIncludePaths.push_back( path ); +} + // -------------------------------------------------------------------------------------- // Description: // Assigns path to the "root", entry point file. diff --git a/shadercompiler/CachingIncludeHandler.h b/shadercompiler/CachingIncludeHandler.h index 48672b78d..91333c648 100644 --- a/shadercompiler/CachingIncludeHandler.h +++ b/shadercompiler/CachingIncludeHandler.h @@ -22,12 +22,20 @@ class CachingIncludeHandler time_t modifiedTime; }; - std::optional Open( const char* fileName, const char* parentData = nullptr, const char* rootPath = nullptr ); + enum IncludeType + { + IncludeLocal, + IncludeSystem + }; + + std::optional Open( const char* fileName, IncludeType includeType, const char* parentData = nullptr, const char* rootPath = nullptr ); void SetRootPath( const char* shaderPath ); std::optional AddPrefix( const char* fileName, const char* prefix ); + void AddSystemIncludePath( const char* path ); + private: typedef std::map PathFromFile; typedef std::map FileFromPath; @@ -38,6 +46,7 @@ class CachingIncludeHandler FileFromPath m_fileFromPath; // Path of the entry point file std::string m_rootPath; + std::vector m_systemIncludePaths; std::mutex m_cs; }; diff --git a/shadercompiler/HLSLScanner.re b/shadercompiler/HLSLScanner.re index ee976dec2..259505133 100644 --- a/shadercompiler/HLSLScanner.re +++ b/shadercompiler/HLSLScanner.re @@ -41,16 +41,16 @@ ID = LETTER(LETTER|DECIMAL)*; #define YYMARKER (marker) #define YYCTXMARKER (ctxMarker) -bool GetIncludePath( ParserState &state, InlineString& path ) +bool GetIncludePath( ParserState &state, InlineString& path, CachingIncludeHandler::IncludeType& includeType ) { - bool local; + includeType = CachingIncludeHandler::IncludeLocal; if( *YYCURSOR == '"' ) { - local = true; + includeType = CachingIncludeHandler::IncludeLocal; } else if( *YYCURSOR == '<' ) { - local = false; + includeType = CachingIncludeHandler::IncludeSystem; } else { @@ -61,7 +61,7 @@ bool GetIncludePath( ParserState &state, InlineString& path ) { if( *YYCURSOR == '"' ) { - if( local ) + if( includeType == CachingIncludeHandler::IncludeLocal ) { path.end = ++YYCURSOR; return true; @@ -69,7 +69,7 @@ bool GetIncludePath( ParserState &state, InlineString& path ) } else if( *YYCURSOR == '>' ) { - if( !local ) + if( includeType == CachingIncludeHandler::IncludeSystem ) { path.end = ++YYCURSOR; return true; @@ -141,14 +141,15 @@ std: { state.GetCurrentLocation().lineNumber++; InlineString path; - if( !GetIncludePath( state, path ) ) + CachingIncludeHandler::IncludeType includeType; + if( !GetIncludePath( state, path, includeType ) ) { state.ShowMessage( EC_INVALID_INCLUDE_PATH ); return PPSR_ERROR; } if( !state.InSkipMode() ) { - state.IncludeFile( path ); + state.IncludeFile( path, includeType ); } start = YYCURSOR; continue; @@ -566,7 +567,7 @@ std: ++YYCURSOR; } - if( !state.InSkipMode() ) + if( !state.InSkipMode() && !state.InDiscoverMode() ) { state.ShowMessage( EC_USER_ERROR, std::string( start, YYCURSOR ).c_str() ); return PPSR_ERROR; diff --git a/shadercompiler/ModifiedTime.cpp b/shadercompiler/ModifiedTime.cpp index bd11d80ad..b741bdd24 100644 --- a/shadercompiler/ModifiedTime.cpp +++ b/shadercompiler/ModifiedTime.cpp @@ -119,7 +119,7 @@ void GetSourceHash( const char* sourcePath, const char* parentData, const char* return; } visited.insert( sourcePath ); - if( auto opened = s_includeHandler.Open( sourcePath, parentData, rootPath ) ) + if( auto opened = s_includeHandler.Open( sourcePath, CachingIncludeHandler::IncludeLocal, parentData, rootPath ) ) { md5.add( opened->data, opened->size ); diff --git a/shadercompiler/ParserState.cpp b/shadercompiler/ParserState.cpp index 6883c82b1..3e604aec0 100644 --- a/shadercompiler/ParserState.cpp +++ b/shadercompiler/ParserState.cpp @@ -988,12 +988,12 @@ bool ParserState::InMacro() const return m_fileStack.back().isMacro; } -void ParserState::IncludeFile( const InlineString& fileName ) +void ParserState::IncludeFile( const InlineString& fileName, CachingIncludeHandler::IncludeType includeType ) { extern CachingIncludeHandler g_includeHandler; std::string path( fileName.start + 1, fileName.end - 1 ); - if( auto file = g_includeHandler.Open( path.c_str(), m_fileStack.back().code.start + 1 ) ) + if( auto file = g_includeHandler.Open( path.c_str(), includeType, m_fileStack.back().code.start + 1 ) ) { FileContents fileContents; diff --git a/shadercompiler/ParserState.h b/shadercompiler/ParserState.h index 1bafdde7f..73cdc73d7 100644 --- a/shadercompiler/ParserState.h +++ b/shadercompiler/ParserState.h @@ -3,6 +3,7 @@ #pragma once #include "InlineString.h" +#include "CachingIncludeHandler.h" class SymbolTable; class ASTNode; @@ -234,7 +235,7 @@ class ParserState bool InDiscoverMode() const; PreprocessorScanResult GetPreprocessorToken( PreprocessorToken& token ); - void IncludeFile( const InlineString& fileName ); + void IncludeFile( const InlineString& fileName, CachingIncludeHandler::IncludeType includeType ); void ParseDefine( const PreprocessorDefine& define, const FileLocation& location, const std::vector& arguments ); PreprocessorDefine* FindDefine( const InlineString& name ); diff --git a/shadercompiler/ShaderCompiler.cpp b/shadercompiler/ShaderCompiler.cpp index 294755c73..00d410db8 100644 --- a/shadercompiler/ShaderCompiler.cpp +++ b/shadercompiler/ShaderCompiler.cpp @@ -208,6 +208,7 @@ void PrintUsage() printf( " /E{e,w,d}[extension] - Specify support for all or certain GLES extensions\n" ); printf( " /novalidate - Skip validating converted GLSL code\n" ); printf( " /permutations - Print permutations of the shader\n" ); + printf( " /I - Specify additional include directory\n" ); #if CCP_TELEMETRY_ENABLED printf( " /telemetry - Enable RAD Telemetry\n" ); #endif @@ -302,6 +303,18 @@ bool ExtractCommandLineArguments( ProgramArguments& args, int argc, char* argv[] { args.ignorePermutations = true; } + else if( strcmp( argv[i], "/I" ) == 0 ) + { + ++i; + if( i < argc ) + { + g_includeHandler.AddSystemIncludePath( argv[i] ); + } + else + { + return false; + } + } else if( strcmp( argv[i], "/define" ) == 0 ) { Macro define; @@ -411,7 +424,7 @@ bool ExtractCommandLineArguments( ProgramArguments& args, int argc, char* argv[] bool PrintPermutations( const char* shaderPath ) { - auto shader = g_includeHandler.Open( shaderPath ); + auto shader = g_includeHandler.Open( shaderPath, CachingIncludeHandler::IncludeLocal ); if( !shader ) { @@ -624,7 +637,7 @@ int main( int argc, char* argv[] ) } // Preload shader file - auto shader = g_includeHandler.Open( args.shaderPath ); + auto shader = g_includeHandler.Open( args.shaderPath, CachingIncludeHandler::IncludeLocal ); if( !shader ) { printf( "%s: error X0000: Could not open input file \"%s\"\n", args.shaderPath, args.shaderPath ); From 6d8ff083a8e66918b1c46366cd01b595a2dd7a95 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Tue, 22 Sep 2026 15:00:05 +0000 Subject: [PATCH 02/83] Add some shader includes --- CMakeLists.txt | 2 + shaders/include/carbon/bindless.fxh | 97 +++++++++++++++++++ shaders/include/carbon/packedtangents.fxh | 81 ++++++++++++++++ .../include/carbon/particleannotations.fxh | 37 +++++++ shaders/include/carbon/system.fxh | 81 ++++++++++++++++ 5 files changed, 298 insertions(+) create mode 100644 shaders/include/carbon/bindless.fxh create mode 100644 shaders/include/carbon/packedtangents.fxh create mode 100644 shaders/include/carbon/particleannotations.fxh create mode 100644 shaders/include/carbon/system.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index fa0d1fc0b..db001aa5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,3 +130,5 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) ) endif() endif() + +install(DIRECTORY shaders/ DESTINATION shaders) diff --git a/shaders/include/carbon/bindless.fxh b/shaders/include/carbon/bindless.fxh new file mode 100644 index 000000000..7f4b20c41 --- /dev/null +++ b/shaders/include/carbon/bindless.fxh @@ -0,0 +1,97 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_BINDLESS_FXH +#define CARBON_BINDLESS_FXH + +#include "system.fxh" + +// Support for bindless rendering with Trinity. Difines types and functions to work with +// bindless resources and heap views in a platform-independent manner. + +// BINDLESS_RENDERING define controls whether bindless rendering is enabled. + +// Don't even try to use bindless rendering on platforms that don't support it (DirectX 11) +#if !PLATFORM_SUPPORTS_SUPPORTS_HEAP_VIEW +#define BINDLESS_RENDERING 0 +#endif + +#ifndef BINDLESS_RENDERING +#define BINDLESS_RENDERING 1 +#endif + +#if BINDLESS_RENDERING + +Texture2D HeapView_Texture2D[] +< + bool IsHeapView = true; +>; + +Texture3D HeapView_Texture3D[] +< + bool IsHeapView = true; +>; + +TextureCube HeapView_TextureCube[] +< + bool IsHeapView = true; +>; + +SamplerState HeapView_Sampler[] +< + bool IsHeapView = true; +>; + +#endif + +// Convenient shortcut to declaring bindless/class texture variables +#if BINDLESS_RENDERING +// CCP Shader compiler defines custom types BindlessHandleTexture... that map to uint on DX12 and Metal +#define BindlessTexture2D BindlessHandleTexture2D +#define BindlessTexture3D BindlessHandleTexture3D +#define BindlessTextureCube BindlessHandleTextureCube +#define BindlessSampler BindlessHandleSampler +#else +#define BindlessTexture2D Texture2D +#define BindlessTexture3D Texture3D +#define BindlessTextureCube TextureCube +#define BindlessSampler SamplerState +#endif + +Texture2D Deref2D( BindlessTexture2D tex ) +{ +#if BINDLESS_RENDERING + return HeapView_Texture2D[tex]; +#else + return tex; +#endif +} + +Texture3D Deref3D( BindlessTexture3D tex ) +{ +#if BINDLESS_RENDERING + return HeapView_Texture3D[tex]; +#else + return tex; +#endif +} + +TextureCube DerefCube( BindlessTextureCube tex ) +{ +#if BINDLESS_RENDERING + return HeapView_TextureCube[tex]; +#else + return tex; +#endif +} + +SamplerState DerefSampler( BindlessSampler sampl ) +{ +#if BINDLESS_RENDERING + return HeapView_Sampler[sampl]; +#else + return sampl; +#endif +} + + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/packedtangents.fxh b/shaders/include/carbon/packedtangents.fxh new file mode 100644 index 000000000..745b88ee8 --- /dev/null +++ b/shaders/include/carbon/packedtangents.fxh @@ -0,0 +1,81 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_PACKEDTANGENTS_FXH +#define CARBON_PACKEDTANGENTS_FXH + + +struct TangentSpace +{ + float3 tangent; + float3 bitangent; + float3 normal; +}; + +// Support for fma insrinsic varies for dx11 +float _Fma( float a, float b, float c ) +{ + return a * b + c; +} + +// Unpacks a tangent space using quaternion representation corresponding to +// cmf::Usage::PackedTangent in carbon-mesh. +TangentSpace UnpackTangentSpace( float4 t ) +{ + // Heavily optimized shader code that constructs the TBN matrix. + + // Extract the xyz components and square them + float x = t.x; + float y = t.y; + float z = t.z; + float x2 = x * x; + float y2 = y * y; + float z2 = z * z; + + // Optimized fma() chain to reconstruct W = sqrt(1 - x2 - y2 - z2) + // Don't use the above x2, y2 and z2 values, to reduce pipeline dependencies. + float w2 = saturate( _Fma( z, -z, _Fma( y, -y, _Fma( x, -x, 1.0f ) ) ) ); + float w = sqrt( w2 ); + + // Calculate shared values. + // These multiplications by 2.0f are free on some GPUs. + float xy = x * y * 2.0f; + float xz = x * z * 2.0f; + float yz = y * z * 2.0f; + float xw = x * w * 2.0f; + float yw = y * w * 2.0f; + float zw = z * w * 2.0f; + + // Compute the three vectors. + TangentSpace space; + + space.tangent = float3( _Fma( -2.0f, y2, _Fma( -2.0f, z2, 1.0f ) ), + xy + zw, + xz - yw ); + space.bitangent = float3( - zw + xy, _Fma( -2.0f, x2, _Fma( -2.0f, z2, 1.0f ) ), + yz + xw ); + space.normal = float3( + yw + xz, + yz - xw, _Fma( -2.0f, x2, _Fma( -2.0f, y2, 1.0f ) ) ) * t.w; // packed normal sign multiplication + + return space; +} + + +// Unpacks a tangent space using angle representation corresponding to +// cmf::Usage::PackedTangentLegacy in carbon-mesh. +TangentSpace UnpackTangentSpaceLegacy( float4 tangents ) +{ + float pi = 3.1415926535897932384626433832795; + + float4 angles = tangents * 2.0 * pi - pi; + float4 sc0, sc1; + sincos( angles.x, sc0.x, sc0.y ); + sincos( angles.y, sc0.z, sc0.w ); + sincos( angles.z, sc1.x, sc1.y ); + sincos( angles.w, sc1.z, sc1.w ); + TangentSpace space; + space.tangent = float3( sc0.y * abs( sc0.z ), sc0.x * abs( sc0.z ), sc0.w ); + space.bitangent = float3( sc1.y * abs( sc1.z ), sc1.x * abs( sc1.z ), sc1.w ); + space.normal = -cross( space.tangent, space.bitangent ); + space.normal = all( angles.yw > 0.0 ) ? -space.normal : space.normal; + return space; +} + + + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/particleannotations.fxh b/shaders/include/carbon/particleannotations.fxh new file mode 100644 index 000000000..679ec6242 --- /dev/null +++ b/shaders/include/carbon/particleannotations.fxh @@ -0,0 +1,37 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_PARTICLEANNOTATIONS_FXH +#define CARBON_PARTICLEANNOTATIONS_FXH + +// This file contains definitions for particle system shader annotations. +// These annotations are used to provide metadata and hints to the editor. +// These annotations should be specified for the particle system vertex shader, and +// they describe the particle attributes used by the shader. +// For example: +// ParticleVtx ParticleVS( ParticleAppVtx inVtx ) +// < +// DESC_PARTICLE_POSITION; +// DESC_PARTICLE_LIFETIME; +// DESC_PARTICLE_CUSTOM( 0, "size", 2 ); +// > +// { +// ... +// } + +#define DESC_PARTICLE_CONCAT( x, y ) x##y + +#define DESC_PARTICLE_ELEMENT( usage, index, name, dimension ) \ + string DESC_PARTICLE_CONCAT( ParticleElement_Name_, __LINE__ ) = name; \ + int DESC_PARTICLE_CONCAT( ParticleElement_Dimension_, __LINE__ ) = dimension; \ + int DESC_PARTICLE_CONCAT( ParticleElement_Usage_, __LINE__ ) = usage; \ + int DESC_PARTICLE_CONCAT( ParticleElement_Index_, __LINE__ ) = index + +#define DESC_PARTICLE_POSITION DESC_PARTICLE_ELEMENT( 1, 0, "POSITION", 3 ) +#define DESC_PARTICLE_VELOCITY DESC_PARTICLE_ELEMENT( 2, 0, "VELOCITY", 3 ) +#define DESC_PARTICLE_LIFETIME DESC_PARTICLE_ELEMENT( 0, 0, "LIFETIME", 2 ) +#define DESC_PARTICLE_MASS DESC_PARTICLE_ELEMENT( 3, 0, "MASS", 1 ) + +#define DESC_PARTICLE_CUSTOM( index, name, dimension ) DESC_PARTICLE_ELEMENT( 4, index, name, dimension ) + + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/system.fxh b/shaders/include/carbon/system.fxh new file mode 100644 index 000000000..75b1f4eda --- /dev/null +++ b/shaders/include/carbon/system.fxh @@ -0,0 +1,81 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_SYSTEM_FXH +#define CARBON_SYSTEM_FXH + +// This file contains definitions for backend API, including capability flags, and shader quality setting defines. + +// Trinity graphics API backend +#define PLATFORM_DX11 2 +#define PLATFORM_DX12 6 +#define PLATFORM_METAL 10 + +#ifndef PLATFORM +#error Missing value for PLATFORM macro +#endif + +// API supports compute shaders +#define PLATFORM_SUPPORTS_COMPUTE 1 + +// API supports geometry shaders +#if PLATFORM==PLATFORM_DX11 || PLATFORM==PLATFORM_DX12 +#define PLATFORM_SUPPORTS_GEOMETRY_SHADERS 1 +#else +#define PLATFORM_SUPPORTS_GEOMETRY_SHADERS 0 +#endif + +// API supports reading MSAA textures +#define PLATFORM_SUPPORTS_MSAA_READS 1 +// API supports GetDimensions method for textures +#define PLATFORM_SUPPORTS_TEXTURE_SIZE_QUERIES 1 +// API supports .Load methods for textures +#define PLATFORM_SUPPORTS_TEXTURE_LOAD 1 + +// API supports SRV/UAV/Sampler heap views +#if PLATFORM==PLATFORM_METAL || PLATFORM==PLATFORM_DX12 +#define PLATFORM_SUPPORTS_SUPPORTS_HEAP_VIEW 1 +#else +#define PLATFORM_SUPPORTS_SUPPORTS_HEAP_VIEW 0 +#endif + +// Maximum size of constant buffer in bytes +#if PLATFORM==PLATFORM_DX11 || PLATFORM==PLATFORM_DX12 +#define PLATFORM_MAX_CONSTANT_BUFFER_SIZE 65536 +#else +#define PLATFORM_MAX_CONSTANT_BUFFER_SIZE 4096 +#endif + +// API supports ray tracing +#if PLATFORM==PLATFORM_DX12 || PLATFORM==PLATFORM_METAL +#define PLATFORM_SUPPORTS_RAY_TRACING 1 +#else +#define PLATFORM_SUPPORTS_RAY_TRACING 0 +#endif + +// Support for "precise" keyword is for DirectX only +#if PLATFORM==PLATFORM_DX11 || PLATFORM==PLATFORM_DX12 +#define DX11_PRECISE precise +#else +#define DX11_PRECISE +#endif + + +// Shader quality setting. Comes from project user settings via Trinity +#define SHADER_QUALITY_LOW 3 +#define SHADER_QUALITY_MEDIUM 4 +#define SHADER_QUALITY_HIGH 5 + +// Legacy quality defines +#define SM_3_0_LO SHADER_QUALITY_LOW +#define SM_3_0_HI SHADER_QUALITY_MEDIUM +#define SM_3_0_DEPTH SHADER_QUALITY_HIGH + +#ifndef SHADERMODEL +#define SHADERMODEL SHADER_QUALITY_HIGH +#endif + +#ifndef SHADER_QUALITY +#define SHADER_QUALITY SHADERMODEL +#endif + +#endif \ No newline at end of file From 8e818845cca27951a712245152b72beba850ba1f Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Wed, 23 Sep 2026 11:51:01 +0000 Subject: [PATCH 03/83] Capitalize filenames --- shaders/include/carbon/{bindless.fxh => Bindless.fxh} | 0 shaders/include/carbon/{packedtangents.fxh => PackedTangents.fxh} | 0 .../carbon/{particleannotations.fxh => ParticleAnnotations.fxh} | 0 shaders/include/carbon/{system.fxh => System.fxh} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename shaders/include/carbon/{bindless.fxh => Bindless.fxh} (100%) rename shaders/include/carbon/{packedtangents.fxh => PackedTangents.fxh} (100%) rename shaders/include/carbon/{particleannotations.fxh => ParticleAnnotations.fxh} (100%) rename shaders/include/carbon/{system.fxh => System.fxh} (100%) diff --git a/shaders/include/carbon/bindless.fxh b/shaders/include/carbon/Bindless.fxh similarity index 100% rename from shaders/include/carbon/bindless.fxh rename to shaders/include/carbon/Bindless.fxh diff --git a/shaders/include/carbon/packedtangents.fxh b/shaders/include/carbon/PackedTangents.fxh similarity index 100% rename from shaders/include/carbon/packedtangents.fxh rename to shaders/include/carbon/PackedTangents.fxh diff --git a/shaders/include/carbon/particleannotations.fxh b/shaders/include/carbon/ParticleAnnotations.fxh similarity index 100% rename from shaders/include/carbon/particleannotations.fxh rename to shaders/include/carbon/ParticleAnnotations.fxh diff --git a/shaders/include/carbon/system.fxh b/shaders/include/carbon/System.fxh similarity index 100% rename from shaders/include/carbon/system.fxh rename to shaders/include/carbon/System.fxh From 90651295c5e473f4b2631e3af44ab9f3226c8576 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 24 Sep 2026 10:23:43 +0000 Subject: [PATCH 04/83] Populating shaders; dummy cmake project for shaders --- CMakeLists.txt | 18 + shaders/include/carbon/Bindless.fxh | 2 +- shaders/include/carbon/Intersections.fxh | 421 ++++++++++++++++++ shaders/include/carbon/Math.fxh | 331 ++++++++++++++ .../carbon/SpaceScene/EnvironmentMap.fxh | 73 +++ .../carbon/SpaceScene/PerSceneData.fxh | 86 ++++ .../include/carbon/SpaceScene/Volumetrics.fxh | 223 ++++++++++ shaders/include/carbon/System.fxh | 10 + 8 files changed, 1163 insertions(+), 1 deletion(-) create mode 100644 shaders/include/carbon/Intersections.fxh create mode 100644 shaders/include/carbon/Math.fxh create mode 100644 shaders/include/carbon/SpaceScene/EnvironmentMap.fxh create mode 100644 shaders/include/carbon/SpaceScene/PerSceneData.fxh create mode 100644 shaders/include/carbon/SpaceScene/Volumetrics.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index db001aa5d..ed4e33e1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,4 +131,22 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() endif() +set(_SHADER_SOURCES + shaders/include/carbon/SpaceScene/EnvironmentMap.fxh + shaders/include/carbon/SpaceScene/PerSceneData.fxh + shaders/include/carbon/SpaceScene/Volumetrics.fxh + shaders/include/carbon/Bindless.fxh + shaders/include/carbon/Intersections.fxh + shaders/include/carbon/Math.fxh + shaders/include/carbon/PackedTangents.fxh + shaders/include/carbon/ParticleAnnotations.fxh + shaders/include/carbon/System.fxh + ) + +add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) +source_group( + TREE "${CMAKE_CURRENT_SOURCE_DIR}/shaders" + FILES ${_SHADER_SOURCES} +) + install(DIRECTORY shaders/ DESTINATION shaders) diff --git a/shaders/include/carbon/Bindless.fxh b/shaders/include/carbon/Bindless.fxh index 7f4b20c41..04be0b958 100644 --- a/shaders/include/carbon/Bindless.fxh +++ b/shaders/include/carbon/Bindless.fxh @@ -3,7 +3,7 @@ #ifndef CARBON_BINDLESS_FXH #define CARBON_BINDLESS_FXH -#include "system.fxh" +#include "System.fxh" // Support for bindless rendering with Trinity. Difines types and functions to work with // bindless resources and heap views in a platform-independent manner. diff --git a/shaders/include/carbon/Intersections.fxh b/shaders/include/carbon/Intersections.fxh new file mode 100644 index 000000000..8b7c049dd --- /dev/null +++ b/shaders/include/carbon/Intersections.fxh @@ -0,0 +1,421 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_INTERSECTIONS_FXH +#define CARBON_INTERSECTIONS_FXH + + + +struct Ray +{ + float3 origin; + float3 dir; +}; + +Ray InitRay(float3 o, float3 d) +{ + Ray r; + r.origin = o; + r.dir = d; + return r; +} + + +struct Plane +{ + float3 normal; + float3 planePoint; +}; + +Plane InitPlane(float3 normal, float3 planePoint) +{ + Plane p; + p.normal = normal; + p.planePoint = planePoint; + return p; +} + +float GetDistanceToPlane( Plane plane, Ray ray ) +{ + float denom = dot( ray.dir, plane.normal ); + float denom2 = dot( ray.dir, -plane.normal ); + float d = max( denom, denom2 ); + if( d == denom2 ) + { + plane.normal = -plane.normal; + } + + const float FLT_EPSILON = 0.0000001; + if( d >= FLT_EPSILON ) + { + float3 rayToPlanePoint = plane.planePoint - ray.origin; + + return dot( rayToPlanePoint, plane.normal ) / d; + } + return -1; +} + +bool PointOnPlane( Ray ray, float t, float3 planePoint, float radius ) +{ + if( t < 0 ) + { + return false; + } + float3 pointInPlaneSpace = ray.origin + t * ray.dir; + float3 dist = planePoint - pointInPlaneSpace; + float r = radius; + + return dot( dist, dist ) - r * r <= 0; +} + +float GetDistanceToCircle(float3 normal, float3 planePoint, float radius, Ray ray) +{ + float t = GetDistanceToPlane( InitPlane( normal, planePoint ), ray); + if( PointOnPlane( ray, t, planePoint, radius ) ) + { + return t; + } + return -1; +} + +// ------------------------------------------------------------------------------- +// Sphere +// ------------------------------------------------------------------------------- +struct Sphere +{ + float3 center; + float radius; +}; + +Sphere InitSphere( float3 center, float radius ) +{ + Sphere s; + s.center = center; + s.radius = radius; + return s; +} + +struct SphereHitInfo +{ + bool occurred; + float4 firstIntersection; // xyz - position, w - distance from eye + float4 secondIntersection; // xyz - position, w - distance from eye +}; + +SphereHitInfo SphereRayHitTest( Sphere sphere, Ray ray ) +{ + SphereHitInfo info; + info.occurred = false; + info.firstIntersection = float4(0, 0, 0, 0); + info.secondIntersection = float4(0, 0, 0, 0); + + // algorithm taken from Real Time Rendering fourth edition, page 958 + float3 originToSphereCenter = sphere.center - ray.origin; + float s = dot( originToSphereCenter, ray.dir ); + float originToSphereCenterLengthSq = dot(originToSphereCenter, originToSphereCenter); + float radSq = sphere.radius * sphere.radius; + + if( s < 0 && originToSphereCenterLengthSq > radSq ) + { + return info; + } + + float mSq = originToSphereCenterLengthSq - s*s; + if( mSq > radSq ) + { + return info; + } + + float intersectionPerpendicularToCenter = sqrt( radSq - mSq ); + float minT = max( 0.0, min( s - intersectionPerpendicularToCenter, s + intersectionPerpendicularToCenter ) ); + float maxT = max( s - intersectionPerpendicularToCenter, s + intersectionPerpendicularToCenter ); + + info.firstIntersection = float4( ray.origin + ray.dir * minT - sphere.center, minT ); + info.secondIntersection = float4( ray.origin + ray.dir * maxT - sphere.center, maxT ); + info.occurred = true; + + return info; +} + + +// ------------------------------------------------------------------------------- +// Cones +// ------------------------------------------------------------------------------- +struct Cone +{ + float height; + float3 tip; + float cosa; // half cone angle + // float tipRadius; + float3 axis; + float baseRadius; + float tipOffset; +}; + +struct ConeHitInfo +{ + float4 firstIntersection; // xyz - position, w - distance from eye + float4 secondIntersection; // xyz - position, w - distance from eye + float4 hits; // frontCone, backCone, base, tip + float shadowConeHit; + bool occurred; + float4 tmp; +}; + +bool PointInCone( Ray ray, float t, Cone cone ) +{ + if( t < 0 ) + { + return false; + } + + float3 pointInConeSpace = ray.origin + t * ray.dir - cone.tip; + + float cone_dist = dot( pointInConeSpace, cone.axis ); + const float FLT_EPSILON = 0.0000001; + + if( cone.tipOffset - cone_dist > 0 || cone_dist > cone.height + FLT_EPSILON ) + { + return false; + } + + float cone_radius_at_dist = ( cone_dist / cone.height ) * cone.baseRadius; + float3 orth_point = pointInConeSpace - cone_dist * cone.axis; + float orth_distance_sq = dot(orth_point, orth_point); + return cone.baseRadius * cone.baseRadius - orth_distance_sq >= 0; +} + +bool GetConeIntersectionDistances(Cone cone, Ray ray, out float t1, out float t2, out float baseT, out float tipT ) +{ + t1 = -1; + t2 = -1; + baseT = -1; + tipT = -1; + + baseT = GetDistanceToCircle(cone.axis, cone.tip + cone.axis * cone.height, cone.baseRadius, ray); + + float tipOffsetRadius = cone.tipOffset / cone.cosa; + tipOffsetRadius = sqrt(tipOffsetRadius * tipOffsetRadius - cone.tipOffset * cone.tipOffset); + tipT = GetDistanceToCircle(cone.axis, cone.tip + cone.axis * cone.tipOffset, tipOffsetRadius, ray); + + // code comes from here http://lousodrome.net/blog/light/2017/01/03/intersection-of-a-ray-and-a-cone/ + float3 co = ray.origin - cone.tip; + + float dirAxisDot = dot(ray.dir, cone.axis); + float coAxisDot = dot(co, cone.axis); + + float a = dirAxisDot * dirAxisDot - cone.cosa * cone.cosa; + float b = 2. * (dirAxisDot * coAxisDot - dot(ray.dir, co) * cone.cosa * cone.cosa); + float c = coAxisDot * coAxisDot - dot(co, co) * cone.cosa * cone.cosa; + + float det = b * b - 4. * a * c; + + if( det < 0 ) + { + if( baseT < 0 && tipT < 0 ) + { + return false; + } + return true; + } + + det = sqrt(abs(det)); + + // if t1 is < 0 then we are will never hit the cone i.e the ray will never intersect + t1 = ( -b - det ) / ( 2. * a ); + // if t2 is < 0 then we are looking down the axis of the cone (in either way) + t2 = ( -b + det ) / ( 2. * a ); + + return true; +} + +// Sorts a vector4 in ascending order (x, y, z, w) +float4 sort(float4 values) +{ + float minv, maxv; + + // move the maximum value to w + minv = min(values.x, values.y); + maxv = max(values.x, values.y); + values.x = minv; + values.y = maxv; + + minv = min(values.y, values.z); + maxv = max(values.y, values.z); + values.y = minv; + values.z = maxv; + + minv = min(values.z, values.w); + maxv = max(values.z, values.w); + values.z = minv; + values.w = maxv; + // now w has the highest value + + // now we can sort xyz easily + minv = min(values.x, min(values.y, values.z)); + maxv = max(values.x, max(values.y, values.z)); + float midv = values.x + values.y + values.z - minv - maxv; + values.x = minv; + values.y = midv; + values.z = maxv; + + // now values are sorted + return values; +} + +ConeHitInfo ConeFlatBaseHitTest( Cone cone, Ray ray ) +{ + ConeHitInfo hitInfo; + hitInfo.occurred = false; + hitInfo.firstIntersection = float4(0, 0, 0, 0); + hitInfo.secondIntersection = float4(0, 0, 0, 0); + hitInfo.hits = float4(0, 0, 0, 0); + hitInfo.tmp = float4(0, 0, 0, 0); + hitInfo.shadowConeHit = 0; + + float coneT1, coneT2, baseT, tipT = -1; + if( !GetConeIntersectionDistances(cone, ray, coneT1, coneT2, baseT, tipT) ) + { + return hitInfo; + } + + bool frontConeHit = PointInCone( ray, coneT2, cone ); + bool backConeHit = PointInCone( ray, coneT1, cone ); + bool rayOriginConeHit = PointInCone( ray, 0, cone ); + bool baseConeHit = baseT > -1; + bool tipConeHit = tipT > -1; + + hitInfo.hits = float4(frontConeHit, backConeHit, baseConeHit, tipConeHit); + hitInfo.shadowConeHit = 1; + + if( !any( hitInfo.hits.xyzw ) ) + { + return hitInfo; + } + + // for the "distances" that don't create a hit, put in invalid values + float4 modifiedT = float4(frontConeHit ? coneT2 : -1, + backConeHit ? coneT1 : -1, + tipConeHit ? tipT : -1, + baseConeHit ? baseT : -1); + + float4 sortedModifiedT = sort(modifiedT); + float2 tToUse; + + if( rayOriginConeHit ) + { + tToUse.x = 0; + tToUse.y = sortedModifiedT.w; + } + else + { + tToUse.x = sortedModifiedT.z >= 0 ? sortedModifiedT.z: sortedModifiedT.w; + tToUse.y = sortedModifiedT.w; + } + + hitInfo.occurred = true; + hitInfo.firstIntersection = float4(ray.origin + ray.dir * tToUse.x - cone.tip, tToUse.x); + hitInfo.secondIntersection = float4(ray.origin + ray.dir * tToUse.y - cone.tip, tToUse.y); + + return hitInfo; +} + +ConeHitInfo ConeRoundBaseHitTest( Cone cone, Ray ray ) +{ + ConeHitInfo hitInfo; + hitInfo.occurred = false; + hitInfo.firstIntersection = float4(0, 0, 0, 0); + hitInfo.secondIntersection = float4(0, 0, 0, 0); + hitInfo.hits = float4(0, 0, 0, 0); + hitInfo.shadowConeHit = false; + hitInfo.tmp = false; + + float coneT1, coneT2, tmp, tipT = -1; + // are we intersecting the cone (endless and in both directions...) + if( !GetConeIntersectionDistances(cone, ray, coneT1, coneT2, tmp, tipT ) ) + { + return hitInfo; + } + + hitInfo.shadowConeHit = true; + + // first do the sphereintersection since that is cheaper + Sphere s; + s.radius = cone.height; + s.center = cone.tip; + + SphereHitInfo si = SphereRayHitTest(s, ray); + + // Early exit, if no spherical intersection occurred + // either of the intersection points are not within the cone radius + if( !si.occurred ) + { + return hitInfo; + } + + float firstIntersectionDot = dot(normalize(si.firstIntersection.xyz), cone.axis); + float secondIntersectionDot = dot(normalize(si.secondIntersection.xyz), cone.axis); + + bool firstBaseHit = firstIntersectionDot - cone.cosa >= 0; + bool secondBaseHit = secondIntersectionDot - cone.cosa >= 0; + + float baseT1 = si.firstIntersection.w; + float baseT2 = si.secondIntersection.w; + + // modify the cone so it fits nicely to the sphere + cone.height *= cone.cosa; + bool frontConeHit = PointInCone( ray, coneT1, cone ); + bool backConeHit = PointInCone( ray, coneT2, cone ); + bool rayOriginConeHit = PointInCone( ray, 0, cone ); + + float tipOffsetRadius = cone.tipOffset / cone.cosa; + tipOffsetRadius = sqrt(tipOffsetRadius * tipOffsetRadius - cone.tipOffset - cone.tipOffset); + bool tipConeHit = PointOnPlane( ray, tipT, cone.tip + cone.axis * cone.tipOffset, tipOffsetRadius); + + float4 coneIntersections = float4(frontConeHit, backConeHit, rayOriginConeHit, tipConeHit); + float2 sphereIntersections = float2(firstBaseHit, secondBaseHit); + hitInfo.hits = float4(frontConeHit, backConeHit, (any(coneIntersections) && any(sphereIntersections)) || all(sphereIntersections), tipConeHit ); + + // if we don't hit the cone or have any cone and sphere intersections or don't hit the sphere, we can return + if( !any(hitInfo.hits.xyzw) ) + { + return hitInfo; + } + + float2 tToUse; + // figure out the t-s to use + // we have 6 ts to pick from: + // - front and back cone intersection + // - front and back sphere + // - tip + // - 0 (the camera) + + // there are 2 scenarios though + // if the camera is intersecting with the cone, then we need the next t (or min(coneT1, coneT2, sphereT1, sphereT2)) + // otherwise we need the middle values of (coneT1, coneT2, sphereT1, sphereT2) + float4 ts = sort(float4( + hitInfo.hits.x ? coneT1 : -1, + hitInfo.hits.y ? coneT2 : -1, + (any(coneIntersections) && sphereIntersections.x) || all(sphereIntersections)? baseT1 : -1, + (any(coneIntersections) && sphereIntersections.y) || all(sphereIntersections)? baseT2 : -1 + ) + ); + + if( rayOriginConeHit ) + { + tToUse.x = 0; + tToUse.y = max(tipT, ts.w); + } + else + { + tToUse.x = ts.z >= 0 ? ts.z: ts.w; + tToUse.y = ts.w; + } + + hitInfo.occurred = true; + hitInfo.firstIntersection = float4(ray.origin + ray.dir * tToUse.x - cone.tip, tToUse.x); + hitInfo.secondIntersection = float4(ray.origin + ray.dir * tToUse.y - cone.tip, tToUse.y); + + return hitInfo; +} + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/Math.fxh b/shaders/include/carbon/Math.fxh new file mode 100644 index 000000000..b90ce7cf4 --- /dev/null +++ b/shaders/include/carbon/Math.fxh @@ -0,0 +1,331 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_MATH_FXH +#define CARBON_MATH_FXH + +static float PI = 3.1415926535897932384626433832795; +static float _2PI = 6.283185307179586476925286766559; +static const float4x4 IDENTITY_MATRIX = float4x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + +// ---------------------------------------------------------------------------------------------- +// extract the eye-pos in world-space from the view matrix +// ---------------------------------------------------------------------------------------------- +float3 ExtractEyePosFromViewMatrix(float4x4 mat) +{ + return float3(mat[0].w, mat[1].w, mat[2].w); +} + +// ---------------------------------------------------------------------------------------------- +// extract the eye-dir in world-space from the view matrix +// ---------------------------------------------------------------------------------------------- +float3 ExtractEyeDirFromViewMatrix(float4x4 mat) +{ + return float3(mat[0].z, mat[1].z, mat[2].z); +} + +// ---------------------------------------------------------------------------------------------- +// extract z_near from projection matrix +// ---------------------------------------------------------------------------------------------- +float ExtractZnearFromProjectionMatrix(float4x4 mat) +{ + return mat[3][2] / mat[2][2]; +} + +// ---------------------------------------------------------------------------------------------- +// extract z_far from projection matrix +// ---------------------------------------------------------------------------------------------- +float ExtractZfarFromProjectionMatrix(float4x4 mat) +{ + return mat[3][2] / (mat[2][2] + 1.0); +} + +// ---------------------------------------------------------------------------------------------- +// extract FovY from projection matrix +// ---------------------------------------------------------------------------------------------- +float ExtractFovYFromProjectionMatrix(float4x4 mat) +{ + return 2.0 * atan(1.0 / mat[1][1]); +} + +// ---------------------------------------------------------------------------------------------- +// compute a simple rotation matrix from a given vector and angle +// ---------------------------------------------------------------------------------------------- +float3x3 GetRotationMatrixAxisAngle(float3 axis, float angle) +{ + float3x3 m; + + // pre + float oneMinusCosA = 1.0 - cos(angle); + float sinA = sin(angle); + + // matrix + m[0][0] = 1.0 + oneMinusCosA * (axis.x * axis.x - 1.0); + m[1][0] = -axis.z * sinA + oneMinusCosA * axis.x * axis.y; + m[2][0] = axis.y * sinA + oneMinusCosA * axis.x * axis.z; + + m[0][1] = axis.z * sinA + oneMinusCosA * axis.x * axis.y; + m[1][1] = 1.0 + oneMinusCosA * (axis.y * axis.y - 1.0); + m[2][1] = -axis.x * sinA + oneMinusCosA * axis.y * axis.z; + + m[0][2] = -axis.y * sinA + oneMinusCosA * axis.x * axis.z; + m[1][2] = axis.x * sinA + oneMinusCosA * axis.y * axis.z; + m[2][2] = 1.0 + oneMinusCosA * (axis.z * axis.z - 1.0); + + return m; +} + +// ---------------------------------------------------------------------------------------------- +// compute a rotation matrix which rotates axis1 into axis2 +// ---------------------------------------------------------------------------------------------- +float3x3 GetRotationMatrixNrmToNrm(float3 normal1, float3 normal2) +{ + float3 rotAxis = normalize(cross(normal1, normal2)); + float rotAngle = acos(dot(normal1, normal2)); + return GetRotationMatrixAxisAngle(rotAxis, rotAngle); +} + +// ---------------------------------------------------------------------------------------------- +// Create a transformation matrix from a quaternion of the form x, y, z, w +// ---------------------------------------------------------------------------------------------- +float4x4 CreateRotationMatrixFromQuaterion(float4 q) +{ + float tx2 = 2 * q.x * q.x; + float ty2 = 2 * q.y * q.y; + float tz2 = 2 * q.z * q.z; + + float txy = 2 * q.x * q.y; + float txz = 2 * q.x * q.z; + float txw = 2 * q.x * q.w; + float tyz = 2 * q.y * q.z; + float tyw = 2 * q.y * q.w; + float tzw = 2 * q.z * q.w; + + float4x4 m3 = + { + { 1 - ty2 - tz2, txy + tzw, txz - tyw, 0 }, + { txy - tzw, 1 - tx2 - tz2, tyz + txw, 0 }, + { txz + tyw, tyz - txw, 1 - tx2 - ty2, 0 }, + { 0, 0, 0, 1 } + }; + return m3; +} + +// ---------------------------------------------------------------------------------------------- +// combine a 3x3 rotation matrix and a float3 position to a 4x4 transform +// ---------------------------------------------------------------------------------------------- +float4x4 CreateTransformMatrix(float3x3 rotationMatrix, float3 translation) +{ + float4x4 m; + + m[0] = float4(rotationMatrix[0], 0.0); + m[1] = float4(rotationMatrix[1], 0.0); + m[2] = float4(rotationMatrix[2], 0.0); + m[3] = float4(translation, 1.0); + + return m; +} + +// ---------------------------------------------------------------------------------------------- +// combine a rotation quaternion and a float4 position to a 4x4 transform +// ---------------------------------------------------------------------------------------------- +float4x4 CreateTransformMatrix(float4 rotationQuaternion, float4 translation) +{ + float4x4 m = CreateRotationMatrixFromQuaterion(rotationQuaternion); + m[3] = translation; + + return m; +} + +// ---------------------------------------------------------------------------------------------- +// extract translation from transform matrix +// ---------------------------------------------------------------------------------------------- +float3 ExtractTranslationFromTransformMatrix(float4x4 mat) +{ + return mat[3].xyz; +} + +// ---------------------------------------------------------------------------------------------- +// extract rotation from transform matrix +// ---------------------------------------------------------------------------------------------- +float3x3 ExtractRotationFromTransformMatrix(float4x4 mat) +{ + float3x3 m; + + m[0] = mat[0].xyz; + m[1] = mat[1].xyz; + m[2] = mat[2].xyz; + return m; +} + +// ---------------------------------------------------------------------------------------------- +// remove translation from a transform matrix +// ---------------------------------------------------------------------------------------------- +float4x4 RemoveTranslationFromMatrix(float4x4 transformMatrix) +{ + float4x4 m = transformMatrix; + m[3] = float4(0.0, 0.0, 0.0, 1.0); + + return m; +} + +// ---------------------------------------------------------------------------------------------- +// create an identity matrix +// ---------------------------------------------------------------------------------------------- +float4x4 CreateIdentityMatrix() +{ + float4x4 m; + + m[0] = float4(1.0, 0.0, 0.0, 0.0); + m[1] = float4(0.0, 1.0, 0.0, 0.0); + m[2] = float4(0.0, 0.0, 1.0, 0.0); + m[3] = float4(0.0, 0.0, 0.0, 1.0); + + return m; +} + +// ---------------------------------------------------------------------------------------------- +// create a non-uniform scaling matrix +// ---------------------------------------------------------------------------------------------- +float4x4 CreateScalingMatrix(float3 s) +{ + float4x4 m; + + m[0] = float4(s.x, 0.0, 0.0, 0.0); + m[1] = float4(0.0, s.y, 0.0, 0.0); + m[2] = float4(0.0, 0.0, s.z, 0.0); + m[3] = float4(0.0, 0.0, 0.0, 1.0); + + return m; +} + +// ---------------------------------------------------------------------------------------------- +// compute a perpendicular vector to a given base vector: is any vector, only perpendicular +// ---------------------------------------------------------------------------------------------- +float3 GetVectorPerpendicular(float3 basis) +{ + // somehow this simple problem of constructing ANY perpendicular to a given vector + // is unsolvable.... at least in a nice, non-hacky way + float3 v = basis.yzx; + return normalize(cross(v, basis)); +} + +// ---------------------------------------------------------------------------------------------- +// "re-linearize" v from min to max +// ---------------------------------------------------------------------------------------------- +float LinStep(float min, float max, float v) +{ + return clamp((v - min) / (max - min), 0.0, 1.0); +} + +// ---------------------------------------------------------------------------------------------- +// remap a value from input range to an output range +// ---------------------------------------------------------------------------------------------- +float RemapFloatRange(float x, float inMin, float inMax, float outMin = 0.0f, float outMax = 1.0f) +{ + return outMin + ((x - inMin) / (inMax - inMin)) * (outMax - outMin); +} + +// ---------------------------------------------------------------------------------------------- +// Hermite spline position +// ---------------------------------------------------------------------------------------------- +float3 HermiteSplinePos(float3 v1, float3 t1, float3 v2, float3 t2, float s) +{ + // spline parameters + float3 a = 2.0 * v1 - 2.0 * v2 + t2 + t1; + float3 b = 3.0 * v2 - 3.0 * v1 - 2.0 * t1 - t2; + float3 c = t1; + float3 d = v1; + // cubic equation + return a * s * s * s + b * s * s + c * s + d; +} + +// ---------------------------------------------------------------------------------------------- +// Hermite spline direction (derive!) +// ---------------------------------------------------------------------------------------------- +float3 HermiteSplineDir(float3 v1, float3 t1, float3 v2, float3 t2, float s) +{ + // spline parameters + float3 a = 2.0 * v1 - 2.0 * v2 + t2 + t1; + float3 b = 3.0 * v2 - 3.0 * v1 - 2.0 * t1 - t2; + float3 c = t1; + // cubic equation becomes 2-dim cause of derive + return 3.0 * a * s * s + 2.0 * b * s + c; +} + +// ---------------------------------------------------------------------------------------------- +// Convert cartesian direction vector to spherical +// ---------------------------------------------------------------------------------------------- +float2 CartesianToSpherical(float3 dir) +{ + // x = sin( theta ) * sin( phi ) + // y = cos( phi ) + // z = cos( theta ) * sin( phi ) + float phi = acos(dir.y); + float theta = PI + atan2(dir.z, dir.x); + return float2(theta, phi); +} + +// ---------------------------------------------------------------------------------------------- +// Convert spherical coords into cartesian vector +// ---------------------------------------------------------------------------------------------- +float3 SphericalToCartesian(float2 spherical) +{ + float z = -sin(spherical.x) * sin(spherical.y); + float y = cos(spherical.y); + float x = -cos(spherical.x) * sin(spherical.y); + return float3(x, y, z); +} + + +float4 Vec4Cross(float4 v1, float4 v2, float4 v3) +{ + float4 result; + result.x = v1.y * (v2.z * v3.w - v3.z * v2.w) - v1.z * (v2.y * v3.w - v3.y * v2.w) + v1.w * (v2.y * v3.z - v2.z * v3.y); + result.y = -(v1.x * (v2.z * v3.w - v3.z * v2.w) - v1.z * (v2.x * v3.w - v3.x * v2.w) + v1.w * (v2.x * v3.z - v3.x * v2.z)); + result.z = v1.x * (v2.y * v3.w - v3.y * v2.w) - v1.y * (v2.x * v3.w - v3.x * v2.w) + v1.w * (v2.x * v3.y - v3.x * v2.y); + result.w = -(v1.x * (v2.y * v3.z - v3.y * v2.z) - v1.y * (v2.x * v3.z - v3.x * v2.z) + v1.z * (v2.x * v3.y - v3.x * v2.y)); + return result; +} + +float4x4 MatrixInverse(float4x4 m) +{ + float4 v, vec[3]; + float d; + + d = determinant(m); + if (!d) + { + return m; + } + float4x4 result; + [unroll] + for (int i = 0; i < 4; i++) + { + float signedDet = (i % 2 == 1) ? -1.f : 1.f; + signedDet /= d; + for (int j = 0; j < 4; j++) + { + if (j != i) + { + int a = j; + if (j > i) + { + a = a - 1; + } + vec[a].x = m[j][0]; + vec[a].y = m[j][1]; + vec[a].z = m[j][2]; + vec[a].w = m[j][3]; + } + } + v = Vec4Cross(vec[0], vec[1], vec[2]); + result[0][i] = signedDet * v.x; + result[1][i] = signedDet * v.y; + result[2][i] = signedDet * v.z; + result[3][i] = signedDet * v.w; + } + return result; +} + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh b/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh new file mode 100644 index 000000000..0a97167f8 --- /dev/null +++ b/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh @@ -0,0 +1,73 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_ENVIRONMENTMAP_FXH +#define CARBON_ENVIRONMENTMAP_FXH + +#include "../System.fxh" + + +// -------------------------------------------------------------------------------------------------- +// texture +// -------------------------------------------------------------------------------------------------- +// Environment map (refleciton) texture set by EveSpaceScene +TextureCube EveSpaceSceneEnvMap +< + bool AutoRegister = true; + bool Tr2sRGB = true; +>; +SamplerState EveSpaceSceneEnvMapSampler +{ + MinFilter = Anisotropic; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Wrap; + AddressV = Wrap; +}; + +// Helper function to convert PBR roughness to gloss value used for environment map lookup +float RoughnessToGloss( float roughness ) +{ + const float GGX_MAX_SPEC_POWER = 28; + const float EPSILON = 0.00052556; + float gloss = 1.0; + if( roughness >= EPSILON ) + { + gloss = roughness * roughness; + gloss *= gloss; + gloss = ( 2.0f / gloss ) - 1.0f; + gloss = log2( gloss ) / GGX_MAX_SPEC_POWER; + } + + return gloss; +} + +// Helper function to convert PBR roughness to mip level used for environment map lookup +float RoughnessToMip( TextureCube envMap, float roughness ) +{ + uint width; + uint height; + uint mipLevels; + envMap.GetDimensions( width, height, mipLevels ); + + return ( 1.0f - RoughnessToGloss( roughness ) ) * float( mipLevels - 1 ); +} + +// Helper function to convert PBR roughness to mip level used for environment map lookup for EveSpaceSceneEnvMap +float RoughnessToMip( float roughness ) +{ + return RoughnessToMip( EveSpaceSceneEnvMap, roughness ); +} + +// Sample an environment map with given direction and surface roughness +float3 SampleEnvironmentMap( TextureCube envMap, float3 dir, float roughness ) +{ + return envMap.SampleLevel( EveSpaceSceneEnvMapSampler, dir, RoughnessToMip( envMap, roughness ) ).rgb; +} + +// Sample EveSpaceSceneEnvMap with given direction and surface roughness +float3 SampleEnvironmentMap( float3 dir, float roughness ) +{ + return SampleEnvironmentMap( EveSpaceSceneEnvMap, dir, roughness ); +} + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/SpaceScene/PerSceneData.fxh b/shaders/include/carbon/SpaceScene/PerSceneData.fxh new file mode 100644 index 000000000..ae3282747 --- /dev/null +++ b/shaders/include/carbon/SpaceScene/PerSceneData.fxh @@ -0,0 +1,86 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_SPACESCENE_PERSCENEDATA_FXH +#define CARBON_SPACESCENE_PERSCENEDATA_FXH + +#include "../System.fxh" + + +struct FroxelPerFrameData +{ + float3 FogColor; + float BackgroundVisibility; + + float BaseDensity; + float MaxDistance; + float MaxDistanceVisibility; + float EnvironmentIntensity; + + float EnvironmentG; + float _pad0; + float _pad1; + float _pad2; + + float4 Planets[2]; +}; + +// Per-scene (per-frame) constant buffer data for the vertex shader. +struct EveSpaceSceneDataVS +{ + // matrices + float4x4 ViewInverseTransposeMat; + float4x4 ViewProjectionMat; + float4x4 ViewMat; + float4x4 ProjectionMat; + float4x4 ShadowViewMat; + float4x4 ShadowViewProjectionMat; + float4x4 EnvMapRotationMat; + float4x4 ViewProjectionLast; + float4x4 ViewLast; + float4x4 ProjLast; + // lighting info + float4 SunDirection; + float4 SunDiffuseColor; + float3 FogFactors; // Depth multiplier in x, constant in y and max fog in z + // rendertarget resolution and fovXY (rt pixelsize in .xy, fovXY in .zw) + float4 TargetResolution; + float4 ViewportAdjustment; + float4 MiscParams; // x - time, y - upscaling amount, zw - viewport size +}; + + +// Per-scene (per-frame) constant buffer data for the pixel shader. +struct EveSpaceSceneDataPS +{ + // some pixel-shaders do need these... + float4x4 ViewInverseTransposeMat; + float4x4 ViewMat; + float4x4 EnvMapRotationMat; + + // scene info + float4 SunDirection; + float4 SunDiffuseColor; // .rgb - sun diffuse color, .a - environment map diffuse "roughness" + float4 AmbientColor; // .rgb - ambient color, .a - nebula intensity + float4 FogColor; + + // various info + float4 ViewportOffsetSize; // .xy - viewport offset, .zw - viewport size + float4 RenderTargetData; // .xy - RT size in pixel, z - MSAA sample count (legacy, always 1 nowadays), w - debug + float4 ShadowMapSettings; // .xyzw - various shadow filter parameters + float4 ShadowMapSettings2; // .xy - shadow camera range, .z - shadow lightness, .w - shadow quality + float4 ProjectionData; // x - projection[3][2], y - projection[2][2], .zw = FoV + float4 MiscData; // x - time, y - scenemiplodbias, z - upscaling amount, w - gamma brightness + uint4 MiscData2; // x - frame counter, y - Jittering (bool), z - InverseShadowMapAtlasSize (float), w - ShadowMapAtlasEntryMinSizeLog2 (uint) + float4 VolumetricSlices; + float4 ShadowMapValues[4]; // x = zFar value[0], y = zFar value[1], z = zFar value[2], w = zFar value[3]..etc + float4x4 ShadowMatrix[16]; // Matrix that takes a coordinate from view space all the way to the packed cascades + float4 SplitInfo; // x = NrOfSplits, y = , z = , w = + float4x4 ProjectionInverseMat; // + float4 CascadeRanges[16]; + + //Froxel fog related global variables + FroxelPerFrameData FroxelFogData; +}; + + +#endif // CARBON_SPACESCENE_PERSCENEDATA_FXH \ No newline at end of file diff --git a/shaders/include/carbon/SpaceScene/Volumetrics.fxh b/shaders/include/carbon/SpaceScene/Volumetrics.fxh new file mode 100644 index 000000000..2e4a7d476 --- /dev/null +++ b/shaders/include/carbon/SpaceScene/Volumetrics.fxh @@ -0,0 +1,223 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_SPACESCENE_VOLUMETRICS_FXH +#define CARBON_SPACESCENE_VOLUMETRICS_FXH + +#include "../System.fxh" +#include "../Intersections.fxh" +#include "PerSceneData.fxh" +#include "../Math.fxh" + +// Depth slices for the rendered cloud volume (see EveChildCloud2) +Texture2DArray EveSceneFogVolumeMap ; + +// 3D froxel fog map and Mie environment map for volumetric effects +Texture3D EveSceneFroxelFogMap ; +TextureCube EveSceneMieEnvironmentMap ; + + +SamplerState EveSceneFogSampler = sampler_state +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; +}; + +SamplerState EveSceneFogVolumeMapSampler = sampler_state +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; +}; + + +float4 _CubicWeights( float x ) +{ + float x2 = x * x; + float x3 = x2 * x; + + const float4x4 m = float4x4( + +2, -3, -3, +5, + -2, +3, +3, +1, + +3, -6, +0, +4, + +1, +0, +0, +0 + ) * (1.0 / 6.0); + + return mul( m, float4( x3, x2, x, 1 ) ); +} + + +// Sample the 3D froxel fog map with bicubic filtering in the XY plane and bilinear filtering in the Z direction. +float3 SampleEveSceneFroxelFogRaw( float2 tc, float z ) +{ + + //Uncomment to disable bicubic filtering + //return EveSceneFroxelFogMap.SampleLevel(EveSceneFogSampler, float3(tc, z), 0.0f); + + + //The following code does 4x4 bicubic filtering on the froxel texture, using only bilinear for Z. + + //float2 size = PerFramePS.FroxelFogData.FroxelResolution.xy; + //float2 invSize = PerFramePS.FroxelFogData.FroxelResolution.zw; + + float width, height, dummy; + EveSceneFroxelFogMap.GetDimensions(width, height, dummy); + float2 size = float2(width, height); + float2 invSize = rcp(size); + + tc = tc * size - 0.5; + + float2 floored = floor(tc); + float2 frac = tc - floored; + + float2 baseTC = floored * invSize; + + float4 weightsX = _CubicWeights(frac.x); + float4 weightsY = _CubicWeights(frac.y); + + + //Since the specific spline used for the cubic weights means that all 4 weights will be over 1.0, + //we can sample a 2x2 area with specific weights for each of the 4 samples by carefully choosing + //the point we sample to achieve the correct ratio of weight between them, and then multiplying + //that ratio by the total of all 4 samples. + + //The problem is simplified due to the fact that we can calculate the weights along X and Y separately. + + //These are the offsets we need to use to get the correct ratio of the texels we want to sample. + float2 offsets0 = float2(weightsX.z / weightsX.x - 0.5, weightsY.z / weightsY.x - 0.5) * invSize + baseTC; //Top left + float2 offsets1 = float2(weightsX.w / weightsX.y + 1.5, weightsY.w / weightsY.y + 1.5) * invSize + baseTC; //Bot right + + //This is the total weight for each of the four samples. + float2 w = float2(weightsX.x, weightsY.x) / float2(weightsX.x + weightsX.y, weightsY.x + weightsY.y); //Top left weight + float2 iw = 1.0 - w; //Bot right weight + + //Do the 4 samples at the correct locations and apply the correct weights. + return + EveSceneFroxelFogMap.SampleLevel(EveSceneFogSampler, float3(offsets0.x, offsets0.y, z), 0.0f) * (( w.x) * ( w.y)) + + EveSceneFroxelFogMap.SampleLevel(EveSceneFogSampler, float3(offsets1.x, offsets0.y, z), 0.0f) * ((iw.x) * ( w.y)) + + EveSceneFroxelFogMap.SampleLevel(EveSceneFogSampler, float3(offsets0.x, offsets1.y, z), 0.0f) * (( w.x) * (iw.y)) + + EveSceneFroxelFogMap.SampleLevel(EveSceneFogSampler, float3(offsets1.x, offsets1.y, z), 0.0f) * ((iw.x) * (iw.y)); +} + + +// Get the froxel fog color for the given screen-space texture coordinates, scene depth. +float4 SampleEveSceneFroxelFog( float2 texCoords, float sceneDepth, EveSpaceSceneDataPS sceneData, bool sampleEnvironmentLighting ) +{ + float4 viewPositionProj = mul(float4(texCoords.x * 2.0 - 1.0, texCoords.y * -2.0 + 1.0, sceneDepth, 1.0), sceneData.ProjectionInverseMat); + float3 viewPosition = viewPositionProj.xyz / viewPositionProj.w; + + + + float dist = min(sceneData.FroxelFogData.MaxDistance, length(viewPosition)); + if(sceneDepth <= 0.0) + { + //If we're at the far plane, override the distance to match the game's expected back clip. + //This makes sure that the fog is the same even if the back clip is adjusted in Graphite. + dist = sceneData.FroxelFogData.MaxDistance; + } + + float4x4 inverseViewMatrix = transpose(sceneData.ViewInverseTransposeMat); + + float3 cameraWorldPosition = mul(float4(0.0, 0.0, 0.0, 1.0), inverseViewMatrix).xyz; + + float3 viewDirection = normalize(viewPosition); + float3 worldDirection = mul(float4(viewDirection, 0.0), inverseViewMatrix).xyz; + + [unroll] + for( int index = 0; index < 2; ++index) + { + float4 sphereData = sceneData.FroxelFogData.Planets[index]; + SphereHitInfo hitInfo = SphereRayHitTest( InitSphere( sphereData.xyz, sphereData.w ), InitRay( cameraWorldPosition, worldDirection ) ); + if( hitInfo.occurred ) + { + dist = min( dist, hitInfo.firstIntersection.w ); + } + } + + float normalizedZ = saturate((exp(-dist * sceneData.FroxelFogData.BaseDensity) - 1.0) / (sceneData.FroxelFogData.MaxDistanceVisibility - 1.0)); + + float3 froxel = SampleEveSceneFroxelFogRaw(texCoords, normalizedZ); + + float extinction = lerp(sceneData.FroxelFogData.BackgroundVisibility, 1.0, exp(-dist * sceneData.FroxelFogData.BaseDensity)); + + + + if( sampleEnvironmentLighting ) + { + float3 environmentLighting = EveSceneMieEnvironmentMap.SampleLevel(EveSceneFogSampler, worldDirection, 0.0).rgb; + + //float shadowing = sceneDepth != 0.0 ? pow(saturate(1.0 - extinction), -sceneData.FroxelFogData.EnvironmentG * 4.0) : 1.0; + float shadowing = 1.0; //Shadowing the environment lighting causes a mismatch between clouds and opaque objects. + + froxel += ((1.0 - extinction) * shadowing * sceneData.FroxelFogData.EnvironmentIntensity) * (environmentLighting * sceneData.FroxelFogData.FogColor); + } + + + return float4( froxel, extinction ); +} + + +float4 SampleEveSceneFog( float4 pos, EveSpaceSceneDataPS sceneData ) // pos is SV_Position +{ + float t0 = sceneData.VolumetricSlices.x; + float t1 = sceneData.VolumetricSlices.y; + float t2 = sceneData.VolumetricSlices.z; + float t3 = sceneData.VolumetricSlices.w; + + float i0, i1; + float z; + float depth = sceneData.ProjectionData.x / ( pos.z + sceneData.ProjectionData.y ); + float weight = 1; + if( depth > t2 ) + { + i0 = 2; + i1 = 3; + z = saturate( LinStep( t2, t3, depth ) ); + } + else if( depth > t1 ) + { + i0 = 1; + i1 = 2; + z = LinStep(t1, t2, depth); + } + else if( depth > t0 ) + { + i0 = 0; + i1 = 1; + z = LinStep(t0, t1, depth); + } + else + { + i0 = 0; + i1 = 0; + z = LinStep(0, t0, depth); + weight = depth / t0; + } + + float2 texCoords = pos.xy / sceneData.RenderTargetData.xy; + + float4 color0 = EveSceneFogVolumeMap.SampleLevel( EveSceneFogVolumeMapSampler, float3( texCoords, i0 ), 0 ); + float4 color1 = EveSceneFogVolumeMap.SampleLevel( EveSceneFogVolumeMapSampler, float3( texCoords, i1 ), 0 ); + float4 color = lerp( color0, color1, z ); + color *= weight; + return color; +} + +float4 SampleEveSceneVolumetrics( float4 pos, EveSpaceSceneDataPS sceneData ) // pos is SV_Position +{ + float4 result = SampleEveSceneFog( pos, sceneData ); + float2 texCoords = pos.xy / sceneData.RenderTargetData.xy; + float4 froxels = SampleEveSceneFroxelFog( texCoords, pos.z, sceneData, sceneData.FroxelFogData.EnvironmentIntensity > 0.0 ); + froxels.a = 1.0 - froxels.a; + result += (1.0 - result.a) * froxels; + + return result; +} + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/System.fxh b/shaders/include/carbon/System.fxh index 75b1f4eda..7706d9c66 100644 --- a/shaders/include/carbon/System.fxh +++ b/shaders/include/carbon/System.fxh @@ -78,4 +78,14 @@ #define SHADER_QUALITY SHADERMODEL #endif + +// Hits for the shader compiler signifying per-object and per-frame constant buffers. +// Used in global variable declarations. The actual register numbers specified in macros are +// just hints to the compiler, and have nothing to do with the actual binding. Declaration example: +// PerFrameStructType PerFrameVS : register( PERFRAME_VS_STARTREGISTER ); +#define PERFRAME_VS_STARTREGISTER vs, c220 +#define PERFRAME_PS_STARTREGISTER ps, c200 +#define PEROBJECT_VS_STARTREGISTER vs, c16 +#define PEROBJECT_PS_STARTREGISTER ps, c40 + #endif \ No newline at end of file From e93c2e331e3b80b1efd714f47ac4984694d6f79b Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 2 Oct 2026 12:58:18 +0000 Subject: [PATCH 05/83] Add support for TextureCube.GetDimensions override for Metal --- shadercompiler/MSLInclude.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/shadercompiler/MSLInclude.h b/shadercompiler/MSLInclude.h index 100ceabfd..8916757f1 100644 --- a/shadercompiler/MSLInclude.h +++ b/shadercompiler/MSLInclude.h @@ -332,6 +332,14 @@ void GetDimensions( texturecube tex, thread W& w, thread H& h ) h = H( tex.get_height() ); } +template +void GetDimensions( texturecube tex, uint mip, thread W& w, thread H& h, thread M& m ) +{ + w = W( tex.get_width() ); + h = H( tex.get_height() ); + m = M( tex.get_num_mip_levels() ); +} + template void GetDimensions( texture3d tex, thread W& w, thread H& h, thread D& d ) { From 78c6d4a3c25acddd1919d9fb2145bdc6f84054e2 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 2 Oct 2026 13:02:36 +0000 Subject: [PATCH 06/83] More shaders --- CMakeLists.txt | 3 + shaders/include/carbon/BoneTransforms.fxh | 19 + shaders/include/carbon/Math.fxh | 4 +- .../include/carbon/SpaceScene/DepthMap.fxh | 9 + .../carbon/SpaceScene/DynamicLighting.fxh | 401 ++++++++++++++++++ .../carbon/SpaceScene/EnvironmentMap.fxh | 10 +- .../carbon/SpaceScene/PerSceneData.fxh | 6 +- shaders/include/carbon/System.fxh | 16 + 8 files changed, 457 insertions(+), 11 deletions(-) create mode 100644 shaders/include/carbon/BoneTransforms.fxh create mode 100644 shaders/include/carbon/SpaceScene/DepthMap.fxh create mode 100644 shaders/include/carbon/SpaceScene/DynamicLighting.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index ed4e33e1a..d26921750 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,10 +132,13 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() set(_SHADER_SOURCES + shaders/include/carbon/SpaceScene/DepthMap.fxh + shaders/include/carbon/SpaceScene/DynamicLighting.fxh shaders/include/carbon/SpaceScene/EnvironmentMap.fxh shaders/include/carbon/SpaceScene/PerSceneData.fxh shaders/include/carbon/SpaceScene/Volumetrics.fxh shaders/include/carbon/Bindless.fxh + shaders/include/carbon/BoneTransforms.fxh shaders/include/carbon/Intersections.fxh shaders/include/carbon/Math.fxh shaders/include/carbon/PackedTangents.fxh diff --git a/shaders/include/carbon/BoneTransforms.fxh b/shaders/include/carbon/BoneTransforms.fxh new file mode 100644 index 000000000..f2b6feae0 --- /dev/null +++ b/shaders/include/carbon/BoneTransforms.fxh @@ -0,0 +1,19 @@ +#ifndef CARBON_BONETRANSFORMS_FXH_ +#define CARBON_BONETRANSFORMS_FXH_ + +// Contains bone transforms for skeletal animation for all objects in the render pass. Each bone transform is a +// 4x3 matrix (3 rows of 4 floats) that represents the transformation of a bone in the skeleton. +StructuredBuffer BoneTransforms ; + +float4x4 GetBoneTransform( int boneIndex ) +{ + float4x3 bone = BoneTransforms[boneIndex]; + + float4x4 boneMatrix = float4x4( float4( bone[0], 0.0 ), + float4( bone[1], 0.0 ), + float4( bone[2], 0.0 ), + float4( bone[3], 1.0 ) ); + return boneMatrix; +} + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/Math.fxh b/shaders/include/carbon/Math.fxh index b90ce7cf4..bb96c3247 100644 --- a/shaders/include/carbon/Math.fxh +++ b/shaders/include/carbon/Math.fxh @@ -3,8 +3,8 @@ #ifndef CARBON_MATH_FXH #define CARBON_MATH_FXH -static float PI = 3.1415926535897932384626433832795; -static float _2PI = 6.283185307179586476925286766559; +static const float PI = 3.1415926535897932384626433832795; +static const float _2PI = 6.283185307179586476925286766559; static const float4x4 IDENTITY_MATRIX = float4x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); diff --git a/shaders/include/carbon/SpaceScene/DepthMap.fxh b/shaders/include/carbon/SpaceScene/DepthMap.fxh new file mode 100644 index 000000000..c802c914b --- /dev/null +++ b/shaders/include/carbon/SpaceScene/DepthMap.fxh @@ -0,0 +1,9 @@ +#ifndef CARBON_DEPTHMAP_FXH +#define CARBON_DEPTHMAP_FXH + +// Contains SRV representation of the depth buffer for the current render pass. Note that not all render passes may use a depth buffer, +// so this may be unbound in some cases. For example, opaque forward rendering passes may not use a depth buffer, while transparent +// forward rendering passes may use the depth buffer from the opaque pass. +Texture2D DepthMap ; + +#endif // CARBON_DEPTHMAP_FXH \ No newline at end of file diff --git a/shaders/include/carbon/SpaceScene/DynamicLighting.fxh b/shaders/include/carbon/SpaceScene/DynamicLighting.fxh new file mode 100644 index 000000000..faf217c0b --- /dev/null +++ b/shaders/include/carbon/SpaceScene/DynamicLighting.fxh @@ -0,0 +1,401 @@ +#ifndef CARBON_DYNAMICLIGHTING_FXH +#define CARBON_DYNAMICLIGHTING_FXH + +#include "../System.fxh" +#include "PerSceneData.fxh" +#include "../Math.fxh" + +// Packed light data for a single light source. See LightBuffer variable. +struct PerLightData +{ + float4 position; // xyz - world position, w - radius + float4 color; // xyz - color, w - bits 0..15 - innerRadius (float 16), bits 16..31 - flags + float4 direction; // see next few lines: + // x bits 0..15 - direction.x (float 16), x bits 16..31 - direction.y (float 16) + // y bits 0..15 - direction.z (float 16), y bits 16..31 - projectionPlaneDistance (float 16) + // z bits 0..15 - outerAngle (float 16), z bits 16..31 - innerAngle (float 16) + // w bits 0..1 - padding, w bits 2..11 - shadowMapScale, w bits 12..21 - shadowMapOffsetX, w bits 22..31 - shadowMapOffsetY +}; + +// Light flags stored in PerLightData.color.w + +// Light affects surfaces (opaque and transparent) +static const uint LIGHT_FLAG_AFFECTS_SURFACE = 1 << 16; +// Light affects particles (opaque and transparent) +static const uint LIGHT_FLAG_AFFECTS_PARTICLES = 1 << 17; +// Light casts shadows +static const uint LIGHT_FLAG_CASTS_SHADOWS = 1 << 18; +// Light affects volumetric fog (if enabled) +static const uint LIGHT_FLAG_IS_VOLUMETRIC = 1 << 19; + +// Stores linked lists of indices into LightBuffer for each tile in the screen. The buffer is partitioned into two sections: +// 3 arrays of per-tile list heads (opaque, transparent and particle arrays) and per-light next indices. The first section contains one uint per tile, +// which is the index (into LightIndexBuffer) of the first light in the linked list for that tile. The second section contains one uint per light, which is the index of the +// next light in the linked list for that tile. A value of for the index 0 indicates the end of the list. +StructuredBuffer LightIndexBuffer ; +// Stores the actual light data for each potentially visible light in the scene. The index into this buffer is stored in LightIndexBuffer. +StructuredBuffer LightBuffer ; + +// Global array of light profiles (IES profiles) for lights that use them. The index into this array is stored in PerLightData.color.w. +Texture2DArray LightProfileArray ; +SamplerState LightProfileSampler +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = None; + AddressU = Clamp; + AddressV = Clamp; +}; + +// Global shadow map atlas for all lights that cast shadows. The window of this atlas is stored in PerLightData.direction.w. +// This atlas is used when rendering rastrized shadows. Raytraced shadows are stored in EveSpaceSceneDynamicShadowMap. +DepthTexture2D ShadowMapAtlas < bool AutoRegister = true; >; + +SamplerComparisonState ShadowMapAtlasSampler +{ + AddressU = Clamp; + AddressV = Clamp; + ComparisonFunc = Greater; + Filter = COMPARISON_MIN_MAG_LINEAR_MIP_POINT; +}; + +Texture2D EveSpaceSceneDynamicShadowMap ; + +// The size of a tile in pixels. This is used to determine which tile a pixel belongs to when looking up the light list for that tile. +#define TILE_SIZE 16 + + +// ------------------------------------------------------------ PCF ------------------------------------------------------------- + +float2x2 _PCFTransform( float2 vpos, bool hasJitter, int frameIndex, float inverseShadowMapAtlasSize ) +{ + float angle = 0.0; + + //Randomize the angle if jittering is enabled (= we have some form of temporal filtering) + //Otherwise, we do no rotating at all to make sure the image isn't noisy or unstable when no AA or upscaling is enabled. + + if( hasJitter ) + { + int2 pixelPos = int2( vpos ); + //We use 9 evenly distributed rotations, which change both per pixel and over time + //This gives us effectively NUM_SAMPLES * 9 samples over time. + uint dither = ( pixelPos.x * 3u + pixelPos.y * 4u + frameIndex * 5u ) % 9u; + angle += float( dither ) * ( PI * 2.0 / 9.0 ); + } + + //Build a rotation matrix so that we can apply the quickly to each sample. + float s; + float c; + sincos( angle, s, c ); + float2x2 rotation = float2x2( + c, -s, + s, c + ); + + return rotation * inverseShadowMapAtlasSize; +} + +float2x2 _PCFTransform( float2 vpos, EveSpaceSceneDataPS perFramePS ) +{ + bool hasJitter = perFramePS.MiscData2.y != 0; + int frameIndex = perFramePS.MiscData2.x; + float inverseShadowMapAtlasSize = asfloat( perFramePS.MiscData2.z ); + return _PCFTransform( vpos, hasJitter, frameIndex, inverseShadowMapAtlasSize ); +} + +// based on: https://www.shadertoy.com/view/4djSRW +float3 _Random( float2 p, uint timer ) +{ + timer &= 2047; + float3 p3 = float3( p, float( timer ) ); + p3 = frac( p3 * float3( .1031, .1030, .0973 ) ); + p3 += dot( p3, p3.yxz + 33.33 ); + return frac( ( p3.xxy + p3.yxx ) * p3.zyx ); +} + +float3 _PCFOffset( float2 vpos, EveSpaceSceneDataPS perFramePS ) +{ + bool hasJitter = perFramePS.MiscData2.y != 0; + return hasJitter ? _Random( vpos, perFramePS.MiscData2.x ).xyz * .004 : 0.0.xxx; +} + +struct _PCFJitter +{ + float2x2 transform; + float3 offset; +}; + +_PCFJitter _GetPCFJitter( float2 vpos, EveSpaceSceneDataPS perFramePS ) +{ + _PCFJitter jitter; + jitter.transform = _PCFTransform( vpos, perFramePS ); + jitter.offset = _PCFOffset( vpos, perFramePS ); + return jitter; +} + +float _PCF( _PCFJitter pcfJitter, DepthTexture2D ShadowMapAtlas, SamplerComparisonState ShadowMapAtlasSampler, float centerDepth, float2 uv ) +{ + const int NUM_SAMPLES = 16; //higher count reduces flickering, but is slower + const float RADIUS = 4.5; //higher increases filter radius, making the transition softer and reducing flickering + + //Here we do a golden angle spiral sample pattern ("optimal" even distribution over a circle) over a larger area + float pcf = 0.0; + [unroll] + for( int i = 0; i < NUM_SAMPLES; i++ ) + { + //The following values are all constant in an unrolled loop + //That's why we don't include the extra "random" rotation here! + const float GOLDEN_ANGLE = PI * ( 3.0 - sqrt( 5.0 ) ); + float angle = float( i ) * GOLDEN_ANGLE; + float f = ( float( i ) + 0.5 ) / float( NUM_SAMPLES ); + float2 sampleOffset = float2( cos( angle ), sin( angle ) ) * ( sqrt( f ) * RADIUS ); + float weight = 1.0 / float( NUM_SAMPLES ); + + //These are actually calculated per sample, so we apply the per-pixel rotation here + float2 sampleUV = uv + mul( pcfJitter.transform, sampleOffset ); + + float comparisonResult = ShadowMapAtlas.SampleCmpLevelZero( ShadowMapAtlasSampler, sampleUV, centerDepth ); + pcf += comparisonResult * weight; + } + + float visibility = pcf; + return visibility; +} + +// ------------------------------------------------------------------------------------------------------------------------------ + +struct ShadowData +{ + _PCFJitter pcfJitter; + uint raytracedMask; +}; + +ShadowData GetShadowData( float2 vpos, EveSpaceSceneDataPS perFramePS ) +{ + ShadowData shadowData; + shadowData.pcfJitter.transform = float2x2( 0., 0., 0., 0. ); + shadowData.pcfJitter.offset = 0.0.xxx; + shadowData.raytracedMask = 0; + + uint shadowQuality = asuint( perFramePS.ShadowMapSettings2.w ); + if( ( shadowQuality & ( SHADOW_QUALITY_FLAG_LOW | SHADOW_QUALITY_FLAG_HIGH ) ) != 0 ) + { + shadowData.pcfJitter = _GetPCFJitter( vpos, perFramePS ); + } + if( ( shadowQuality & SHADOW_QUALITY_FLAG_RAYTRACED ) != 0 ) + { + shadowData.raytracedMask = EveSpaceSceneDynamicShadowMap.Load( int3( int2( vpos.xy ), 0 ) ).x; + } + return shadowData; +} + +// Light list types for GetDynamicLightingListHead function +static const uint LIGHT_LIST_TYPE_OPAQUE = 0; +static const uint LIGHT_LIST_TYPE_TRANSPARENT = 1; +static const uint LIGHT_LIST_TYPE_PARTICLES = 2; + +// Returns the index of the first light record in the linked list for the tile that contains the pixel at vpos. +// The lightListType parameter specifies which list to return (opaque, transparent or particle). +uint GetDynamicLightingListHead( uint2 vpos, uint targetWidth, uint lightListType ) +{ + uint2 pixelPos = vpos.xy / TILE_SIZE; + uint tilesPerRow = ( targetWidth + TILE_SIZE - 1 ) / TILE_SIZE; + uint index = pixelPos.x + pixelPos.y * tilesPerRow; + return LightIndexBuffer[index * 3 + lightListType]; +} + + +struct ComputedDynamicLight +{ + // Direction from the lit position to the light source, normalized. + float3 lightDirection; + // Distance from the lit position to the light source. + float distance; + // Color of the light source, after shadowing. Does not take distance-based attenuation into account. + float3 lightColor; + // Increase in roughness due to the light. + float roughnessIncrease; + // Light radius + float radius; + // Light inner radius + float innerRadius; +}; + +// Computes the lighting contribution of a single light source at a given position in world space. +// Returns true if the light contributes to the lighting at the given position (based on distance and filters), false otherwise. +// The lighting data is returned in the computedDynamicLight parameter. +// Parameters: +// shadowData - Shadow data for the current pixel, including PCF jitter and raytraced mask. Normally GetDynamicLight is called in a loop over all lights, +// and this data is computed once per pixel and passed to each call to GetDynamicLight. +// inverseShadowMapAtlasSize - Inverse size of the shadow map atlas (from EveSpaceSceneDataPS). +// shadowMapAtlasEntryMinSizeLog2 - Minimum size of a shadow map atlas entry, in log2 (from EveSpaceSceneDataPS). +// shadowQuality - Current shadow quality setting in the application (from EveSpaceSceneDataPS, see SHADOW_QUALITY_FLAG_*). +// lightData - Data for the light source, obtained from LightBuffer. +// litPosition - Position in world space being lit. +// flags - Flags for filtering which lights to consider (LIGHT_FLAG_*). +bool GetDynamicLight( + ShadowData shadowData, + float inverseShadowMapAtlasSize, + uint shadowMapAtlasEntryMinSizeLog2, + uint shadowQuality, + PerLightData lightData, + float3 litPosition, + uint flags, + out ComputedDynamicLight computedDynamicLight ) +{ + computedDynamicLight.lightDirection = 0; + computedDynamicLight.distance = 0; + computedDynamicLight.lightColor = 0; + computedDynamicLight.roughnessIncrease = 0; + computedDynamicLight.radius = 0; + computedDynamicLight.innerRadius = 0; + + computedDynamicLight.lightDirection = lightData.position.xyz - litPosition; + float3 unnormalizedLightDirection = computedDynamicLight.lightDirection; + computedDynamicLight.distance = length( computedDynamicLight.lightDirection ); + computedDynamicLight.lightDirection /= computedDynamicLight.distance; + + float radius = lightData.position.w; + computedDynamicLight.radius = radius; + float innerRadius = f16tof32( asuint( lightData.color.w ) & 0xffff ); + computedDynamicLight.innerRadius = innerRadius; + uint lightFlags = asuint( lightData.color.w ); + uint profile = lightFlags >> 20; + bool gotShadowMap = ( lightFlags & LIGHT_FLAG_CASTS_SHADOWS ) != 0; + + float3 lightDir = float3( + f16tof32( asuint( lightData.direction.x ) & 0xffff ), + f16tof32( asuint( lightData.direction.x ) >> 16 ), + f16tof32( asuint( lightData.direction.y ) & 0xffff ) + ); + float outerCosAngle = f16tof32( asuint( lightData.direction.z ) & 0xffff ); + float innerCosAngle = f16tof32( asuint( lightData.direction.z ) >> 16 ); + float cosAngle = dot( lightDir, computedDynamicLight.lightDirection ); + + bool result = false; + [branch] + if( computedDynamicLight.distance < radius && ( lightFlags & flags ) != 0 ) + { + float pointLightFuzzyness = clamp( innerRadius / computedDynamicLight.distance, 0.0, 0.8 ); + + // fuzzFactor needs to be in the 4th power (or 2 powers stronger than roughness) + // so the fuzz doesn't overshadow the roughness of the material (if that makes sense) + float fuzzFactor = pow( pointLightFuzzyness, 4 ); + + float attenuation = 1; + + if( outerCosAngle > 0.0f ) + { + attenuation *= pow( LinStep( outerCosAngle, innerCosAngle, cosAngle ), 2 ); + } + if( profile > 0 ) + { + attenuation *= LightProfileArray.SampleLevel( LightProfileSampler, float3( cosAngle * -0.5 + 0.5, 0, profile - 1 ), 0 ); + } + + if( ( shadowQuality & ( SHADOW_QUALITY_FLAG_LOW | SHADOW_QUALITY_FLAG_HIGH ) ) != 0 && inverseShadowMapAtlasSize > 0. && gotShadowMap && attenuation > 0. ) + { + uint shadowMapScale = ( ( asuint( lightData.direction.w ) >> 2 ) & ( ( 1 << 10 ) - 1 ) ) << shadowMapAtlasEntryMinSizeLog2; + uint shadowMapOffsetX = ( ( asuint( lightData.direction.w ) >> 12 ) & ( ( 1 << 10 ) - 1 ) ) << shadowMapAtlasEntryMinSizeLog2; + uint shadowMapOffsetY = ( ( asuint( lightData.direction.w ) >> 22 ) & ( ( 1 << 10 ) - 1 ) ) << shadowMapAtlasEntryMinSizeLog2; + float projectionPlaneDistance = f16tof32( asuint( lightData.direction.y ) >> 16 ); + + float depth = 0.; + if( outerCosAngle > 0.0f ) + { + // spotlight + lightDir = -lightDir; + float3 up = abs( lightDir.y ) < .7 ? float3( 0., 1., 0. ) : float3( 1., 0., 0. ); + float3 side = normalize( cross( lightDir, up ) ); + up = cross( side, lightDir ); + float3x3 lightRotation = float3x3( side, up, lightDir ); + unnormalizedLightDirection = mul( lightRotation, -unnormalizedLightDirection ); + depth = unnormalizedLightDirection.z; + } + else + { + // pointlight + float3 absLightDir = abs( computedDynamicLight.lightDirection ); + absLightDir += shadowData.pcfJitter.offset; + float maxDir = max( max( absLightDir.x, absLightDir.y ), absLightDir.z ); + if( absLightDir.x == maxDir ) + { + depth = unnormalizedLightDirection.x; + unnormalizedLightDirection.xy = unnormalizedLightDirection.zy; + shadowMapOffsetX += 0; + } + else if( absLightDir.y == maxDir ) + { + depth = unnormalizedLightDirection.y; + unnormalizedLightDirection.xy = unnormalizedLightDirection.xz; + shadowMapOffsetX += shadowMapScale; + } + else + { + depth = unnormalizedLightDirection.z; + unnormalizedLightDirection.xy = unnormalizedLightDirection.yx; + shadowMapOffsetX += 2 * shadowMapScale; + } + unnormalizedLightDirection.y *= depth > 0. ? -1. : 1.; + shadowMapOffsetY += depth < 0. ? shadowMapScale : 0; + depth = abs( depth ); + } + + // perspective projection of z, assuming reverse z and far clip being the same as near clip divided by 1000 + const float b = 1. / 999.; + float m = radius * b; + unnormalizedLightDirection.z = -b + m / depth; + + // perspective projection of xy and flipping image + unnormalizedLightDirection.xy *= ( projectionPlaneDistance / depth ); + unnormalizedLightDirection.y *= -1.; + + // margin scale and changing value range from [-1, 1] to [0, 1] + const float margin = 8.; + float marginScale = .5 - ( margin / shadowMapScale ); + unnormalizedLightDirection.xy = unnormalizedLightDirection.xy * marginScale + .5.xx; + + // coordinate on atlas + unnormalizedLightDirection.xy = unnormalizedLightDirection.xy * float( shadowMapScale ) + float2( shadowMapOffsetX, shadowMapOffsetY ); + unnormalizedLightDirection.xy *= inverseShadowMapAtlasSize; + + float visibility = _PCF( shadowData.pcfJitter, ShadowMapAtlas, ShadowMapAtlasSampler, unnormalizedLightDirection.z, unnormalizedLightDirection.xy ); + + attenuation *= visibility; + } + + if( ( shadowQuality & SHADOW_QUALITY_FLAG_RAYTRACED ) != 0 && gotShadowMap && attenuation > 0. ) + { + uint shadowMask = ( ( asuint( lightData.direction.w ) ) & ( ( 1 << 16 ) - 1 ) ); + int shadow = shadowData.raytracedMask & shadowMask; + attenuation *= shadow != 0 ? 0. : 1.; + } + + computedDynamicLight.lightColor = lightData.color.rgb * attenuation; // innerRadius now softens the core in GetBoundedAttenuation; (1-fuzz) dimming dropped to avoid double-counting source size (fuzz still drives roughnessIncrease) + computedDynamicLight.roughnessIncrease = fuzzFactor; + result = true; + } + return result; +} + +// Computes the lighting contribution of a single light source at a given position in world space. +// Returns true if the light contributes to the lighting at the given position (based on distance and filters), false otherwise. +// The lighting data is returned in the computedDynamicLight parameter. +// Parameters: +// shadowData - Shadow data for the current pixel, including PCF jitter and raytraced mask. Normally GetDynamicLight is called in a loop over all lights, +// and this data is computed once per pixel and passed to each call to GetDynamicLight. +// index - Index of the light in LightBuffer to compute lighting for. +// litPosition - Position in world space being lit. +// perFramePS - Per-scene pixel shader data (from EveSpaceSceneDataPS). +// flags - Flags for filtering which lights to consider (LIGHT_FLAG_*). +bool GetDynamicLight( ShadowData shadowData, uint index, float3 litPosition, EveSpaceSceneDataPS perFramePS, uint flags, out ComputedDynamicLight computedDynamicLight ) +{ + PerLightData lightData = LightBuffer[index]; + float inverseShadowMapAtlasSize = asfloat( perFramePS.MiscData2.z ); + uint shadowMapAtlasEntryMinSizeLog2 = asuint( perFramePS.MiscData2.w ); + uint shadowQuality = asuint( perFramePS.ShadowMapSettings2.w ); + return GetDynamicLight( shadowData, inverseShadowMapAtlasSize, shadowMapAtlasEntryMinSizeLog2, shadowQuality, lightData, litPosition, flags, computedDynamicLight ); +} + + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh b/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh index 0a97167f8..c68b4130b 100644 --- a/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh +++ b/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh @@ -46,8 +46,8 @@ float RoughnessToMip( TextureCube envMap, float roughness ) { uint width; uint height; - uint mipLevels; - envMap.GetDimensions( width, height, mipLevels ); + uint mipLevels; + envMap.GetDimensions( 0, width, height, mipLevels ); return ( 1.0f - RoughnessToGloss( roughness ) ) * float( mipLevels - 1 ); } @@ -64,10 +64,4 @@ float3 SampleEnvironmentMap( TextureCube envMap, float3 dir, float roughness ) return envMap.SampleLevel( EveSpaceSceneEnvMapSampler, dir, RoughnessToMip( envMap, roughness ) ).rgb; } -// Sample EveSpaceSceneEnvMap with given direction and surface roughness -float3 SampleEnvironmentMap( float3 dir, float roughness ) -{ - return SampleEnvironmentMap( EveSpaceSceneEnvMap, dir, roughness ); -} - #endif \ No newline at end of file diff --git a/shaders/include/carbon/SpaceScene/PerSceneData.fxh b/shaders/include/carbon/SpaceScene/PerSceneData.fxh index ae3282747..3b022e8b1 100644 --- a/shaders/include/carbon/SpaceScene/PerSceneData.fxh +++ b/shaders/include/carbon/SpaceScene/PerSceneData.fxh @@ -48,6 +48,10 @@ struct EveSpaceSceneDataVS float4 MiscParams; // x - time, y - upscaling amount, zw - viewport size }; +static const uint SHADOW_QUALITY_FLAG_DISABLED = 1; +static const uint SHADOW_QUALITY_FLAG_LOW = 1 << 1; +static const uint SHADOW_QUALITY_FLAG_HIGH = 1 << 2; +static const uint SHADOW_QUALITY_FLAG_RAYTRACED = 1 << 3; // Per-scene (per-frame) constant buffer data for the pixel shader. struct EveSpaceSceneDataPS @@ -67,7 +71,7 @@ struct EveSpaceSceneDataPS float4 ViewportOffsetSize; // .xy - viewport offset, .zw - viewport size float4 RenderTargetData; // .xy - RT size in pixel, z - MSAA sample count (legacy, always 1 nowadays), w - debug float4 ShadowMapSettings; // .xyzw - various shadow filter parameters - float4 ShadowMapSettings2; // .xy - shadow camera range, .z - shadow lightness, .w - shadow quality + float4 ShadowMapSettings2; // .xy - shadow camera range, .z - shadow lightness, .w - shadow quality, uint (SHADOW_QUALITY_FLAG_*) float4 ProjectionData; // x - projection[3][2], y - projection[2][2], .zw = FoV float4 MiscData; // x - time, y - scenemiplodbias, z - upscaling amount, w - gamma brightness uint4 MiscData2; // x - frame counter, y - Jittering (bool), z - InverseShadowMapAtlasSize (float), w - ShadowMapAtlasEntryMinSizeLog2 (uint) diff --git a/shaders/include/carbon/System.fxh b/shaders/include/carbon/System.fxh index 7706d9c66..624090fcc 100644 --- a/shaders/include/carbon/System.fxh +++ b/shaders/include/carbon/System.fxh @@ -88,4 +88,20 @@ #define PEROBJECT_VS_STARTREGISTER vs, c16 #define PEROBJECT_PS_STARTREGISTER ps, c40 + +#if __INTELLISENSE__ + +// Intellisense stub definions for custom types used by the shader compiler. + +// DepthTexture2D is a custom type recognized by the shader compiler. It is used to declare depth textures in a platform-independent way. +#define DepthTexture2D Texture2D + +// Bindless handles are essentially uint values on all supported platforms, but the shader compiler recognizes them as custom types for additional semantics. +#define BindlessHandleTexture2D uint +#define BindlessHandleTexture3D uint +#define BindlessHandleTextureCube uint +#define BindlessHandleSampler uint + +#endif + #endif \ No newline at end of file From ce978c569b20c071878b2333ebf452d0c9324ea1 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 2 Oct 2026 13:17:02 +0000 Subject: [PATCH 07/83] Rename carbon shader include directory --- shaders/include/{carbon => Carbon}/Bindless.fxh | 0 shaders/include/{carbon => Carbon}/BoneTransforms.fxh | 0 shaders/include/{carbon => Carbon}/Intersections.fxh | 0 shaders/include/{carbon => Carbon}/Math.fxh | 0 shaders/include/{carbon => Carbon}/PackedTangents.fxh | 0 shaders/include/{carbon => Carbon}/ParticleAnnotations.fxh | 0 shaders/include/{carbon => Carbon}/SpaceScene/DepthMap.fxh | 0 shaders/include/{carbon => Carbon}/SpaceScene/DynamicLighting.fxh | 0 shaders/include/{carbon => Carbon}/SpaceScene/EnvironmentMap.fxh | 0 shaders/include/{carbon => Carbon}/SpaceScene/PerSceneData.fxh | 0 shaders/include/{carbon => Carbon}/SpaceScene/Volumetrics.fxh | 0 shaders/include/{carbon => Carbon}/System.fxh | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename shaders/include/{carbon => Carbon}/Bindless.fxh (100%) rename shaders/include/{carbon => Carbon}/BoneTransforms.fxh (100%) rename shaders/include/{carbon => Carbon}/Intersections.fxh (100%) rename shaders/include/{carbon => Carbon}/Math.fxh (100%) rename shaders/include/{carbon => Carbon}/PackedTangents.fxh (100%) rename shaders/include/{carbon => Carbon}/ParticleAnnotations.fxh (100%) rename shaders/include/{carbon => Carbon}/SpaceScene/DepthMap.fxh (100%) rename shaders/include/{carbon => Carbon}/SpaceScene/DynamicLighting.fxh (100%) rename shaders/include/{carbon => Carbon}/SpaceScene/EnvironmentMap.fxh (100%) rename shaders/include/{carbon => Carbon}/SpaceScene/PerSceneData.fxh (100%) rename shaders/include/{carbon => Carbon}/SpaceScene/Volumetrics.fxh (100%) rename shaders/include/{carbon => Carbon}/System.fxh (100%) diff --git a/shaders/include/carbon/Bindless.fxh b/shaders/include/Carbon/Bindless.fxh similarity index 100% rename from shaders/include/carbon/Bindless.fxh rename to shaders/include/Carbon/Bindless.fxh diff --git a/shaders/include/carbon/BoneTransforms.fxh b/shaders/include/Carbon/BoneTransforms.fxh similarity index 100% rename from shaders/include/carbon/BoneTransforms.fxh rename to shaders/include/Carbon/BoneTransforms.fxh diff --git a/shaders/include/carbon/Intersections.fxh b/shaders/include/Carbon/Intersections.fxh similarity index 100% rename from shaders/include/carbon/Intersections.fxh rename to shaders/include/Carbon/Intersections.fxh diff --git a/shaders/include/carbon/Math.fxh b/shaders/include/Carbon/Math.fxh similarity index 100% rename from shaders/include/carbon/Math.fxh rename to shaders/include/Carbon/Math.fxh diff --git a/shaders/include/carbon/PackedTangents.fxh b/shaders/include/Carbon/PackedTangents.fxh similarity index 100% rename from shaders/include/carbon/PackedTangents.fxh rename to shaders/include/Carbon/PackedTangents.fxh diff --git a/shaders/include/carbon/ParticleAnnotations.fxh b/shaders/include/Carbon/ParticleAnnotations.fxh similarity index 100% rename from shaders/include/carbon/ParticleAnnotations.fxh rename to shaders/include/Carbon/ParticleAnnotations.fxh diff --git a/shaders/include/carbon/SpaceScene/DepthMap.fxh b/shaders/include/Carbon/SpaceScene/DepthMap.fxh similarity index 100% rename from shaders/include/carbon/SpaceScene/DepthMap.fxh rename to shaders/include/Carbon/SpaceScene/DepthMap.fxh diff --git a/shaders/include/carbon/SpaceScene/DynamicLighting.fxh b/shaders/include/Carbon/SpaceScene/DynamicLighting.fxh similarity index 100% rename from shaders/include/carbon/SpaceScene/DynamicLighting.fxh rename to shaders/include/Carbon/SpaceScene/DynamicLighting.fxh diff --git a/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh b/shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh similarity index 100% rename from shaders/include/carbon/SpaceScene/EnvironmentMap.fxh rename to shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh diff --git a/shaders/include/carbon/SpaceScene/PerSceneData.fxh b/shaders/include/Carbon/SpaceScene/PerSceneData.fxh similarity index 100% rename from shaders/include/carbon/SpaceScene/PerSceneData.fxh rename to shaders/include/Carbon/SpaceScene/PerSceneData.fxh diff --git a/shaders/include/carbon/SpaceScene/Volumetrics.fxh b/shaders/include/Carbon/SpaceScene/Volumetrics.fxh similarity index 100% rename from shaders/include/carbon/SpaceScene/Volumetrics.fxh rename to shaders/include/Carbon/SpaceScene/Volumetrics.fxh diff --git a/shaders/include/carbon/System.fxh b/shaders/include/Carbon/System.fxh similarity index 100% rename from shaders/include/carbon/System.fxh rename to shaders/include/Carbon/System.fxh From 4be94b053d2f2224fcb67d1051e64fb8baf11e09 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 2 Oct 2026 13:22:55 +0000 Subject: [PATCH 08/83] Update path --- CMakeLists.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d26921750..dce401516 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,18 +132,18 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() set(_SHADER_SOURCES - shaders/include/carbon/SpaceScene/DepthMap.fxh - shaders/include/carbon/SpaceScene/DynamicLighting.fxh - shaders/include/carbon/SpaceScene/EnvironmentMap.fxh - shaders/include/carbon/SpaceScene/PerSceneData.fxh - shaders/include/carbon/SpaceScene/Volumetrics.fxh - shaders/include/carbon/Bindless.fxh - shaders/include/carbon/BoneTransforms.fxh - shaders/include/carbon/Intersections.fxh - shaders/include/carbon/Math.fxh - shaders/include/carbon/PackedTangents.fxh - shaders/include/carbon/ParticleAnnotations.fxh - shaders/include/carbon/System.fxh + shaders/include/Carbon/SpaceScene/DepthMap.fxh + shaders/include/Carbon/SpaceScene/DynamicLighting.fxh + shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh + shaders/include/Carbon/SpaceScene/PerSceneData.fxh + shaders/include/Carbon/SpaceScene/Volumetrics.fxh + shaders/include/Carbon/Bindless.fxh + shaders/include/Carbon/BoneTransforms.fxh + shaders/include/Carbon/Intersections.fxh + shaders/include/Carbon/Math.fxh + shaders/include/Carbon/PackedTangents.fxh + shaders/include/Carbon/ParticleAnnotations.fxh + shaders/include/Carbon/System.fxh ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) From fc6ec1c4d0632f5da40ffd78865fc8a6d1151da3 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 2 Oct 2026 15:00:33 +0000 Subject: [PATCH 09/83] More shaders --- CMakeLists.txt | 1 + shaders/include/Carbon/BoneTransforms.fxh | 2 + .../include/Carbon/SpaceScene/DepthMap.fxh | 2 + .../Carbon/SpaceScene/DynamicLighting.fxh | 2 + .../Carbon/SpaceScene/PerObjectData.fxh | 194 ++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/PerObjectData.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index dce401516..5d381b955 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/DepthMap.fxh shaders/include/Carbon/SpaceScene/DynamicLighting.fxh shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh + shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh shaders/include/Carbon/Bindless.fxh diff --git a/shaders/include/Carbon/BoneTransforms.fxh b/shaders/include/Carbon/BoneTransforms.fxh index f2b6feae0..7a948441f 100644 --- a/shaders/include/Carbon/BoneTransforms.fxh +++ b/shaders/include/Carbon/BoneTransforms.fxh @@ -1,3 +1,5 @@ +// Copyright © 2026 CCP ehf. + #ifndef CARBON_BONETRANSFORMS_FXH_ #define CARBON_BONETRANSFORMS_FXH_ diff --git a/shaders/include/Carbon/SpaceScene/DepthMap.fxh b/shaders/include/Carbon/SpaceScene/DepthMap.fxh index c802c914b..b2bcc1d95 100644 --- a/shaders/include/Carbon/SpaceScene/DepthMap.fxh +++ b/shaders/include/Carbon/SpaceScene/DepthMap.fxh @@ -1,3 +1,5 @@ +// Copyright © 2026 CCP ehf. + #ifndef CARBON_DEPTHMAP_FXH #define CARBON_DEPTHMAP_FXH diff --git a/shaders/include/Carbon/SpaceScene/DynamicLighting.fxh b/shaders/include/Carbon/SpaceScene/DynamicLighting.fxh index faf217c0b..3df0ea43f 100644 --- a/shaders/include/Carbon/SpaceScene/DynamicLighting.fxh +++ b/shaders/include/Carbon/SpaceScene/DynamicLighting.fxh @@ -1,3 +1,5 @@ +// Copyright © 2026 CCP ehf. + #ifndef CARBON_DYNAMICLIGHTING_FXH #define CARBON_DYNAMICLIGHTING_FXH diff --git a/shaders/include/Carbon/SpaceScene/PerObjectData.fxh b/shaders/include/Carbon/SpaceScene/PerObjectData.fxh new file mode 100644 index 000000000..f36d9bdde --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/PerObjectData.fxh @@ -0,0 +1,194 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_PEROBJECTDATA_FXH +#define CARBON_PEROBJECTDATA_FXH + +#include "../BoneTransforms.fxh" + +// Constant buffer format for per-object data for space scene objects. This data is provided by the engine to the vertex shader stage. +struct EveSpaceObjectDataVS +{ + // world transform of this object + float4x4 WorldMat; + // world transform of this object in the previous frame + float4x4 WorldMatLast; + // inverse world transform of this object + float4x4 InvWorldMat; + // additional ship-data ( components: .x = boosterGain, .y = activation, .z = unused, .w = boundingsphere radius ) + float4 Shipdata; + // clip data for disolve fx ( components: .xyz = center, .w = signed squared size ) + float4 Clipdata1; + // bounding ellipsoid data + float4 EllipsoidRadii; + float4 EllipsoidCenter; + // custom mask data for pattern projection + float4x4 CustomMaskMatrix[2]; + // additional custommap-data ( components: .x = layerCount, components: .y = isMirrored, ) + float4 CustomMaskData[2]; + + uint4 BoneOffsets; // .x = current frame offset, .y = previous frame offset + uint4 MorphTarget; // .x = VertexDataOffset, .y = AnimationDataOffset, .z = MorphTargetsCount, .w = BakedVertexDataOffset + + float4 CustomData; +}; + +// Constant buffer format for per-object data for space scene objects. This data is provided by the engine to the pixel shader stage. +struct EveSpaceObjectDataPS +{ + // world transform of this object + float4x4 WorldMat; + // world transform of this object in the previous frame + float4x4 WorldMatLast; + // inverse world transform of this object + float4x4 InvWorldMat; + + // additional ship-data ( components: .x = boosterGain, .y = activation, .z = dirt level, .w = boundingsphere radius ) + float4 Shipdata; + // clip data for disolve fx ( components: .xyz = center, .w = signed squared size ) + float4 Clipdata1; + // misc data ( .x = signed squared clip sphere 2 radius, .y = impact data offset, .z = clip sphere 2 factor, .w = clip sphere factor) + float4 Miscdata; + // SH lighting coefficients + float4 ShLighting[7]; + // custom mask material ids ( components: .x = material1, .y = material2, .z = material3, .w = material4 ) + float4 CustomMaskMaterialIDs[2]; + // custom mask targets ( components: .x = isTargetMtl1, .y = isTargetMtl2, .z = isTargetMtl3, .w = isTargetMtl4 ) + float4 CustomMaskTargets[2]; + float4 CustomMaskClamps; + float4 ScreenSize; + float4 CustomData; +}; + +// Unified buffer per-object data for space scene objects. Used by shared instanced rendering and read from InstancedPerObjectBuffer. +// It is also possible to construct this data from the VS and PS per-object data structures, but some fields will be zeroed out. +// See CreateEveSpaceObjectData() functions below. +struct EveSpaceObjectData +{ + // world transform of this object + float4x4 WorldMat; + // world transform of this object in the previous frame + float4x4 WorldMatLast; + // inverse world transform of this object + float4x4 InvWorldMat; + // additional ship-data ( components: .x = boosterGain, .y = activation, .z = unused, .w = boundingsphere radius ) + float4 Shipdata; + // clip data for disolve fx ( components: .xyz = center, .w = signed squared size ) + float4 Clipdata1; + // misc data ( .x = signed squared clip sphere 2 radius, .y = impact data offset, .z = clip sphere 2 factor, .w = clip sphere factor) + float4 Miscdata; + + // bounding ellipsoid data + float4 EllipsoidRadii; + float4 EllipsoidCenter; + + // custom mask data + float4x4 CustomMaskMatrix[2]; + // additional custommap-data ( components: .x = layerCount, components: .y = isMirrored, ) + float4 CustomMaskData[2]; + // custom mask material ids ( components: .x = material1, .y = material2, .z = material3, .w = material4 ) + float4 CustomMaskMaterialIDs[2]; + // custom mask targets ( components: .x = isTargetMtl1, .y = isTargetMtl2, .z = isTargetMtl3, .w = isTargetMtl4 ) + float4 CustomMaskTargets[2]; + float4 CustomMaskClamps; + + // .x = current frame offset, .y = previous frame offset + uint4 BoneOffsets; + // .x - tactical camera object type, .y - tactical view transparency type + float4 CustomData; + // SH lighting coefficients + float4 ShLighting[7]; +}; + + +EveSpaceObjectData CreateEveSpaceObjectData( EveSpaceObjectDataVS vsData ) +{ + EveSpaceObjectData perObjectData; + perObjectData.WorldMat = vsData.WorldMat; + perObjectData.WorldMatLast = vsData.WorldMatLast; + perObjectData.InvWorldMat = vsData.InvWorldMat; + perObjectData.Shipdata = vsData.Shipdata; + perObjectData.Clipdata1 = vsData.Clipdata1; + perObjectData.Miscdata = 0; + perObjectData.EllipsoidRadii = vsData.EllipsoidRadii; + perObjectData.EllipsoidCenter = vsData.EllipsoidCenter; + perObjectData.CustomMaskMatrix[0] = vsData.CustomMaskMatrix[0]; + perObjectData.CustomMaskMatrix[1] = vsData.CustomMaskMatrix[1]; + perObjectData.CustomMaskData[0] = vsData.CustomMaskData[0]; + perObjectData.CustomMaskData[1] = vsData.CustomMaskData[1]; + perObjectData.CustomMaskMaterialIDs[0] = 0; + perObjectData.CustomMaskMaterialIDs[1] = 0; + perObjectData.CustomMaskTargets[0] = 0; + perObjectData.CustomMaskTargets[1] = 0; + perObjectData.CustomMaskClamps = 0; + perObjectData.BoneOffsets = vsData.BoneOffsets; + perObjectData.CustomData = vsData.CustomData; + perObjectData.ShLighting[0] = 0; + perObjectData.ShLighting[1] = 0; + perObjectData.ShLighting[2] = 0; + perObjectData.ShLighting[3] = 0; + perObjectData.ShLighting[4] = 0; + perObjectData.ShLighting[5] = 0; + perObjectData.ShLighting[6] = 0; + return perObjectData; +} + +EveSpaceObjectData CreateEveSpaceObjectData( EveSpaceObjectDataPS psData ) +{ + EveSpaceObjectData perObjectData; + perObjectData.WorldMat = psData.WorldMat; + perObjectData.WorldMatLast = psData.WorldMatLast; + perObjectData.InvWorldMat = psData.InvWorldMat; + perObjectData.Shipdata = psData.Shipdata; + perObjectData.Clipdata1 = psData.Clipdata1; + perObjectData.Miscdata = psData.Miscdata; + perObjectData.EllipsoidRadii = 0; + perObjectData.EllipsoidCenter = 0; + perObjectData.CustomMaskMatrix[0] = float4x4( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + perObjectData.CustomMaskMatrix[1] = float4x4( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + perObjectData.CustomMaskData[0] = 0; + perObjectData.CustomMaskData[1] = 0; + perObjectData.CustomMaskMaterialIDs[0] = psData.CustomMaskMaterialIDs[0]; + perObjectData.CustomMaskMaterialIDs[1] = psData.CustomMaskMaterialIDs[1]; + perObjectData.CustomMaskTargets[0] = psData.CustomMaskTargets[0]; + perObjectData.CustomMaskTargets[1] = psData.CustomMaskTargets[1]; + perObjectData.CustomMaskClamps = psData.CustomMaskClamps; + perObjectData.BoneOffsets = 0; + perObjectData.CustomData = psData.CustomData; + + perObjectData.ShLighting[0] = psData.ShLighting[0]; + perObjectData.ShLighting[1] = psData.ShLighting[1]; + perObjectData.ShLighting[2] = psData.ShLighting[2]; + perObjectData.ShLighting[3] = psData.ShLighting[3]; + perObjectData.ShLighting[4] = psData.ShLighting[4]; + perObjectData.ShLighting[5] = psData.ShLighting[5]; + perObjectData.ShLighting[6] = psData.ShLighting[6]; + // intentionally skipping ScreenSize as I don't think it's used + return perObjectData; +} + +// This buffer contains per-object data for shared instanced rendering. +StructuredBuffer InstancedPerObjectBuffer ; + + +float4x4 GetBoneMatrix( EveSpaceObjectData perObjectData, int boneIndex ) +{ + return GetBoneTransform( perObjectData.BoneOffsets.x + boneIndex ); +} + +float4x4 GetLastBoneMatrix( EveSpaceObjectData perObjectData, int boneIndex ) +{ + return GetBoneTransform( perObjectData.BoneOffsets.y + boneIndex ); +} + +float4x4 GetBoneMatrix( EveSpaceObjectDataVS perObjectData, int boneIndex ) +{ + return GetBoneTransform( perObjectData.BoneOffsets.x + boneIndex ); +} + +float4x4 GetLastBoneMatrix( EveSpaceObjectDataVS perObjectData, int boneIndex ) +{ + return GetBoneTransform( perObjectData.BoneOffsets.y + boneIndex ); +} + + +#endif \ No newline at end of file From 9f20d8fa1d741a170dd62c1f627c1159458dc344 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 5 Oct 2026 10:35:20 +0000 Subject: [PATCH 10/83] Booster shader headers --- CMakeLists.txt | 3 ++ .../SpaceScene/BehaviorGroupBooster.fxh | 23 ++++++++ .../Carbon/SpaceScene/EveBoosterSet.fxh | 49 +++++++++++++++++ .../Carbon/SpaceScene/EveChildBoosterSet.fxh | 54 +++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d381b955..d57b5b524 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,9 +132,12 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() set(_SHADER_SOURCES + shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh shaders/include/Carbon/SpaceScene/DepthMap.fxh shaders/include/Carbon/SpaceScene/DynamicLighting.fxh shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh + shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh + shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh diff --git a/shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh b/shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh new file mode 100644 index 000000000..64e54e5c8 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh @@ -0,0 +1,23 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_BEHAVIORGROUPBOOSTER_FXH +#define CARBON_BEHAVIORGROUPBOOSTER_FXH + + +// Data passed from the engine to the vertex shader stage for BehaviourGroupBooster draw calls. +struct BehaviourGroupBoosterVertexInput +{ + // Vertex position in local instance space + float3 position : POSITION; + // UV coordinates + float2 texCoord : TEXCOORD0; + // Owner agent position (xyz) and scale (w) + float4 agentPos : TEXCOORD1; + // Owner agent rotation quaternion + float4 agentRot : TEXCOORD2; + // Booster data: x=intensity, y= per agent random number (0 to 1), z=atlasIndex0, w=atlasindex1 + float4 boosterData : TEXCOORD3; +}; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh b/shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh new file mode 100644 index 000000000..990832fa9 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh @@ -0,0 +1,49 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVEBOOSTERSET_FXH +#define CARBON_EVEBOOSTERSET_FXH + +// Data passed from the engine to the vertex shader stage for EveBoosterSet draw calls. +struct EveBoosterSetVertexInput +{ + // Vertex position in local instance space + float3 position : POSITION; + // UV coordinates; only filled when shader quality is set to low, for "star" shaped boosters + float2 texCoord : TEXCOORD0; + // 4x4 matrix that transforms the booster from local instance space to object space + float4 row1 : TEXCOORD1; + float4 row2 : TEXCOORD2; + float4 row3 : TEXCOORD3; + float4 row4 : TEXCOORD4; + // Custom values passed from SOF (no particular semantics, but can be used for various purposes in the shader) + float4 functionality : TEXCOORD5; + // Per booster instance random number from 0 to 1 used for offsetting booster animations + float wavePhase : TEXCOORD6; + // Texture atlas indices as floats, passed from SOF + float2 atlasIndex : TEXCOORD7; +}; + + +// Constant buffer format for per-object data for EveBoosterSet. This data is provided by the engine to the vertex shader stage. +struct EveBoosterSetDataVS +{ + // World matrix of the booster's owner ship + float4x4 WorldMat; + // Additional ship-data ( components: .x = boosterGain, .y = speed, .z = maxSize, .w = unused ) + float4 Shipdata; + // Trail spline data + float4 TrailsControlPositions[5]; + float4 TrailsControlNormals[5]; +}; + + +// Constant buffer format for per-object data for EveBoosterSet. This data is provided by the engine to the pixel shader stage. +struct EveBoosterSetDataPS +{ + // Additional ship-data ( components: .x = boosterGain, .y = trailIntensity, .z = warpStrength, .w = unused ) + float4 Shipdata; +}; + + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh b/shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh new file mode 100644 index 000000000..235bcd3dd --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh @@ -0,0 +1,54 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVECHILDBOOSTERSET_FXH +#define CARBON_EVECHILDBOOSTERSET_FXH + + +// Data passed from the engine to the vertex shader stage for EveChildBoosterSet draw calls. +struct EveChildBoosterSetVertexInput +{ + // Vertex position in local instance space + float3 position : POSITION; +}; + + +// Data passed from the engine to the vertex shader stage for EveChildBoosterSet draw calls. +struct EveChildBoosterSetInstanceData +{ + // 4x3 matrix that transforms the booster from local instance space to object space + float4x3 transform; + // Booster intensity + float intensity; + // Per booster instance random number from 0 to 1 used for offsetting booster animations + float wavePhase; + // Texture atlas indices, passed from SOF + uint atlasIndex0; + uint atlasIndex1; +}; + +StructuredBuffer ChildBoosterSetInstances ; + + +// Constant buffer format for per-object data for EveChildBoosterSet. This data is provided by the engine to the vertex shader stage. +struct EveChildBoosterSetDataVS +{ + // World matrix of the booster's owner ship + float4x4 WorldMat; + float _padding0; + float _padding1; + // Booster size at maximum intensity (used for scaling the booster in the shader) + float maxBoosterSize; + // Offset into the ChildBoosterSetInstances structured buffer for this booster set's instances + uint instanceOffset; +}; + + +// Constant buffer format for per-object data for EveChildBoosterSet. This data is provided by the engine to the pixel shader stage. +struct EveChildBoosterSetDataPS +{ + // Additional ship-data ( components: .x = unused, .y = unused, .z = warpStrength, .w = unused ) + float4 Shipdata; +}; + + +#endif \ No newline at end of file From efe911b5a9436737337630bd98af852acecf03d2 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 5 Oct 2026 10:59:38 +0000 Subject: [PATCH 11/83] Decal header --- CMakeLists.txt | 1 + .../Carbon/SpaceScene/EveSpaceObjectDecal.fxh | 108 ++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index d57b5b524..079af1ed1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,6 +138,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh + shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh diff --git a/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh b/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh new file mode 100644 index 000000000..f856aa356 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh @@ -0,0 +1,108 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVESPACEOBJECTDECAL_FXH +#define CARBON_EVESPACEOBJECTDECAL_FXH + +#include "PerObjectData.fxh" +#include "../Math.fxh" + + +// Data passed from the engine to the vertex shader stage for EveSpaceObjectDecal draw calls. +struct EveSpaceObjectDecalDataVS +{ + // World transform of this decal's parent + float4x4 WorldMat; + // Inverse world transform of this decal's parent + float4x4 InvWorldMat; + // Decal projection to parent space (or to local bone) transform + float4x4 DecalMatrix; + // Inverse decal projection to parent space transform + float4x4 InvDecalMatrix; + // Transform from bone space to parent space + float4x4 ParentBoneMatrix; + // Inverse transform from parent space to bone space + float4x4 InvParentBoneMatrix; +}; + + +// Data passed from the engine to the pixel shader stage for EveSpaceObjectDecal draw calls. +struct EveSpaceObjectDecalDataPS +{ + // Parent ship's display data ( components: .x = killcounter, .yzw = unused ) + float4 DisplayData; + // Additional ship-data ( components: .x = boosterGain, .y = activation, .z = dirt, .w = boundingsphere radius ) + float4 Shipdata; + // Clip data for disolve fx ( components: .xyz = center, .w = signed size ) + float4 Clipdata1; + // Misc data ( components: .x = signed square of clip radius 2, .yzw = unused ) + float4 Miscdata; + // SH lighting coefficients + float4 ShLighting[7]; +}; + + + +EveSpaceObjectData CreateEveSpaceObjectData( EveSpaceObjectDecalDataVS perObjectData ) +{ + EveSpaceObjectData pod; + pod.WorldMat = perObjectData.WorldMat; + pod.WorldMatLast = (float4x4)0; + pod.BoneOffsets = (uint4)0; + + pod.Shipdata = (float4)0; + pod.Clipdata1 = (float4)0; + pod.Miscdata = (float4)0; + pod.EllipsoidRadii = (float4)0; + pod.EllipsoidCenter = (float4)0; + pod.CustomMaskMatrix[0] = IDENTITY_MATRIX; + pod.CustomMaskMatrix[1] = IDENTITY_MATRIX; + pod.CustomMaskData[0] = (float4)0; + pod.CustomMaskData[1] = (float4)0; + pod.CustomMaskMaterialIDs[0] = (float4)0; + pod.CustomMaskMaterialIDs[1] = (float4)0; + pod.CustomMaskTargets[0] = (float4)0; + pod.CustomMaskTargets[1] = (float4)0; + pod.CustomMaskClamps = (float4)0; + pod.CustomData = (float4)0; + // SH lighting coefficients + for( int i = 0; i < 7; ++i ) + { + pod.ShLighting[i] = 0; + } + return pod; +} + + +EveSpaceObjectData CreateEveSpaceObjectData( EveSpaceObjectDecalDataPS perObjectData ) +{ + EveSpaceObjectData pod; + pod.WorldMat = (float4x4)0; + pod.WorldMatLast = (float4x4)0; + pod.BoneOffsets = (uint4)0; + + pod.Shipdata = perObjectData.Shipdata; + pod.Clipdata1 = perObjectData.Clipdata1; + pod.Miscdata = perObjectData.Miscdata; + pod.EllipsoidRadii = (float4)0; + pod.EllipsoidCenter = (float4)0; + pod.CustomMaskMatrix[0] = IDENTITY_MATRIX; + pod.CustomMaskMatrix[1] = IDENTITY_MATRIX; + pod.CustomMaskData[0] = (float4)0; + pod.CustomMaskData[1] = (float4)0; + pod.CustomMaskMaterialIDs[0] = (float4)0; + pod.CustomMaskMaterialIDs[1] = (float4)0; + pod.CustomMaskTargets[0] = (float4)0; + pod.CustomMaskTargets[1] = (float4)0; + pod.CustomMaskClamps = (float4)0; + pod.CustomData = (float4)0; + // SH lighting coefficients + for( int i = 0; i < 7; ++i ) + { + pod.ShLighting[i] = perObjectData.ShLighting[i]; + } + return pod; +} + + + +#endif \ No newline at end of file From 819d2044253af8109490ca68ce33927d71d2154b Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 5 Oct 2026 15:40:21 +0000 Subject: [PATCH 12/83] More shader includes --- CMakeLists.txt | 6 +++ shaders/include/Carbon/Intersections.fxh | 8 ++-- .../Carbon/SpaceScene/EveBannerSet.fxh | 22 ++++++++++ .../Carbon/SpaceScene/EveChildBulletStorm.fxh | 34 ++++++++++++++++ .../include/Carbon/SpaceScene/EveHazeSet.fxh | 28 +++++++++++++ .../include/Carbon/SpaceScene/EvePlaneSet.fxh | 32 +++++++++++++++ .../Carbon/SpaceScene/EveSpotlightSet.fxh | 40 +++++++++++++++++++ .../Carbon/SpaceScene/EveSpriteSet.fxh | 26 ++++++++++++ 8 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 shaders/include/Carbon/SpaceScene/EveBannerSet.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveHazeSet.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 079af1ed1..57cf56201 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,9 +136,15 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/DepthMap.fxh shaders/include/Carbon/SpaceScene/DynamicLighting.fxh shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh + shaders/include/Carbon/SpaceScene/EveBannerSet.fxh shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh + shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh + shaders/include/Carbon/SpaceScene/EveHazeSet.fxh + shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh + shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh + shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh diff --git a/shaders/include/Carbon/Intersections.fxh b/shaders/include/Carbon/Intersections.fxh index 8b7c049dd..151d02196 100644 --- a/shaders/include/Carbon/Intersections.fxh +++ b/shaders/include/Carbon/Intersections.fxh @@ -44,8 +44,8 @@ float GetDistanceToPlane( Plane plane, Ray ray ) plane.normal = -plane.normal; } - const float FLT_EPSILON = 0.0000001; - if( d >= FLT_EPSILON ) + const float epsilon = 0.0000001; + if( d >= epsilon ) { float3 rayToPlanePoint = plane.planePoint - ray.origin; @@ -171,9 +171,9 @@ bool PointInCone( Ray ray, float t, Cone cone ) float3 pointInConeSpace = ray.origin + t * ray.dir - cone.tip; float cone_dist = dot( pointInConeSpace, cone.axis ); - const float FLT_EPSILON = 0.0000001; + const float epsilon = 0.0000001; - if( cone.tipOffset - cone_dist > 0 || cone_dist > cone.height + FLT_EPSILON ) + if( cone.tipOffset - cone_dist > 0 || cone_dist > cone.height + epsilon ) { return false; } diff --git a/shaders/include/Carbon/SpaceScene/EveBannerSet.fxh b/shaders/include/Carbon/SpaceScene/EveBannerSet.fxh new file mode 100644 index 000000000..7a7b1bd4f --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveBannerSet.fxh @@ -0,0 +1,22 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVEBANNERSET_FXH +#define CARBON_EVEBANNERSET_FXH + + +// Data passed from the engine to the vertex shader stage for EveBannerSet draw calls. +struct EveBannerSetVertexInput +{ + // Vertex position in local space + float3 position : POSITION; + // Vertex normal in local space + float3 normal : NORMAL; + // UV coordinates + float2 texCoord : TEXCOORD; + // W component contains bone index for skinning, XYZ components are unused + int4 indices : BLENDINDICES; +}; + +// EveBannerSet uses the same per-object data layout as other space objects. See PerObjectData.fxh + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh b/shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh new file mode 100644 index 000000000..dfccfa60a --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh @@ -0,0 +1,34 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVECHILDBULLETSTORM_FXH +#define CARBON_EVECHILDBULLETSTORM_FXH + + +// Data passed from the engine to the vertex shader stage for EveChildBulletStorm draw calls. +struct EveChildBulletStormVertexInput +{ + // Vertex index of the corner of the quad, from 0 to 3 + float cornerID : TEXCOORD0; + // Bullet position in object space + float3 positionOS : TEXCOORD1; + // Bullet direction in object space + float3 directionOS : TEXCOORD2; + // XYZ - three independent random values per bullet (from 0 to 1), W - part ID + float4 data : TEXCOORD3; +}; + + +// Data passed from the engine to the vertex shader stage for EveChildBulletStorm draw calls. +struct EveChildBulletStormDataVS +{ + // World transform matrix + float4x4 WorldMatrix; + // Target information: X - number of targets (for TargetPositionAndSize), Y - effect range, Z - clip sphere radius, W - bullet speed + float4 TargetPositionInfo; + // Up to 10 target positions and sizes (XYZ = position, W = size) + float4 TargetPositionAndSize[10]; +}; + + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveHazeSet.fxh b/shaders/include/Carbon/SpaceScene/EveHazeSet.fxh new file mode 100644 index 000000000..76136241a --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveHazeSet.fxh @@ -0,0 +1,28 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVEHAZESET_FXH +#define CARBON_EVEHAZESET_FXH + + +// Data passed from the engine to the vertex shader stage for EveHazeSet draw calls. +struct EveHazeSetVertexInput +{ + // 3x4 matrix that transforms the haze from local instance space to object space + float4 transform1 : TEXCOORD0; + float4 transform2 : TEXCOORD1; + float4 transform3 : TEXCOORD2; + // 3x4 matrix that transforms the haze from object space to local instance space + float4 invTransform1 : TEXCOORD3; + float4 invTransform2 : TEXCOORD4; + float4 invTransform3 : TEXCOORD5; + // X - haze falloff, Y - source size, Z - source brightness, W - saturation + float4 hazeData : TEXCOORD6; + // Color of the haze + float4 color : COLOR; + // X - vertex index (0-7), Y - skeleton bone index if the haze is attached to the bone + uint4 index : TEXCOORD7; +}; + +// EveHazeSet uses the same per-object data layout as other space objects. See PerObjectData.fxh + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh b/shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh new file mode 100644 index 000000000..d99d75cfe --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh @@ -0,0 +1,32 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVEPLANESET_FXH +#define CARBON_EVEPLANESET_FXH + + +// Data passed from the engine to the vertex shader stage for EvePlaneSet draw calls. +struct EvePlaneSetVertexInput +{ + // 3x4 matrix that transforms the plane from local instance space to world space + float4 transform1 : TEXCOORD0; + float4 transform2 : TEXCOORD1; + float4 transform3 : TEXCOORD2; + // Color of the plane + float4 color : COLOR; + // UV layer 1 transform and scroll data (XY - scale, ZW - offset) + float4 layer1Transform : TEXCOORD3; + // UV layer 2 transform and scroll data (XY - scale, ZW - offset) + float4 layer2Transform : TEXCOORD4; + // UV layer 1 scroll data (XY - scroll speed, ZW - scroll offset) + float4 layer1Scroll : TEXCOORD5; + // UV layer 2 scroll data (XY - scroll speed, ZW - scroll offset) + float4 layer2Scroll : TEXCOORD6; + // Z - texture atlas index + uint4 index : TEXCOORD7; + // Plane blink data coming from SOF (X - blink rate, Y - blink phase, Z - duty cycle, W - blink mode) + float4 blinkData : TEXCOORD8; +}; + +// EvePlaneSet uses the quad renderer for rendering sprites, so shaders do not have access to per-object data. + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh b/shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh new file mode 100644 index 000000000..a371df02d --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh @@ -0,0 +1,40 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVESPOTLIGHTSET_FXH +#define CARBON_EVESPOTLIGHTSET_FXH + +// Data passed from the engine to the vertex shader stage for EveSpotlightSet cone geometry draw calls. +struct EveSpotlightSetConeVertexInput +{ + // Spotlight color and activation state (w - ship activation) + float4 color : COLOR0; + // 3x4 matrix that transforms the spotlight from local instance space to world space + float4 transform1 : TEXCOORD0; + float4 transform2 : TEXCOORD1; + float4 transform3 : TEXCOORD2; + // X - booster gain, Y - unused + float2 boosterGain : TEXCOORD3; + // Vertex index of the spotlight cone (0-3) + float index : TEXCOORD4; +}; + + +// Data passed from the engine to the vertex shader stage for EveSpotlightSet glow sprite draw calls. +struct EveSpotlightSetGlowVertexInput +{ + // 3x4 matrix that transforms the spotlight from local instance space to world space + float4 transform1 : TEXCOORD0; + float4 transform2 : TEXCOORD1; + float4 transform3 : TEXCOORD2; + // Spotlight sprite color and activation state (w - ship activation) + float4 spriteColor : COLOR0; + // Spotlight flare color (w - unused) + float4 flareColor : COLOR1; + // Sprite scale (XYZ) and boosterGain influence (W) + float4 scale : TEXCOORD3; + // Vertex index of the spotlight cone (0-3) + float index : TEXCOORD4; +}; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh b/shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh new file mode 100644 index 000000000..c5f7147ab --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh @@ -0,0 +1,26 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVESPRITESET_FXH +#define CARBON_EVESPRITESET_FXH + +// Data passed from the engine to the vertex shader stage for EveSpriteSet draw calls. +struct EveSpriteSetVertexInput +{ + // Sprite center position in world space + float3 position : POSITION; + // Sprite color + float4 color : COLOR; + // X - owner ship's activation strength, Y - sprite blink phase, Z - sprite blink rate, W - sprite minimum size + float4 texcoord0 : TEXCOORD0; + // X - sprite maximum size, Y - sprite falloff, Z, W - unused + float2 texcoord1 : TEXCOORD1; + // Warp mode color + float4 warpColor : COLOR1; + // Vertex index for sprite quad (0-3) + float index : TEXCOORD5; +}; + +// EveSpriteSet uses the quad renderer for rendering sprites, so shaders do not have access to per-object data. + + +#endif \ No newline at end of file From b1eff7708c9c580e38f41dfc7023fb49cd5cc574 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Tue, 6 Oct 2026 10:37:08 +0000 Subject: [PATCH 13/83] Lensflare shaders --- CMakeLists.txt | 3 + .../Lensflares/OccluderManagement.fx | 58 +++++++++++++++++++ .../Carbon/SpaceScene/EveLensflare.fxh | 35 +++++++++++ .../include/Carbon/SpaceScene/EveOccluder.fxh | 44 ++++++++++++++ 4 files changed, 140 insertions(+) create mode 100644 shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx create mode 100644 shaders/include/Carbon/SpaceScene/EveLensflare.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveOccluder.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 57cf56201..d4ec01bb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,6 +141,8 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh shaders/include/Carbon/SpaceScene/EveHazeSet.fxh + shaders/include/Carbon/SpaceScene/EveLensflare.fxh + shaders/include/Carbon/SpaceScene/EveOccluder.fxh shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh @@ -155,6 +157,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/PackedTangents.fxh shaders/include/Carbon/ParticleAnnotations.fxh shaders/include/Carbon/System.fxh + shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx b/shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx new file mode 100644 index 000000000..d0f90aecf --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx @@ -0,0 +1,58 @@ +float OcclusionBufferOffset ; +RWBuffer FlareOcclusionBuffer ; + +groupshared float occlusions[4]; + +[numthreads( 4, 1, 1 )] +void CopyCountersCS( uint3 groupIdx : SV_GroupID, uint3 threadIdx : SV_GroupThreadID ) +{ + uint flareOffset = groupIdx.x * 13; + uint occluderOffset = flareOffset + 5 + threadIdx.x * 2; + uint persistedOffset = flareOffset + 1 + threadIdx.x; + + uint total = FlareOcclusionBuffer[occluderOffset]; + if( total > 0 ) + { + uint unoccluded = FlareOcclusionBuffer[occluderOffset + 1]; + + float occlusion = float( unoccluded ) / float( total ) / 100.0; + FlareOcclusionBuffer[persistedOffset] = asuint( occlusion ); + + FlareOcclusionBuffer[occluderOffset] = 0; + FlareOcclusionBuffer[occluderOffset + 1] = 0; + occlusions[threadIdx.x] = occlusion; + } + else + { + occlusions[threadIdx.x] = asfloat( FlareOcclusionBuffer[persistedOffset] ); + } + + GroupMemoryBarrierWithGroupSync(); + + if( threadIdx.x == 0 ) + { + FlareOcclusionBuffer[flareOffset] = asuint( occlusions[0] * occlusions[1] * occlusions[2] * occlusions[3] ); + } +} + +[numthreads( 13, 1, 1 )] +void ClearCS( uint3 threadIdx : SV_GroupThreadID ) +{ + FlareOcclusionBuffer[asuint( OcclusionBufferOffset ) + threadIdx.x] = threadIdx.x < 5 ? asuint( 1.0 ) : 0; +} + +technique CopyCounters +{ + pass P0 + { + ComputeShader = compile cs_5_0 CopyCountersCS(); + } +} + +technique Clear +{ + pass P0 + { + ComputeShader = compile cs_5_0 ClearCS(); + } +} diff --git a/shaders/include/Carbon/SpaceScene/EveLensflare.fxh b/shaders/include/Carbon/SpaceScene/EveLensflare.fxh new file mode 100644 index 000000000..604b65dcb --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveLensflare.fxh @@ -0,0 +1,35 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVELENSFLARE_FXH +#define CARBON_EVELENSFLARE_FXH + + +struct EveLensflarePerObjectData +{ + // Direction towards the lens flare that owns the occluder; W - flare size scale + float4 LensflareFxDirectionScale; + // Offset into the occlusion buffer where the occlusion results for this lens flar are stored. + // X - foreground occlusion results, Y - background (planets, etc.) occlusion results, Z, W - unused + uint4 OcclusionIndices; +}; + +// The buffer containing occlusion results of occlusion queries for lens flares. Read values need to be cast to float using asfloat() to get the occlusion ratio in the range [0, 1]. +Buffer FlareOcclusionBuffer ; + +float GetLensFlareOcclusion( uint index ) +{ + return asfloat( FlareOcclusionBuffer[index] ); +} + +// Direction towards the lens flare that owns the occluder; W - flare size scale +// Can be used for querying lens flare position for shaders outside the lens flare system. +float4 LensflareFxDirectionScale ; + +// Stores offsets into the occlusion buffer where the occlusion results for a lens flare are stored. +// X - offset into the occlusion buffer for foreground occlusion results (cast to uint with asuint()) +// Y - offset into the occlusion buffer for background occlusion results (cast to uint with asuint()) +// Z, W - unused +float4 LensflareFxOccScale ; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveOccluder.fxh b/shaders/include/Carbon/SpaceScene/EveOccluder.fxh new file mode 100644 index 000000000..da7670992 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveOccluder.fxh @@ -0,0 +1,44 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVEOCCLUDER_FXH +#define CARBON_EVEOCCLUDER_FXH + +#include "DepthMap.fxh" +#include "Volumetrics.fxh" + +// Offset into the occlusion buffer where the occlusion results for this occluder are stored. +// Even though the variable is declared as a float, it is used as an integer value in the shader code (use asuint). +float OcclusionBufferOffset ; +// Scaling factor for fog occlusion to apply to the resulting occlusion value. +float OcclusionFogWeight ; +// Direction towards the lens flare that owns the occluder; W - flare size scale +float4 LensflareFxDirectionScale ; + + +// Destination buffer for writing occlusion results. Each occluder occupies two consecutive uint values in the buffer. +// The first value is the total occluder's shaded pixel count, and the second value is the unoccluded pixel count. +RWBuffer FlareOcclusionBuffer ; + +SamplerState _EveOccluderDepthMapSampler +{ + MinFilter = Point; + MagFilter = Point; + MipFilter = None; + AddressU = Mirror; + AddressV = Mirror; +}; + +// Records occlusion for a pixel with normalized screen space coordinates. +void EveOccluderRecordOcclusion( float2 pos ) +{ + uint bufferOffset = asuint( OcclusionBufferOffset ); + float depth = DepthMap.SampleLevel( _EveOccluderDepthMapSampler, pos, 0.0 ).r; + if( depth == 0 ) + { + float4 fog = EveSceneFogVolumeMap.SampleLevel( EveSceneFogVolumeMapSampler, float3( pos, 3 ), 0 ); + InterlockedAdd( FlareOcclusionBuffer[1 + bufferOffset], uint( 100 * ( 1 - min( fog.a * OcclusionFogWeight, 0.95 ) ) ) ); + } + InterlockedAdd( FlareOcclusionBuffer[bufferOffset], 1 ); +} + +#endif \ No newline at end of file From fcb6cd18d69f5285e29275939178f0e4dd86ce66 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Tue, 6 Oct 2026 14:27:48 +0000 Subject: [PATCH 14/83] More shaders --- CMakeLists.txt | 2 ++ .../Carbon/SpaceScene/EveTransform.fxh | 19 +++++++++++ shaders/include/Carbon/Tr2CurveLineSet.fxh | 33 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/EveTransform.fxh create mode 100644 shaders/include/Carbon/Tr2CurveLineSet.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index d4ec01bb0..895521d1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,6 +147,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh + shaders/include/Carbon/SpaceScene/EveTransform.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh @@ -157,6 +158,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/PackedTangents.fxh shaders/include/Carbon/ParticleAnnotations.fxh shaders/include/Carbon/System.fxh + shaders/include/Carbon/Tr2CurveLineSet.fxh shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx ) diff --git a/shaders/include/Carbon/SpaceScene/EveTransform.fxh b/shaders/include/Carbon/SpaceScene/EveTransform.fxh new file mode 100644 index 000000000..915ea3435 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveTransform.fxh @@ -0,0 +1,19 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVETRANSFORM_FXH +#define CARBON_EVETRANSFORM_FXH + + +// Data passed from the engine to the vertex shader stage for EveTransform draw calls. +struct EveTransformDataVS +{ + // World transform of this object + float4x4 WorldMat; + // World transform of this object in the previous frame + float4x4 WorldMatLast; + // Inverse world transform of this object + float4x4 InvWorldMat; +}; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/Tr2CurveLineSet.fxh b/shaders/include/Carbon/Tr2CurveLineSet.fxh new file mode 100644 index 000000000..b1b0793e2 --- /dev/null +++ b/shaders/include/Carbon/Tr2CurveLineSet.fxh @@ -0,0 +1,33 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_TR2CURVELINESET_FXH +#define CARBON_TR2CURVELINESET_FXH + +// Data passed from the engine to the vertex shader stage for Tr2CurveLineSet draw calls. +struct Tr2CurveLineSetVertexInput +{ + // Vertex position in local space + float3 position : POSITION; + // XYZ - offset to next/previous line segment, W - width (incl. -1.f to indicate direction) + float4 lineDir : TEXCOORD0; + // X - 0 or 1 for begin/end, Y - uniform scalar from 0 to 1 across length of line segment, Z - override color border, W - length of vert in uniform scalar + float4 beginEnd : TEXCOORD1; + // X - animation speed, Y - animation scale, Z - lineID + float3 animationData : TEXCOORD2; + // Offset to one after next/previous line segment + float3 nextLineDir : TEXCOORD3; + // Line color + float4 color : COLOR0; + // Override color + float4 overrideColor : COLOR1; + // Overlay color + float4 overlayColor : COLOR2; +}; + +// Data passed from the engine to any shader stage for Tr2CurveLineSet draw calls. +struct Tr2CurveLineSetData +{ + float4x4 WorldMat; +}; + +#endif \ No newline at end of file From 680489e9835c2b1a85c77a5c695181a6494526f3 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Wed, 7 Oct 2026 08:45:57 +0000 Subject: [PATCH 15/83] GPU particle shaders --- CMakeLists.txt | 10 + .../Space/SpecialFX/Particles/Gpu/Clear.fx | 64 +++++ .../Space/SpecialFX/Particles/Gpu/Emit.fx | 137 +++++++++++ .../Particles/Gpu/SetDrawParameters.fx | 24 ++ .../SpecialFX/Particles/Gpu/SetSortArgs.fx | 24 ++ .../Space/SpecialFX/Particles/Gpu/Sort.fx | 94 ++++++++ .../SpecialFX/Particles/Gpu/SortInner.fx | 90 ++++++++ .../Space/SpecialFX/Particles/Gpu/SortStep.fx | 52 +++++ .../Space/SpecialFX/Particles/Gpu/Update.fx | 218 ++++++++++++++++++ shaders/include/Carbon/Math.fxh | 28 +++ shaders/include/Carbon/RandomXOrShift.fxh | 38 +++ .../Carbon/SpaceScene/GpuParticles.fxh | 86 +++++++ 12 files changed, 865 insertions(+) create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx create mode 100644 shaders/include/Carbon/RandomXOrShift.fxh create mode 100644 shaders/include/Carbon/SpaceScene/GpuParticles.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 895521d1b..947c3925f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh shaders/include/Carbon/SpaceScene/EveTransform.fxh + shaders/include/Carbon/SpaceScene/GpuParticles.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh @@ -157,8 +158,17 @@ set(_SHADER_SOURCES shaders/include/Carbon/Math.fxh shaders/include/Carbon/PackedTangents.fxh shaders/include/Carbon/ParticleAnnotations.fxh + shaders/include/Carbon/RandomXOrShift.fxh shaders/include/Carbon/System.fxh shaders/include/Carbon/Tr2CurveLineSet.fxh + shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx ) diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx new file mode 100644 index 000000000..18524e524 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx @@ -0,0 +1,64 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/SpaceScene/GpuParticles.fxh" + +struct PerObjectVSData +{ + uint bufferSize; +} PerObjectVS; + +RWStructuredBuffer DeadBuffer; +RWBuffer ParticleCounters; +RWStructuredBuffer ParticleBuffer; + + +[numthreads( 1, 1, 1 )] +void ClearCounter() +{ + ParticleCounters[0] = 0; +} + +#define POPULATE_DEAD_DIM 16 + +[numthreads( POPULATE_DEAD_DIM, POPULATE_DEAD_DIM, 1 )] +void PopulateDead( uint groupIndex : SV_GroupIndex ) +{ + uint iterations = PerObjectVS.bufferSize / POPULATE_DEAD_DIM / POPULATE_DEAD_DIM; + for( uint i = 0; i < iterations; ++i ) + { + GpuParticleData particle = (GpuParticleData)0; + particle.age = -1; + ParticleBuffer[groupIndex + POPULATE_DEAD_DIM * POPULATE_DEAD_DIM * i] = particle; + int index; + InterlockedAdd( ParticleCounters[0], 1, index ); + DeadBuffer[index] = groupIndex + POPULATE_DEAD_DIM * POPULATE_DEAD_DIM * i; + } + + GroupMemoryBarrierWithGroupSync(); + + if( groupIndex == 0 ) + { + for( uint i = iterations * POPULATE_DEAD_DIM * POPULATE_DEAD_DIM; i < PerObjectVS.bufferSize; ++i ) + { + GpuParticleData particle = (GpuParticleData)0; + particle.age = -1; + ParticleBuffer[i] = particle; + int index; + InterlockedAdd( ParticleCounters[0], 1, index ); + DeadBuffer[index] = i; + } + } +} + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 ClearCounter(); + } + pass p1 + { + ComputeShader = compile cs_5_0 PopulateDead(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx new file mode 100644 index 000000000..d7c94669d --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx @@ -0,0 +1,137 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/System.fxh" +#include "../../../../../include/Carbon/Math.fxh" +#include "../../../../../include/Carbon/RandomXOrShift.fxh" +#include "../../../../../include/Carbon/SpaceScene/GpuParticles.fxh" + + +float3 GetRandomDirection( float3 direction, float angle, float innerAngle, float3 rands ) +{ + if( angle >= PI / 2 ) + { + angle = PI; + } + float3 dir = normalize( direction ); + + float phi = lerp( innerAngle, angle, rands.x ); + float theta = rands.y * 4 * PI; + + float4 q = QuaternionRotationYawPitchRoll( 0, phi, theta ); + float4 qp = float4( -q.xyz, q.w ); + float4 v = float4( 0, 0, 1, 0 ); + v = QuaternionMultiply( QuaternionMultiply( q, v ), qp ); + + float3 x = abs( dir.x ) > abs( dir.y ) ? float3( 0, 1, 0 ) : float3( 1, 0, 0 ); + float3 y = normalize( cross( dir, x ) ); + x = cross( dir, y ); + + return dir * v.z + x * v.x + y * v.y; +} + + +#define GROUP_X 16 +#define GROUP_Y 16 + +struct EmitterData +{ + float3 position; + uint count; + + float3 positionPrevious; + float radius; + + float3 direction; + float angle; + + float3 directionPrevious; + uint emitterSeed; // LO: emitter, HI: seed + + float3 velocity; + float minSpeed; + + float3 velocityPrevious; + float maxSpeed; + + float innerAngle; + float3 unused; +}; + +struct PerObjectVSData +{ + uint count; + uint3 padding; + // should be EmitterData data[(PLATFORM_MAX_CONSTANT_BUFFER_SIZE - 16)/sizeof(EmitterData)], but ShaderCompiler can't handle that +#if PLATFORM_MAX_CONSTANT_BUFFER_SIZE == 4096 + EmitterData data[36]; +#elif PLATFORM_MAX_CONSTANT_BUFFER_SIZE == 65536 + EmitterData data[585]; +#else +#error "Need to define proper length for the emitter CB" +#endif + +} PerObjectVS; + +RWStructuredBuffer ParticleBuffer; +RWBuffer ParticleCounters; +RWStructuredBuffer DeadBuffer; + +groupshared EmitterData g_emitter; + +[numthreads( GROUP_X, GROUP_Y, 1 )] +void Emit( uint3 grid : SV_GroupID, uint groupIndex : SV_GroupIndex, uint3 threadID : SV_GroupThreadID ) +{ + if( groupIndex == 0 ) + { + uint emitIndex = grid.x; + g_emitter = PerObjectVS.data[emitIndex]; + } + + GroupMemoryBarrierWithGroupSync(); + + uint rng_state = RandInit( groupIndex + ( g_emitter.emitterSeed >> 16 ) ); + + uint start = threadID.x + threadID.y * GROUP_X; + for( uint i = start; i < g_emitter.count; i += GROUP_X * GROUP_Y ) + { + int deadIndex; + InterlockedAdd( ParticleCounters[0], -1, deadIndex ); + --deadIndex; + + if( deadIndex >= 0 ) + { + float birthTime = RandFloat( rng_state ); + float3 velocityDirection = GetRandomDirection( + normalize( lerp( g_emitter.directionPrevious, g_emitter.direction, birthTime ) ), + g_emitter.angle, + g_emitter.innerAngle, + float3( RandFloat( rng_state ), RandFloat( rng_state ), RandFloat( rng_state ) ) ); + + uint index = DeadBuffer[deadIndex]; + GpuParticleData particle; + particle.position = lerp( g_emitter.positionPrevious, g_emitter.position, birthTime ); + particle.position += velocityDirection * g_emitter.radius; + particle.velocity = velocityDirection * + lerp( g_emitter.minSpeed, g_emitter.maxSpeed, RandFloat( rng_state ) ) + lerp( g_emitter.velocityPrevious, g_emitter.velocity, birthTime ); + particle.age = 0; + particle.emitterSeed = ( g_emitter.emitterSeed & 0xffff ) | ( Rand( rng_state ) << 16 ); + + + ParticleBuffer[index] = particle; + } + else + { + break; + } + } +} + + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 Emit(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx new file mode 100644 index 000000000..6807ffdd1 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx @@ -0,0 +1,24 @@ +// Copyright © 2026 CCP ehf. + + +RWBuffer DrawParameters; +Buffer ParticleCounters; + +[numthreads( 1, 1, 1 )] +void SetParameters() +{ + uint count = ParticleCounters[1]; + DrawParameters[0] = count * 6; + DrawParameters[1] = 1; + DrawParameters[2] = 0; + DrawParameters[3] = 0; +} + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 SetParameters(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx new file mode 100644 index 000000000..29a8e019d --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx @@ -0,0 +1,24 @@ +// Copyright © 2026 CCP ehf. + + +RWBuffer SortParameters; +Buffer ParticleCounters; + +[numthreads( 1, 1, 1 )] +void SetParameters() +{ + uint count = ParticleCounters[1]; + SortParameters[0] = ( ( max( count, (uint)1 ) - 1 ) >> 9 ) + 1; + SortParameters[1] = 1; + SortParameters[2] = 1; + SortParameters[3] = count; +} + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 SetParameters(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx new file mode 100644 index 000000000..f5b9001a3 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx @@ -0,0 +1,94 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/SpaceScene/GpuParticles.fxh" + +// Code based on https://github.com/GPUOpen-LibrariesAndSDKs/GPUParticles11 + +#define SORT_SIZE 512 + +#define HALF_SIZE 256 // (SORT_SIZE/2) +#define ITERATIONS 1 // (HALF_SIZE > 1024 ? HALF_SIZE/1024 : 1) +#define NUM_THREADS 256 // (HALF_SIZE/ITERATIONS) +#define INVERSION (16*2 + 8*3) + + +RWStructuredBuffer VisibleBuffer; +Buffer SortParameters; + + +groupshared GpuParticleVisibleData g_LDS[SORT_SIZE]; + + +[numthreads( NUM_THREADS, 1, 1 )] +void BitonicSortLDS( uint3 Gid : SV_GroupID, + uint3 DTid : SV_DispatchThreadID, + uint3 GTid : SV_GroupThreadID, + uint GI : SV_GroupIndex ) +{ + int GlobalBaseIndex = ( Gid.x * SORT_SIZE ) + GTid.x; + int LocalBaseIndex = GI; + + int g_NumElements = int( SortParameters[3] ); + if( g_NumElements == 0 ) + { + return; + } + + uint numElementsInThreadGroup = max( 0, min( SORT_SIZE, g_NumElements - int( Gid.x * SORT_SIZE ) ) ); + + // Load shared data + int i; + [unroll] + for( i = 0; i < 2 * ITERATIONS; ++i ) + { + if( GI + i * NUM_THREADS < numElementsInThreadGroup ) + g_LDS[LocalBaseIndex + i * NUM_THREADS] = VisibleBuffer[GlobalBaseIndex + i * NUM_THREADS]; + } + GroupMemoryBarrierWithGroupSync(); + + // Bitonic sort + for( uint nMergeSize = 2; nMergeSize <= SORT_SIZE; nMergeSize = nMergeSize * 2 ) + { + for( int nMergeSubSize = nMergeSize >> 1; nMergeSubSize > 0; nMergeSubSize = nMergeSubSize >> 1 ) + { + [unroll] + for( i = 0; i < ITERATIONS; ++i ) + { + int tmp_index = GI + NUM_THREADS * i; + int index_low = tmp_index & ( nMergeSubSize - 1 ); + int index_high = 2 * ( tmp_index - index_low ); + int index = index_high + index_low; + + uint nSwapElem = uint( nMergeSubSize ) == nMergeSize >> 1 ? index_high + ( 2 * nMergeSubSize - 1 ) - index_low : index_high + nMergeSubSize + index_low; + if( nSwapElem < numElementsInThreadGroup ) + { + GpuParticleVisibleData a = g_LDS[index]; + GpuParticleVisibleData b = g_LDS[nSwapElem]; + + if( a.depth > b.depth ) + { + g_LDS[index] = b; + g_LDS[nSwapElem] = a; + } + } + GroupMemoryBarrierWithGroupSync(); + } + } + } + + // Store shared data + [unroll] + for( i = 0; i < 2 * ITERATIONS; ++i ) + { + if( GI + i * NUM_THREADS < numElementsInThreadGroup ) + VisibleBuffer[GlobalBaseIndex + i * NUM_THREADS] = g_LDS[LocalBaseIndex + i * NUM_THREADS]; + } +} + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 BitonicSortLDS(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx new file mode 100644 index 000000000..8b13149a0 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx @@ -0,0 +1,90 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/SpaceScene/GpuParticles.fxh" + +// Code based on https://github.com/GPUOpen-LibrariesAndSDKs/GPUParticles11 + +#define SORT_SIZE 512 + +#define NUM_THREADS 256 // (SORT_SIZE/2) +#define INVERSION (16*2 + 8*3) + +RWStructuredBuffer VisibleBuffer; +Buffer SortParameters; + +groupshared GpuParticleVisibleData g_LDS[SORT_SIZE]; + + +[numthreads( NUM_THREADS, 1, 1 )] +void BitonicInnerSort( + uint3 Gid : SV_GroupID, + uint3 DTid : SV_DispatchThreadID, + uint3 GTid : SV_GroupThreadID, + uint GI : SV_GroupIndex ) +{ + int4 tgp; + + tgp.x = Gid.x * 256; + tgp.y = 0; + tgp.z = SortParameters[3]; + tgp.w = min( 512, max( 0, tgp.z - int( Gid.x * 512 ) ) ); + + int GlobalBaseIndex = tgp.y + tgp.x * 2 + GTid.x; + int LocalBaseIndex = GI; + int i; + + // Load shared data + if( GlobalBaseIndex < tgp.z ) + { + [unroll] + for( i = 0; i < 2; ++i ) + { + if( (int)GI + i * NUM_THREADS < tgp.w ) + g_LDS[LocalBaseIndex + i * NUM_THREADS] = VisibleBuffer[GlobalBaseIndex + i * NUM_THREADS]; + } + } + GroupMemoryBarrierWithGroupSync(); + + // sort threadgroup shared memory + for( int nMergeSubSize = SORT_SIZE >> 1; nMergeSubSize > 0; nMergeSubSize = nMergeSubSize >> 1 ) + { + int tmp_index = GI; + int index_low = tmp_index & ( nMergeSubSize - 1 ); + int index_high = 2 * ( tmp_index - index_low ); + int index = index_high + index_low; + + uint nSwapElem = index_high + nMergeSubSize + index_low; + + if( (int)nSwapElem < tgp.w ) + { + GpuParticleVisibleData a = g_LDS[index]; + GpuParticleVisibleData b = g_LDS[nSwapElem]; + + if( a.depth > b.depth ) + { + g_LDS[index] = b; + g_LDS[nSwapElem] = a; + } + } + GroupMemoryBarrierWithGroupSync(); + } + + // Store shared data + if( GlobalBaseIndex < tgp.z ) + { + [unroll] + for( i = 0; i < 2; ++i ) + { + if( (int)GI + i * NUM_THREADS < tgp.w ) + VisibleBuffer[GlobalBaseIndex + i * NUM_THREADS] = g_LDS[LocalBaseIndex + i * NUM_THREADS]; + } + } +} + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 BitonicInnerSort(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx new file mode 100644 index 000000000..d6aa03839 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx @@ -0,0 +1,52 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/SpaceScene/GpuParticles.fxh" + +// Code based on https://github.com/GPUOpen-LibrariesAndSDKs/GPUParticles11 + +RWStructuredBuffer VisibleBuffer; +Buffer SortParameters; + +struct PerObjectVSData +{ + int4 JobParams; +} PerObjectVS; + +[numthreads( 256, 1, 1 )] +void BitonicSortStep( uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID ) +{ + int4 tgp; + + tgp.x = Gid.x * 256; + tgp.y = 0; + tgp.z = SortParameters[3]; + tgp.w = min( 512, max( 0, tgp.z - (int)Gid.x * 512 ) ); + + uint localID = tgp.x + GTid.x; // calculate threadID within this sortable-array + + uint index_low = localID & ( PerObjectVS.JobParams.x - 1 ); + uint index_high = 2 * ( localID - index_low ); + + uint index = tgp.y + index_high + index_low; + uint nSwapElem = tgp.y + index_high + PerObjectVS.JobParams.y + PerObjectVS.JobParams.z * index_low; + + if( nSwapElem < uint( tgp.y + tgp.z ) ) + { + GpuParticleVisibleData a = VisibleBuffer[index]; + GpuParticleVisibleData b = VisibleBuffer[nSwapElem]; + + if( a.depth > b.depth ) + { + VisibleBuffer[index] = b; + VisibleBuffer[nSwapElem] = a; + } + } +} + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 BitonicSortStep(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx new file mode 100644 index 000000000..5ade62772 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx @@ -0,0 +1,218 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/Math.fxh" +#include "../../../../../include/Carbon/SpaceScene/GpuParticles.fxh" +#include "../../../../../include/Carbon/SpaceScene/PerSceneData.fxh" + + +#define GROUP_X 16 +#define GROUP_Y 16 + + +Texture3D NoiseMap +< + bool SasUiVisible = true; +>; + +SamplerState NoiseMapSampler +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Wrap; + AddressV = Wrap; + AddressW = Wrap; +}; + +float3 GetTurbulence( float3 position, float frequency, float3 offset, float3 animation ) +{ + position += offset; + position *= frequency; + position += NoiseMap.SampleLevel( NoiseMapSampler, animation / 32, 0.0 ).xyz; + float3 result = 0; + float amplitude = 1; + + [unroll] + for( int i = 0; i < 3; ++i ) + { + result += ( NoiseMap.SampleLevel( NoiseMapSampler, position, 0.0 ).xyz - 0.5 ) * amplitude; + amplitude *= 0.5; + position = 2.0 * position.zyx; + } + return result; +} + +bool UpdateParticle( inout GpuParticleData particle, GpuParticleEmitterParams emitter, float dt, float seedf, float3 originShift, float3 turbulenceOffset, float3 turbulenceAnimation ) +{ + if( particle.age >= 0 ) + { + particle.age += dt; + + if( particle.age >= lerp( emitter.minLifeTime, emitter.maxLifeTime, seedf ) ) + { + particle.age = -1; + return false; + } + else + { + // forces + particle.velocity += float3( 0, emitter.gravity * dt, 0 ); + particle.velocity += GetTurbulence( particle.position, emitter.turbulenceFrequency, turbulenceOffset, turbulenceAnimation ) * emitter.turbulenceAmplitude * dt; + if( emitter.attractor.w != 0 ) + { + float3 dir = normalize( emitter.attractor.xyz - particle.position ); + particle.velocity += dir * emitter.attractor.w * dt; + } + if( emitter.drag < 0 ) + { + float speed = length( particle.velocity ); + if( speed > 0 ) + { + particle.velocity += particle.velocity * speed * emitter.drag * dt; + } + } + else + { + particle.velocity -= particle.velocity * emitter.drag * dt; + } + + particle.position += particle.velocity * dt + originShift; + if( any( isnan( particle.position ) ) ) + { + return false; + } + return true; + } + } + else + { + return false; + } +} + + +struct PerObjectVSData +{ + uint groupCountX; + uint groupCountY; + uint groupCountZ; + float deltaTime; + + float3 originShift; + uint bufferSize; + float4 turbulenceOffset; + float4 turbulenceAnimation; + + float4 frustumPlanes[6]; +} PerObjectVS; + +RWStructuredBuffer ParticleBuffer; +RWStructuredBuffer DeadBuffer; +RWBuffer ParticleCounters; +RWStructuredBuffer VisibleBuffer; +StructuredBuffer Emitters; + +EveSpaceSceneDataVS PerFrameVS : register( PERFRAME_VS_STARTREGISTER ); + +bool SphereInFrustum( float4 xyzr, float4 frustumPlane[6] ) +{ + [unroll] + for( uint i = 0; i != 6; ++i ) + { + if( dot( float4( xyzr.xyz, 1 ), -frustumPlane[i] ) > xyzr.w ) + { + return false; + } + } + return true; +} + +[numthreads( GROUP_X, GROUP_Y, 1 )] +void Update( uint3 grid : SV_GroupID, uint groupIndex : SV_GroupIndex ) +{ + uint offset = ( grid.x + grid.y * PerObjectVS.groupCountX + grid.z * PerObjectVS.groupCountX * PerObjectVS.groupCountY ) * GROUP_X * GROUP_Y + groupIndex; + float3 eye = ExtractEyePosFromViewMatrix( PerFrameVS.ViewInverseTransposeMat ); + float3 dir = normalize( ExtractEyeDirFromViewMatrix( PerFrameVS.ViewMat ) ); + float widthProjection = PerFrameVS.ProjectionMat[0][0] * PerFrameVS.TargetResolution.x; + + uint bufferSize = PerObjectVS.bufferSize; + + for( uint i = offset; i < bufferSize; i += GROUP_X * GROUP_Y * PerObjectVS.groupCountX * PerObjectVS.groupCountY * PerObjectVS.groupCountZ ) + { + GpuParticleData particle = ParticleBuffer[i]; + GpuParticleEmitterParams emitter = Emitters[particle.emitterSeed & 0xffff]; + uint seed = particle.emitterSeed >> 16; + float seedf = float( seed ) / float( 0xffff ); + + if( particle.age >= 0 ) + { + if( UpdateParticle( particle, emitter, PerObjectVS.deltaTime, seedf, PerObjectVS.originShift.xyz, PerObjectVS.turbulenceOffset.xyz, PerObjectVS.turbulenceAnimation.xyz ) ) + { + float maxSize = max( emitter.sizes.x, max( emitter.sizes.y, emitter.sizes.z ) ) * ( 1 + abs( emitter.sizeVariance ) ); + float4 frustumPlanes[6] = + { + PerObjectVS.frustumPlanes[0], + PerObjectVS.frustumPlanes[1], + PerObjectVS.frustumPlanes[2], + PerObjectVS.frustumPlanes[3], + PerObjectVS.frustumPlanes[4], + PerObjectVS.frustumPlanes[5] + }; + if( SphereInFrustum( float4( particle.position, maxSize ), frustumPlanes ) ) + { + float depth = -dot( dir, particle.position - eye ); + float screenSize = maxSize / max( 1.0, depth ) * widthProjection; + if( screenSize > 2 ) + { + int index; + InterlockedAdd( ParticleCounters[1], 1, index ); + + GpuParticleVisibleData ad; + ad.index = i; + ad.depth = -depth; + VisibleBuffer[index] = ad; + } + } + } + else + { + int index; + InterlockedAdd( ParticleCounters[0], 1, index ); + + DeadBuffer[index] = i; + } + ParticleBuffer[i] = particle; + } + else + { + int index; + InterlockedAdd( ParticleCounters[0], 1, index ); + DeadBuffer[index] = i; + } + } +} + + +[numthreads( 1, 1, 1 )] +void ClearCountersCS() +{ + ParticleCounters[0] = 0; + ParticleCounters[1] = 0; +} + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 Update(); + } +} + +technique ClearCounters +{ + pass p0 + { + ComputeShader = compile cs_5_0 ClearCountersCS(); + } +} diff --git a/shaders/include/Carbon/Math.fxh b/shaders/include/Carbon/Math.fxh index bb96c3247..1f2cda8d4 100644 --- a/shaders/include/Carbon/Math.fxh +++ b/shaders/include/Carbon/Math.fxh @@ -328,4 +328,32 @@ float4x4 MatrixInverse(float4x4 m) return result; } + +float4 QuaternionRotationYawPitchRoll( float yaw, float pitch, float roll ) +{ + float sinYaw = sin( yaw / 2.0f ); + float cosYaw = cos( yaw / 2.0f ); + float sinPitch = sin( pitch / 2.0f ); + float cosPitch = cos( pitch / 2.0f ); + float sinRoll = sin( roll / 2.0f ); + float cosRoll = cos( roll / 2.0f ); + + float4 result; + result.x = sinYaw * cosPitch * sinRoll + cosYaw * sinPitch * cosRoll; + result.y = sinYaw * cosPitch * cosRoll - cosYaw * sinPitch * sinRoll; + result.z = cosYaw * cosPitch * sinRoll - sinYaw * sinPitch * cosRoll; + result.w = cosYaw * cosPitch * cosRoll + sinYaw * sinPitch * sinRoll; + return result; +} + +float4 QuaternionMultiply( float4 q1, float4 q2 ) +{ + float4 result; + result.x = q2.w * q1.x + q2.x * q1.w + q2.y * q1.z - q2.z * q1.y; + result.y = q2.w * q1.y - q2.x * q1.z + q2.y * q1.w + q2.z * q1.x; + result.z = q2.w * q1.z + q2.x * q1.y - q2.y * q1.x + q2.z * q1.w; + result.w = q2.w * q1.w - q2.x * q1.x - q2.y * q1.y - q2.z * q1.z; + return result; +} + #endif \ No newline at end of file diff --git a/shaders/include/Carbon/RandomXOrShift.fxh b/shaders/include/Carbon/RandomXOrShift.fxh new file mode 100644 index 000000000..7495c0efc --- /dev/null +++ b/shaders/include/Carbon/RandomXOrShift.fxh @@ -0,0 +1,38 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_RANDOM_FXH +#define CARBON_RANDOM_FXH + + +// Based on https://www.reedbeta.com/blog/quick-and-easy-gpu-random-numbers-in-d3d11/ + +// Initializes a random number generator state based on a seed +uint RandInit( uint seed ) +{ + seed = ( seed ^ 61 ) ^ ( seed >> 16 ); + seed *= 9; + seed = seed ^ ( seed >> 4 ); + seed *= 0x27d4eb2d; + seed = seed ^ ( seed >> 15 ); + return seed; +} + +// Returns a random uint in the range [0, 2^32 - 1] and updates the rngState +uint Rand( inout uint rngState ) +{ + // Xorshift algorithm from George Marsaglia's paper + rngState ^= ( rngState << 13 ); + rngState ^= ( rngState >> 17 ); + rngState ^= ( rngState << 5 ); + return rngState; +} + +// Returns a random float in the range [0, 1) and updates the rngState +float RandFloat( inout uint rngState ) +{ + return float( Rand( rngState ) ) * ( 1.0 / 4294967296.0 ); +} + + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/GpuParticles.fxh b/shaders/include/Carbon/SpaceScene/GpuParticles.fxh new file mode 100644 index 000000000..f40b9fae3 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/GpuParticles.fxh @@ -0,0 +1,86 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_GPUPARTICLES_FXH +#define CARBON_GPUPARTICLES_FXH + +// Per particle data stored in the particle buffer. The particle buffer is a structured buffer of GpuParticleData elements. +struct GpuParticleData +{ + // Position of the particle in world space + float3 position; + // Age of the particle in seconds + float age; + // Particle velocity in world space + float3 velocity; + // 16 low bits - emitter index, 16 high bits - random seed for this particle + uint emitterSeed; +}; + +// Per emitter data stored in the emitter buffer. The emitter buffer is a structured buffer of GpuParticleEmitterParams elements. +struct GpuParticleEmitterParams +{ + // Minimal particle lifetime in seconds + float minLifeTime; + // Maximal particle lifetime in seconds + float maxLifeTime; + // Index of the texture in the texture atlas + float textureIndex; + // Particle color over lifetime, defined by a piecewise linear curve of 4 colors + float4 colors[4]; + // Particle sizes over lifetime, defined by a spline of 3 sizes + float3 sizes; + // Variance of the particle size + float sizeVariance; + // Drag force coefficient applied to the particles + float drag; + // Amplitude of the turbulence force applied to the particles + float turbulenceAmplitude; + // Frequency of the turbulence force applied to the particles + float turbulenceFrequency; + // Gravity force applied to the particles + float gravity; + // Attractor force applied to the particle: XYZ - attractor position, W - attractor strength + float4 attractor; + // Velocity stretch factor or rotation speed + // If velocityStretchRotation is negative, it is used as a velocity stretch factor. If it is positive, it is used as a rotation speed in radians per second. + float velocityStretchRotation; +}; + +float GetGpuParticleSize( GpuParticleEmitterParams params, float age, float seed ) +{ + float v = 1.0 - age; + float spline = params.sizes.x * v * v + params.sizes.y * 2.0 * age * v + params.sizes.z * age * age; + return spline * ( 1 + params.sizeVariance * seed ); +} + +float4 GetGpuParticleColor( GpuParticleEmitterParams params, float age, float exponent ) +{ + age = pow( abs( age ), log( exponent ) / log( 0.5 ) ); + float4 color; + if( age <= 0.333 ) + { + color = lerp( params.colors[0], params.colors[1], age / 0.333 ); + } + else if( age <= 0.666 ) + { + color = lerp( params.colors[1], params.colors[2], age / 0.333 - 1 ); + } + else + { + color = lerp( params.colors[2], params.colors[3], age / ( 1 - 0.666 ) - 0.666 / ( 1 - 0.666 ) ); + } + return color; +} + + +// Per particle data stored in the visible buffer. The visible buffer is a structured buffer of GpuParticleVisibleData elements. +struct GpuParticleVisibleData +{ + // Particle index in the particle buffer + uint index; + // Particle depth in projection space + float depth; +}; + + +#endif \ No newline at end of file From cf4c6e8f4bb5aa365a932bbea1e6b3e33eb20b3a Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Wed, 7 Oct 2026 12:19:55 +0000 Subject: [PATCH 16/83] More shaders --- CMakeLists.txt | 9 +- .../SpecialFX/Volumetric/Fog/ApplyFroxels.fx | 53 +++++++ .../SpecialFX/Volumetric/Fog/FilterFroxels.fx | 113 +++++++++++++ .../Space/SpecialFX/Volumetric/Fog/Fog.fxh | 118 ++++++++++++++ .../Volumetric/Fog/RaymarchFroxels.fx | 66 ++++++++ .../Volumetric/Fog/UpdateMieEnvironmentMap.fx | 148 ++++++++++++++++++ .../include/Carbon/SpaceScene/EveStretch2.fxh | 29 ++++ .../Carbon/SpaceScene/EveTacticalOverlay.fxh | 47 ++++++ 8 files changed, 582 insertions(+), 1 deletion(-) create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx create mode 100644 shaders/include/Carbon/SpaceScene/EveStretch2.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 947c3925f..54686bdd3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,8 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh shaders/include/Carbon/SpaceScene/EveTransform.fxh + shaders/include/Carbon/SpaceScene/EveStretch2.fxh + shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh shaders/include/Carbon/SpaceScene/GpuParticles.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh @@ -161,6 +163,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/RandomXOrShift.fxh shaders/include/Carbon/System.fxh shaders/include/Carbon/Tr2CurveLineSet.fxh + shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx @@ -169,7 +172,11 @@ set(_SHADER_SOURCES shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx - shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx + shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx + shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx + shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh + shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx + shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx new file mode 100644 index 000000000..6602e0e5c --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx @@ -0,0 +1,53 @@ +// Copyright © 2026 CCP ehf. + +#pragma permutation(ENVIRONMENT_LIGHTING, values = ( ENVIRONMENT_LIGHTING_DISABLED, ENVIRONMENT_LIGHTING_ENABLED ) ) + +#include "../../../../../include/Carbon/System.fxh" +#include "../../../../../include/Carbon/SpaceScene/PerSceneData.fxh" +#include "../../../../../include/Carbon/SpaceScene/Volumetrics.fxh" +#include "../../../../../include/Carbon/SpaceScene/DepthMap.fxh" + +EveSpaceSceneDataPS PerFramePS : register( PERFRAME_PS_STARTREGISTER ); + + +SamplerState DepthMapSamplerClamp +{ + MinFilter = Point; + MagFilter = Point; + MipFilter = None; + AddressU = Clamp; + AddressV = Clamp; +}; + + +float4 vs( float4 pos : POSITION ) : SV_Position +{ + return pos; +}; + +float4 ps( float4 pos : SV_Position ) : SV_Target0 +{ + float2 texCoords = pos.xy / PerFramePS.RenderTargetData.xy; + float sceneDepth = DepthMap.SampleLevel( DepthMapSamplerClamp, texCoords, 0.0 ).r; + + float4 result; +#if ENVIRONMENT_LIGHTING == ENVIRONMENT_LIGHTING_ENABLED + result = SampleEveSceneFroxelFog( texCoords, sceneDepth, PerFramePS, true ); +#else + result = SampleEveSceneFroxelFog( texCoords, sceneDepth, PerFramePS, false ); +#endif + return result; +} + +technique Main +{ + pass P0 + { + SrcBlend = One; + DestBlend = SrcAlpha; + CullMode = None; + ZEnable = False; + VertexShader = compile vs_5_0 vs(); + PixelShader = compile ps_5_0 ps(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx new file mode 100644 index 000000000..7235a6ea2 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx @@ -0,0 +1,113 @@ +// Copyright © 2026 CCP ehf. + +#include "Fog.fxh" + +SamplerState NearestClampSampler = sampler_state +{ + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; +}; +SamplerState LinearClampSampler = sampler_state +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; +}; + +Texture3D InputTexture; +Texture3D PreviousTexture; + + +RWTexture3D OutputTexture; + + +void accumulate( inout float4 m1, inout float4 m2, float weight, float4 froxel ) +{ + m1 += froxel * weight; + m2 += ( froxel * froxel ) * weight; +} + +[numthreads( 4, 4, 4 )] +void Test( uint3 coords : SV_DispatchThreadID ) +{ + if( coords.x >= FroxelPerObject.Resolution.x || coords.y >= FroxelPerObject.Resolution.y || coords.z >= FroxelPerObject.Resolution.z ) + { + return; + } + + float3 texCoords = ( float3( coords ) + 0.5 ) / float3( FroxelPerObject.Resolution ); + + float4 current = InputTexture.SampleLevel( NearestClampSampler, texCoords, 0 ); + + float4 m1 = 0.0; + float4 m2 = 0.0; + + float weight = 1.0 / 7.0; + + accumulate( m1, m2, weight, current ); + accumulate( m1, m2, weight, InputTexture.SampleLevel( NearestClampSampler, texCoords, 0, int3( -1, 0, 0 ) ) ); + accumulate( m1, m2, weight, InputTexture.SampleLevel( NearestClampSampler, texCoords, 0, int3( +1, 0, 0 ) ) ); + accumulate( m1, m2, weight, InputTexture.SampleLevel( NearestClampSampler, texCoords, 0, int3( 0, -1, 0 ) ) ); + accumulate( m1, m2, weight, InputTexture.SampleLevel( NearestClampSampler, texCoords, 0, int3( 0, +1, 0 ) ) ); + accumulate( m1, m2, weight, InputTexture.SampleLevel( NearestClampSampler, texCoords, 0, int3( 0, 0, -1 ) ) ); + accumulate( m1, m2, weight, InputTexture.SampleLevel( NearestClampSampler, texCoords, 0, int3( 0, 0, +1 ) ) ); + + float4 mean = m1; + float4 std = sqrt( max( m2 - mean * mean, 0.0 ) ); + + float4 result = current; + + //if(true) //Could attempt an early out here to improve performance when std is small (i.e. tight clamping --> we basically ignore the previous frame anyway) + { + +#if 1 + float layerDistance = GetLayerDistance( texCoords.z ); + float3 viewDirection = float3( texCoords.xy * FroxelPerObject.UnprojectParams.xy + FroxelPerObject.UnprojectParams.zw, -1.0 ); + float3 viewPosition = viewDirection * ( layerDistance * rsqrt( dot( viewDirection, viewDirection ) ) ); + + float3 previousViewPosition = mul( float4( viewPosition, 1.0 ), FroxelPerObject.ReprojectionMatrix ).xyz; //no need to do perspective divide + float2 previousCoords = ( previousViewPosition.xy / -previousViewPosition.z ) * FroxelPerObject.PreviousProjectParams.xy + FroxelPerObject.PreviousProjectParams.zw; + float previousNormalizedZ = GetNormalizedZ( length( previousViewPosition ) ); + + float3 previousTexCoords = float3( previousCoords, previousNormalizedZ ); + float4 previous = PreviousTexture.SampleLevel( LinearClampSampler, previousTexCoords, 0 ); +#else + float4 previous = PreviousTexture.SampleLevel(NearestClampSampler, texCoords, 0); +#endif + + + float gamma = 2.0; + previous = clamp( previous, mean - std * gamma, mean + std * gamma ); + + result = lerp( previous, current, 0.05 ); + + //result = float4(abs(texCoords - previousTexCoords) * 100.0, 1.0); + + //result = float4(abs(previousTexCoords - texCoords.xy), 0, current.a); + } + + if( any( isnan( result ) ) || any( isinf( result ) ) ) + { + result = float4( 1, 0, 0, 1 ); + } + + OutputTexture[coords] = result; + +} + + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 Test(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh new file mode 100644 index 000000000..9a9b3b237 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh @@ -0,0 +1,118 @@ +// Copyright © 2026 CCP ehf. + +#ifndef FOG_FXH +#define FOG_FXH + +#include "../../../../../include/Carbon/System.fxh" + + +static const uint LIGHT_FLAG_AFFECTS_SURFACE = 1 << 16; +static const uint LIGHT_FLAG_AFFECTS_PARTICLES = 1 << 17; +static const uint LIGHT_FLAG_CASTS_SHADOWS = 1 << 18; +static const uint LIGHT_FLAG_IS_VOLUMETRIC = 1 << 19; + +struct PerLightData +{ + float4 position; // xyz - world position, w - radius + float4 color; // xyz - color, w - bits 0..15 - innerRadius (float 16), bits 16..31 - flags + float4 direction; // see next few lines: + // x bits 0..15 - direction.x (float 16), x bits 16..31 - direction.y (float 16) + // y bits 0..15 - direction.z (float 16), y bits 16..31 - projectionPlaneDistance (float 16) + // z bits 0..15 - outerAngle (float 16), z bits 16..31 - innerAngle (float 16) + // w bits 0..1 - padding, w bits 2..11 - shadowMapScale, w bits 12..21 - shadowMapOffsetX, w bits 22..31 - shadowMapOffsetY +}; + +struct HitInfo +{ + float visibility; +}; + +#ifndef RAYTRACING +Texture2D ShadowMapAtlas ; +#endif + +struct FroxelPerObjectData +{ + uint3 Resolution; + uint NumDynamicLights; + + float3 Jitter; + float Far; + + float3 Scattering; + float BaseDensity; + + float MaxDistanceVisibility; + float LightG; + float EnvironmentIntensity; + float InverseShadowMapAtlasSize; + + float3 Extinction; + uint ShadowMapAtlasEntryMinSizeLog2; + + float4x4 InverseViewMatrix; + + + float GodRayNoiseFrequency; + float GodRayNoiseLerp; + float GodRayNoiseAnimation; + float GodRayNoiseIntensity; + + float4x4 GodRayNoiseMatrix; + + + float3 FogNoiseOffset; + float FogNoiseFrequency; + + float FogNoiseLerp; + float FogNoiseIntensity; + float2 LinearizeDepthParams; + + + float4 UnprojectParams; + float4 PreviousProjectParams; + float4x4 ReprojectionMatrix; + + float3 SunViewDirection; + float SunAngle; + + float3 SunWorldDirection; + float pad0; + + float3 SunColor; + float LightProfileTextureWidth; + + //Directional light shadows + float4 ShadowMapValues[4]; // x = zFar value[0], y = zFar value[1], z = zFar value[2], w = zFar value[3]..etc + float4x4 ShadowMatrix[16]; // Matrix that takes a coordinate from view space all the way to the packed cascades + float4 SplitInfo; // x = NrOfSplits, y = , z = , w = + + PerLightData DynamicLights[16]; + + float4 Planets[2]; +}; + +cbuffer FroxelPerObjectCB : register(b3) +{ + FroxelPerObjectData FroxelPerObject; +} + +float Dither(uint2 xy, float jitter) +{ + float g = 1.32471795724474602596; + return frac(jitter + dot(float2(xy), 1.0 / float2(g, g*g))); +} + +float GetLayerDistance(float normalizedZ) +{ + float layerDistance = -log(lerp(1.0, FroxelPerObject.MaxDistanceVisibility, normalizedZ)) / FroxelPerObject.BaseDensity; + return layerDistance; +} + +float GetNormalizedZ(float layerDistance) +{ + float normalizedZ = saturate((exp(-layerDistance * FroxelPerObject.BaseDensity) - 1.0) / (FroxelPerObject.MaxDistanceVisibility - 1.0)); + return normalizedZ; +} + +#endif \ No newline at end of file diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx new file mode 100644 index 000000000..998353832 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx @@ -0,0 +1,66 @@ +// Copyright © 2026 CCP ehf. + +#pragma permutation(INPUT_SOURCE, values = ( INPUT_SOURCE_INPUT_TEXTURE, INPUT_SOURCE_OUTPUT_TEXTURE ) ) + +#include "Fog.fxh" + +Texture3D InputTexture; + +RWTexture3D OutputTexture; + +[numthreads( 8, 4, 1 )] +void Test( uint3 coords : SV_DispatchThreadID ) +{ + if( coords.x >= FroxelPerObject.Resolution.x || coords.y >= FroxelPerObject.Resolution.y || coords.z >= FroxelPerObject.Resolution.z ) + { + return; + } + + float inverseLayers = 1.0 / FroxelPerObject.Resolution.z; + + float4 total = 0.0; + + float previousDistance = 0.0; + + for( uint i = 0; i < FroxelPerObject.Resolution.z; i++ ) + { + + float normalizedZ = ( float( i ) + 1.0 ) * inverseLayers; + + float layerDistance = min( FroxelPerObject.Far, GetLayerDistance( normalizedZ ) ); + float stepSize = layerDistance - previousDistance; + previousDistance = layerDistance; + +#if INPUT_SOURCE == INPUT_SOURCE_INPUT_TEXTURE + float3 froxel = InputTexture[uint3( coords.xy, i )]; +#else + float3 froxel = OutputTexture[uint3(coords.xy, i)]; +#endif + float density = stepSize * FroxelPerObject.BaseDensity; + + //Naive integration explodes when density is large, greatly overestimating the scattering + //This is especially bad at high fog density with the last layer, as that one goes to the far plane + //float3 color = froxel * Scattering * density; + + //Physically correct integration makes sure we don't emit more light than is coming in. + float3 color = froxel * FroxelPerObject.Scattering * ( 1.0 - exp( -density ) ); + + float visibility = exp( -total.a ); + + total += float4( color * visibility, density ); + + OutputTexture[uint3( coords.xy, i )] = total.rgb; + } + + +} + + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 Test(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx new file mode 100644 index 000000000..d0be66964 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx @@ -0,0 +1,148 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/System.fxh" + + +uint Resolution; +float2 Jitter; + +float EnvironmentG; + +float BlendWeight; + +float Random; + +TextureCube EveSpaceSceneStaticEnvMap; + +SamplerState LinearClampSampler = sampler_state +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; +}; + +RWTexture2DArray PrecomputedMieEnvironmentMap; + + +float dither( uint2 coords, float scale ) +{ + float g = 1.32471795724474602596; + return frac( Random + dot( float2( coords ), 1.0 / float2( g, g * g ) ) ) * ( 2.0 * scale ) - scale; +} + + +[numthreads( 8, 8, 1 )] +void Test( uint3 coords : SV_DispatchThreadID ) +{ + if( coords.x >= Resolution || coords.y >= Resolution ) + { + return; + } + + float u = ( coords.x + 0.5 ) / Resolution * +2.0 - 1.0; + float v = ( coords.y + 0.5 ) / Resolution * -2.0 + 1.0; + uint face = coords.z; + + + float3 direction; + + if( face == 0 ) + direction = float3( 1, v, -u ); + else if( face == 1 ) + direction = float3( -1, v, u ); + else if( face == 2 ) + direction = float3( u, 1, -v ); + else if( face == 3 ) + direction = float3( u, -1, v ); + else if( face == 4 ) + direction = float3( u, v, 1 ); + else + direction = float3( -u, v, -1 ); + + direction = normalize( direction ); + + float3 normal = -direction; + + float3 up = float3( 1, 0, 0 ); + if( abs( dot( normal, up ) ) > 0.9 ) + { + up = float3( 0, 1, 0 ); + } + float3 tangent = normalize( cross( normal, up ) ); + float3 bitangent = cross( normal, tangent ); + + float4x4 transform = float4x4( + float4( tangent, 0.0 ), + float4( bitangent, 0.0 ), + float4( normal, 0.0 ), + float4( 0.0, 0.0, 0.0, 1.0 ) + ); + + const int ENVIRONMENT_SAMPLES = 32; + + const float PI = 3.14159265359; + + float g = EnvironmentG; + float g2 = g * g; + + const float GRADIENT_STRENGTH = 32.0; + float gradient = GRADIENT_STRENGTH / -g - GRADIENT_STRENGTH; + + float mipmap = log2( gradient ); + + + float weight = rcp( float( ENVIRONMENT_SAMPLES ) ); + + float3 environmentLighting = 0.0; + for( int i = 0; i < ENVIRONMENT_SAMPLES; i++ ) + { + + float2 randomOffset = float2( ( i + 0.5 ) / ENVIRONMENT_SAMPLES, i * 0.61803398875 ); + + randomOffset = frac( randomOffset + Jitter ); + + + float a = ( 1.0 / ( 2.0 * g ) ) * ( 1.0 + g2 - pow( ( 1.0 - g2 ) / ( 1.0 - g + 2.0 * g * randomOffset.x ), 2.0 ) ); + float b = randomOffset.y * ( PI * 2.0 ); + + float2 vertical = float2( a, sqrt( 1.0 - a * a ) ); + + float2 horizontal = float2( cos( b ), sin( b ) ); + float3 direction = mul( float4( horizontal.x * vertical.y, horizontal.y * vertical.y, vertical.x, 0.0 ), transform ).xyz; + float3 environmentColor = EveSpaceSceneStaticEnvMap.SampleLevel( LinearClampSampler, direction, 0.0 ).rgb; + + environmentLighting += environmentColor * weight; + } + + float3 previous = PrecomputedMieEnvironmentMap[coords]; + + float3 result = lerp( previous, environmentLighting, BlendWeight ); + + + if( any( isnan( result ) ) || any( isinf( result ) ) ) + { + result = float3( 1, 0, 0 ); + } + + //None of this helps with the precision issues :( + + //result *= 1.0 + dither(coords.xy, 1.0 / 512.0); + + //float3 test = asfloat(int3(asint(result)) + int(dither(coords.xy, 512.0 * 160))); + //result = test; + + PrecomputedMieEnvironmentMap[coords] = result; +} + + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 Test(); + } +} diff --git a/shaders/include/Carbon/SpaceScene/EveStretch2.fxh b/shaders/include/Carbon/SpaceScene/EveStretch2.fxh new file mode 100644 index 000000000..9b94d8d96 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveStretch2.fxh @@ -0,0 +1,29 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVESTRETCH2_FXH +#define CARBON_EVESTRETCH2_FXH + + +// Data passed from the engine to the all shader stage for EveStretch2 draw calls. +struct EveStretch2PerObjectData +{ + // XYZ - stretch source position in world space, W - scale factor for the destination point or 0 if the destination effect is hidden + float4 SourcePosition; + // XYZ - stretch destination position in world space, W - scale factor for the destination point + float4 DestPosition; + // X - time from the beginning of the "start" phase, Y - time from the beginning of the firing loop, Z - time from the beginning of the "end" phase, W - random value from 0 to 1 + float4 Timing; + // X - effect intensity, YZW - unused + float4 Misc; +}; + + +// Data passed from the engine to the vertex shader stage for EveStretch2 draw calls. +struct EveStretch2Vertex +{ + // X - index of the quad, Y - index of the vertex in the quad + float2 indices : POSITION; +}; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh b/shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh new file mode 100644 index 000000000..85b778385 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh @@ -0,0 +1,47 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVETACTICALOVERLAY_FXH +#define CARBON_EVETACTICALOVERLAY_FXH + + +// Data passed from the engine to the vertex shader stage for EveTacticalOverlay sphere connector draw calls. +struct EveTacticalOverlaySphereConnectorVertexInput +{ + // XYZ - connector position in world space, W - step count and step index + float4 instanceData : TEXCOORD0; + // Object radius in integer part, intensity in fractional part + float instanceData2 : TEXCOORD1; + // Quad vertex index (0-3) + float index : TEXCOORD5; +}; + + +// Data passed from the engine to the vertex shader stage for EveTacticalOverlay anchor draw calls. +struct EveTacticalOverlayAnchorVertexInput +{ + // XYZ - anchor position in world space, W - effect intensity + float4 instanceData : TEXCOORD0; + // Quad vertex index (0-3) + float index : TEXCOORD5; +}; + + +// Data passed from the engine to the vertex shader stage for EveTacticalOverlay velocity connector draw calls. +struct EveTacticalOverlayVelocityConnectorVertexInput +{ + // XYZ - connector position in world space, W - quad index (0 - velocity, 1 - approach amount, 2 - relative approach amount) + float4 instanceData : TEXCOORD0; + // XYZ - velocity in world space, W - radius in integer part, blink phase in fractional part + float4 instanceData2 : TEXCOORD1; + // Quad vertex index (0-3) + float index : TEXCOORD5; +}; + +// Tactical overlay plane position in world space, passed via a variable store +float3 PlanePosition = float3( 0, 0, 0 ); +// Player ship velocity in world space, passed via a variable store +float3 RootVelocity = float3( 0, 0, 0 ); +// X - active range; Y - fadeout length; Z - multiplier for range and fadeout; W - base/source/ship radius +float4 Fadeout = float4( 200000.0, 50000.0, 1.0, 50.0 ); + +#endif \ No newline at end of file From 95affb1c9eec9651f0fe29ce97ed930d1d560119 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Wed, 7 Oct 2026 13:05:53 +0000 Subject: [PATCH 17/83] Fog shaders --- CMakeLists.txt | 2 +- .../SpecialFX/Volumetric/Fog/FilterFroxels.fx | 11 +++-- .../Volumetric/Fog/RaymarchFroxels.fx | 11 +++-- .../Carbon/SpaceScene/FroxelFog.fxh} | 48 ++++++------------- 4 files changed, 31 insertions(+), 41 deletions(-) rename shaders/{Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh => include/Carbon/SpaceScene/FroxelFog.fxh} (61%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 54686bdd3..363a566a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveTransform.fxh shaders/include/Carbon/SpaceScene/EveStretch2.fxh shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh + shaders/include/Carbon/SpaceScene/FroxelFog.fxh shaders/include/Carbon/SpaceScene/GpuParticles.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh @@ -174,7 +175,6 @@ set(_SHADER_SOURCES shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx - shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx ) diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx index 7235a6ea2..79d1ae614 100644 --- a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx @@ -1,6 +1,11 @@ // Copyright © 2026 CCP ehf. -#include "Fog.fxh" +#include "../../../../../include/Carbon/SpaceScene/FroxelFog.fxh" + +cbuffer FroxelPerObjectCB : register( b3 ) +{ + FroxelPerObjectData FroxelPerObject; +} SamplerState NearestClampSampler = sampler_state { @@ -68,13 +73,13 @@ void Test( uint3 coords : SV_DispatchThreadID ) { #if 1 - float layerDistance = GetLayerDistance( texCoords.z ); + float layerDistance = FroxelGetLayerDistance( texCoords.z, FroxelPerObject ); float3 viewDirection = float3( texCoords.xy * FroxelPerObject.UnprojectParams.xy + FroxelPerObject.UnprojectParams.zw, -1.0 ); float3 viewPosition = viewDirection * ( layerDistance * rsqrt( dot( viewDirection, viewDirection ) ) ); float3 previousViewPosition = mul( float4( viewPosition, 1.0 ), FroxelPerObject.ReprojectionMatrix ).xyz; //no need to do perspective divide float2 previousCoords = ( previousViewPosition.xy / -previousViewPosition.z ) * FroxelPerObject.PreviousProjectParams.xy + FroxelPerObject.PreviousProjectParams.zw; - float previousNormalizedZ = GetNormalizedZ( length( previousViewPosition ) ); + float previousNormalizedZ = FroxelGetNormalizedZ( length( previousViewPosition ), FroxelPerObject ); float3 previousTexCoords = float3( previousCoords, previousNormalizedZ ); float4 previous = PreviousTexture.SampleLevel( LinearClampSampler, previousTexCoords, 0 ); diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx index 998353832..e89c0b9c5 100644 --- a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx @@ -2,7 +2,12 @@ #pragma permutation(INPUT_SOURCE, values = ( INPUT_SOURCE_INPUT_TEXTURE, INPUT_SOURCE_OUTPUT_TEXTURE ) ) -#include "Fog.fxh" +#include "../../../../../include/Carbon/SpaceScene/FroxelFog.fxh" + +cbuffer FroxelPerObjectCB : register( b3 ) +{ + FroxelPerObjectData FroxelPerObject; +} Texture3D InputTexture; @@ -27,14 +32,14 @@ void Test( uint3 coords : SV_DispatchThreadID ) float normalizedZ = ( float( i ) + 1.0 ) * inverseLayers; - float layerDistance = min( FroxelPerObject.Far, GetLayerDistance( normalizedZ ) ); + float layerDistance = min( FroxelPerObject.Far, FroxelGetLayerDistance( normalizedZ, FroxelPerObject ) ); float stepSize = layerDistance - previousDistance; previousDistance = layerDistance; #if INPUT_SOURCE == INPUT_SOURCE_INPUT_TEXTURE float3 froxel = InputTexture[uint3( coords.xy, i )]; #else - float3 froxel = OutputTexture[uint3(coords.xy, i)]; + float3 froxel = OutputTexture[uint3( coords.xy, i )]; #endif float density = stepSize * FroxelPerObject.BaseDensity; diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh b/shaders/include/Carbon/SpaceScene/FroxelFog.fxh similarity index 61% rename from shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh rename to shaders/include/Carbon/SpaceScene/FroxelFog.fxh index 9a9b3b237..830c59b1a 100644 --- a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh +++ b/shaders/include/Carbon/SpaceScene/FroxelFog.fxh @@ -1,17 +1,11 @@ // Copyright © 2026 CCP ehf. -#ifndef FOG_FXH -#define FOG_FXH +#ifndef CARBON_FOG_FXH +#define CARBON_FOG_FXH -#include "../../../../../include/Carbon/System.fxh" +#include "../System.fxh" - -static const uint LIGHT_FLAG_AFFECTS_SURFACE = 1 << 16; -static const uint LIGHT_FLAG_AFFECTS_PARTICLES = 1 << 17; -static const uint LIGHT_FLAG_CASTS_SHADOWS = 1 << 18; -static const uint LIGHT_FLAG_IS_VOLUMETRIC = 1 << 19; - -struct PerLightData +struct FroxelPerLightData { float4 position; // xyz - world position, w - radius float4 color; // xyz - color, w - bits 0..15 - innerRadius (float 16), bits 16..31 - flags @@ -22,15 +16,6 @@ struct PerLightData // w bits 0..1 - padding, w bits 2..11 - shadowMapScale, w bits 12..21 - shadowMapOffsetX, w bits 22..31 - shadowMapOffsetY }; -struct HitInfo -{ - float visibility; -}; - -#ifndef RAYTRACING -Texture2D ShadowMapAtlas ; -#endif - struct FroxelPerObjectData { uint3 Resolution; @@ -61,7 +46,7 @@ struct FroxelPerObjectData float4x4 GodRayNoiseMatrix; - float3 FogNoiseOffset; + float3 FogNoiseOffset; float FogNoiseFrequency; float FogNoiseLerp; @@ -83,35 +68,30 @@ struct FroxelPerObjectData float LightProfileTextureWidth; //Directional light shadows - float4 ShadowMapValues[4]; // x = zFar value[0], y = zFar value[1], z = zFar value[2], w = zFar value[3]..etc + float4 ShadowMapValues[4]; // x = zFar value[0], y = zFar value[1], z = zFar value[2], w = zFar value[3]..etc float4x4 ShadowMatrix[16]; // Matrix that takes a coordinate from view space all the way to the packed cascades float4 SplitInfo; // x = NrOfSplits, y = , z = , w = - PerLightData DynamicLights[16]; + FroxelPerLightData DynamicLights[16]; float4 Planets[2]; }; -cbuffer FroxelPerObjectCB : register(b3) -{ - FroxelPerObjectData FroxelPerObject; -} - -float Dither(uint2 xy, float jitter) +float FroxelDither( uint2 xy, float jitter ) { - float g = 1.32471795724474602596; - return frac(jitter + dot(float2(xy), 1.0 / float2(g, g*g))); + float g = 1.32471795724474602596; + return frac( jitter + dot( float2( xy ), 1.0 / float2( g, g * g ) ) ); } -float GetLayerDistance(float normalizedZ) +float FroxelGetLayerDistance( float normalizedZ, FroxelPerObjectData froxelPerObject ) { - float layerDistance = -log(lerp(1.0, FroxelPerObject.MaxDistanceVisibility, normalizedZ)) / FroxelPerObject.BaseDensity; + float layerDistance = -log( lerp( 1.0, froxelPerObject.MaxDistanceVisibility, normalizedZ ) ) / froxelPerObject.BaseDensity; return layerDistance; } -float GetNormalizedZ(float layerDistance) +float FroxelGetNormalizedZ( float layerDistance, FroxelPerObjectData froxelPerObject ) { - float normalizedZ = saturate((exp(-layerDistance * FroxelPerObject.BaseDensity) - 1.0) / (FroxelPerObject.MaxDistanceVisibility - 1.0)); + float normalizedZ = saturate( ( exp( -layerDistance * froxelPerObject.BaseDensity ) - 1.0 ) / ( froxelPerObject.MaxDistanceVisibility - 1.0 ) ); return normalizedZ; } From 73785932c0de398221c6bf9a4ab9585107e93106 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Wed, 7 Oct 2026 13:58:21 +0000 Subject: [PATCH 18/83] Cloud shaders --- CMakeLists.txt | 3 + .../SpecialFX/Volumetric/BlurVolumetric.fx | 79 +++++++++++++++++++ .../SpecialFX/Volumetric/DownsampleDepth.fx | 31 ++++++++ .../Carbon/SpaceScene/EnvironmentMap.fxh | 6 +- .../Carbon/SpaceScene/EveChildCloud2.fxh | 53 +++++++++++++ 5 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx create mode 100644 shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 363a566a4..4ca3484e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,6 +140,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh + shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh shaders/include/Carbon/SpaceScene/EveHazeSet.fxh shaders/include/Carbon/SpaceScene/EveLensflare.fxh shaders/include/Carbon/SpaceScene/EveOccluder.fxh @@ -177,6 +178,8 @@ set(_SHADER_SOURCES shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx + shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx + shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx b/shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx new file mode 100644 index 000000000..11f947d9c --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx @@ -0,0 +1,79 @@ +#pragma permutation(SOURCE_TYPE, values=(SOURCE_TYPE_ARRAY, SOURCE_TYPE_TEXTURE)) + +#include "../../../../include/Carbon/SpaceScene/PerSceneData.fxh" +#include "../../../../include/Carbon/SpaceScene/Volumetrics.fxh" + +EveSpaceSceneDataPS PerFramePS : register( PERFRAME_PS_STARTREGISTER ); + + +float4 vs( float4 pos : POSITION ) : SV_Position +{ + return pos; +}; + + +SamplerState EveSceneFogVolumeMapPSampler +{ + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; +}; + +float4 DepthSizes; +Texture2D VolumetricDepthMap; +Texture2D SourceMap; + +float GetLinearDepth( float d ) +{ + return PerFramePS.ProjectionData.x / ( d + PerFramePS.ProjectionData.y ); +} + +float4 ps( float4 pos : SV_Position ) : SV_Target +{ + float2 uv = pos.xy / DepthSizes.xy; + float2 invTexelSize = DepthSizes.zw; + + float centerDepth = GetLinearDepth( VolumetricDepthMap.SampleLevel( EveSceneFogVolumeMapPSampler, uv, 0 ) ); + + half4 color = 0; + half weight = 0; + +#define HALFTAP 2 + const half weights[HALFTAP * 2 + 1] = { 18, 46, 90, 46, 18 }; + + [unroll] + for( float i = -HALFTAP; i <= HALFTAP; ++i ) + { + float depth = GetLinearDepth( VolumetricDepthMap.SampleLevel( EveSceneFogVolumeMapPSampler, uv + i * invTexelSize, 0 ) ); + + half w = weights[i + HALFTAP]; + float denom = 1 + min( depth, centerDepth ); + w *= half( 1 - saturate( abs( depth - centerDepth ) / denom ) ); +#if SOURCE_TYPE == SOURCE_TYPE_TEXTURE + color += w * SourceMap.SampleLevel( EveSceneFogVolumeMapPSampler, uv + i * invTexelSize, 0 ); +#else + color += w * half4( EveSceneFogVolumeMap.SampleLevel( EveSceneFogVolumeMapPSampler, float3( uv + i * invTexelSize, 3 ), 0 ) ); +#endif + weight += w; + } + color /= weight; + + color.a = saturate( color.a ); //half precision math means we can get over 1.0 alpha, so saturate it. + + return float4( color ); +} + +technique Main +{ + pass P0 + { + AlphaBlendEnable = false; + CullMode = None; + ZEnable = False; + VertexShader = compile vs_5_0 vs(); + PixelShader = compile ps_5_0 ps(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx b/shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx new file mode 100644 index 000000000..757aa103f --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx @@ -0,0 +1,31 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../include/Carbon/System.fxh" +#include "../../../../include/Carbon/SpaceScene/DepthMap.fxh" + + +float4 vs( float4 pos : POSITION ) : SV_Position +{ + return pos; +} + + +float4 DepthSizes; + +float4 ps( float4 pos : SV_Position ) : SV_Target +{ + return DepthMap.Load( float3( pos.xy / DepthSizes.xy * DepthSizes.zw, 0 ) ); +} + + +technique Main +{ + pass P0 + { + AlphaBlendEnable = false; + CullMode = None; + ZEnable = False; + VertexShader = compile vs_5_0 vs(); + PixelShader = compile ps_5_0 ps(); + } +} diff --git a/shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh b/shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh index c68b4130b..2ab4cc415 100644 --- a/shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh +++ b/shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh @@ -42,7 +42,7 @@ float RoughnessToGloss( float roughness ) } // Helper function to convert PBR roughness to mip level used for environment map lookup -float RoughnessToMip( TextureCube envMap, float roughness ) +float RoughnessToMip( float roughness, TextureCube envMap ) { uint width; uint height; @@ -55,13 +55,13 @@ float RoughnessToMip( TextureCube envMap, float roughness ) // Helper function to convert PBR roughness to mip level used for environment map lookup for EveSpaceSceneEnvMap float RoughnessToMip( float roughness ) { - return RoughnessToMip( EveSpaceSceneEnvMap, roughness ); + return RoughnessToMip( roughness, EveSpaceSceneEnvMap ); } // Sample an environment map with given direction and surface roughness float3 SampleEnvironmentMap( TextureCube envMap, float3 dir, float roughness ) { - return envMap.SampleLevel( EveSpaceSceneEnvMapSampler, dir, RoughnessToMip( envMap, roughness ) ).rgb; + return envMap.SampleLevel( EveSpaceSceneEnvMapSampler, dir, RoughnessToMip( roughness, envMap ) ).rgb; } #endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh b/shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh new file mode 100644 index 000000000..1af046d7a --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh @@ -0,0 +1,53 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVECHILDCLOUD2_FXH +#define CARBON_EVECHILDCLOUD2_FXH + + +// Data passed from the engine to the vertex shader stage for EveChildCloud2 draw calls. +struct EveChildCloud2VertexInput +{ + // Vertex position in object space + float3 position : POSITION; +}; + + +struct EveChildCloud2LightInfo +{ + float4 position; // xyz - position, w - radius + float4 color; // xyz - color, w - normalized inner radius +}; + + +// Constant buffer format for per-object data for EveChildCloud2. This data is provided by the engine to all shader stages. +struct EveChildCloud2PerObjectData +{ + float4x4 WorldMat; + float4x4 ProjectionInvMat; + float4x4 WorldViewInvMat; + uint4 LightmapDimensions; // xyz - lightmap width/height/depth, w - current generation offset + uint4 NoiseConfig; // xy - random offset, zw - noise texture width/height + float4 SunDirection; // xyz - sun direction in model space, w - slice 0 w + float4 ViewPosition; // xyz - view position in model space, w - slice 1 w + float4 ViewDirection; // xyz - view direction in model space, w - slice 2 w + float4 RelativeScaling; // xyz - renormalizing factors for non-uniform scaling, w - lod factor + float4 TargetInvSize; // xy - render target inv size x2 + EveChildCloud2LightInfo Lights[4]; + float4 MapOffsets[3]; + float4x4 LightViewProj; +}; + + +// The expected pixel shader output from EveChildCloud2 materials. +// Each slice of the cloud is written to a separate render target. +// Slice depth is taken from EveChildCloud2PerObjectData +struct EveChildCloud2PSOutput +{ + float4 slice0 : SV_Target0; + float4 slice1 : SV_Target1; + float4 slice2 : SV_Target2; + float4 slice3 : SV_Target3; +}; + + +#endif \ No newline at end of file From f17f853a24a1433e57dbb9023273106a8d458a60 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Wed, 7 Oct 2026 14:58:16 +0000 Subject: [PATCH 19/83] More vfx shaders --- CMakeLists.txt | 3 ++ .../Carbon/SpaceScene/EveChildCloud.fxh | 30 +++++++++++++++++++ .../Carbon/SpaceScene/EveChildQuad.fxh | 29 ++++++++++++++++++ .../Carbon/SpaceScene/EveStarfield.fxh | 23 ++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/EveChildCloud.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveChildQuad.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveStarfield.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ca3484e0..8deb3cf98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,14 +140,17 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh + shaders/include/Carbon/SpaceScene/EveChildCloud.fxh shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh shaders/include/Carbon/SpaceScene/EveHazeSet.fxh shaders/include/Carbon/SpaceScene/EveLensflare.fxh shaders/include/Carbon/SpaceScene/EveOccluder.fxh shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh + shaders/include/Carbon/SpaceScene/EveChildQuad.fxh shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh + shaders/include/Carbon/SpaceScene/EveStarfield.fxh shaders/include/Carbon/SpaceScene/EveTransform.fxh shaders/include/Carbon/SpaceScene/EveStretch2.fxh shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh diff --git a/shaders/include/Carbon/SpaceScene/EveChildCloud.fxh b/shaders/include/Carbon/SpaceScene/EveChildCloud.fxh new file mode 100644 index 000000000..fee339ee6 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveChildCloud.fxh @@ -0,0 +1,30 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVECHILDCLOUD_FXH +#define CARBON_EVECHILDCLOUD_FXH + + +// Data passed from the engine to the vertex shader stage for EveChildCloud draw calls. +struct EveChildCloudVertexInput +{ + float2 position : POSITION; +}; + + +// Data passed from the engine to the vertex shader stage for EveChildCloud draw calls. +struct EveChildCloudPerObjectDataVS +{ + float4x4 WorldMat; + float4x4 WorldViewMat; + float4x4 WorldViewInv; + float4x4 ProjectionInv; + // Near plane in object space + float4 NearPlaneLocal; + // XYZ - camera position in object space, W - screen depth of the object (Z in clip space) + float4 EyePosLocal; + // Bounds of the cloud in projection space (XY - min, ZW - max) + float4 ScreenSize; +}; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveChildQuad.fxh b/shaders/include/Carbon/SpaceScene/EveChildQuad.fxh new file mode 100644 index 000000000..487ae2b80 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveChildQuad.fxh @@ -0,0 +1,29 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVECHILDQUAD_FXH +#define CARBON_EVECHILDQUAD_FXH + + +struct EveChildQuadVertexInput +{ + // Quad vertex index (0-3) + float index : TEXCOORD5; + + // Transform matrix (3x4) from owner local space to world space + float4 parentTransform0 : POSITION0; + float4 parentTransform1 : POSITION1; + float4 parentTransform2 : POSITION2; + + // Transform matrix (3x4) from quad local space to owner local space + float4 localTransform0 : POSITION3; + float4 localTransform1 : POSITION4; + float4 localTransform2 : POSITION5; + + // Quad color + float4 color : TEXCOORD0; + // X - quad brightness, Y - unused + float2 data : TEXCOORD1; +}; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveStarfield.fxh b/shaders/include/Carbon/SpaceScene/EveStarfield.fxh new file mode 100644 index 000000000..8bce8f5a3 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveStarfield.fxh @@ -0,0 +1,23 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVESTARFIELD_FXH +#define CARBON_EVESTARFIELD_FXH + +struct EveStarfieldVertexInput +{ + // Start sprite position in local space + float3 position : POSITION; + // Random number from 0 to 1 for each star + float coloridx : TEXCOORD0; + // Maximum intensity of the star sprite + float flashIntensity : TEXCOORD1; + // Random phase for the star sprite's flashing effect (0 to 1) + float phase : TEXCOORD2; + // Random rate for the star sprite's flashing effect + float rate : TEXCOORD3; + // X - vertex corner index (0-3), Y - texture atlas element index, Z - unused, W - unused + uint4 index : TEXCOORD4; +}; + + +#endif \ No newline at end of file From 2c5f030810115a90e88f91f2543e9d322cdbe67c Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 09:32:09 +0000 Subject: [PATCH 20/83] Raytracing helpers --- CMakeLists.txt | 2 + .../SpaceScene/Raytracing/GeometryData.fxh | 158 ++++++++ shaders/include/Carbon/VertexBufferUtil.fxh | 346 ++++++++++++++++++ 3 files changed, 506 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh create mode 100644 shaders/include/Carbon/VertexBufferUtil.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 8deb3cf98..acf16de35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,6 +132,7 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() set(_SHADER_SOURCES + shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh shaders/include/Carbon/SpaceScene/DepthMap.fxh shaders/include/Carbon/SpaceScene/DynamicLighting.fxh @@ -168,6 +169,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/RandomXOrShift.fxh shaders/include/Carbon/System.fxh shaders/include/Carbon/Tr2CurveLineSet.fxh + shaders/include/Carbon/VertexBufferUtil.fxh shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx diff --git a/shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh b/shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh new file mode 100644 index 000000000..674181bcf --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh @@ -0,0 +1,158 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_RAYTRACING_GEOMETRYDATA_FXH +#define CARBON_RAYTRACING_GEOMETRYDATA_FXH + +#include "../../PackedTangents.fxh" +#include "../../VertexBufferUtil.fxh" + +// Constant buffer layout for data describing the geometry of a mesh for ray tracing shaders. +// This is used to read vertex and index data from buffers in a shader. +// Normally the constant buffer for this data is declared as: +// cbuffer RtVertexBufferData : register( b5, space8 ) { RayTracingGeometryData geometryData; } +struct RayTracingGeometryData +{ + // Index into the buffer heap view array for the index buffer of the mesh. + uint indexBufferId; + // Index buffer stride in bytes (2 for 16-bit indices, 4 for 32-bit indices). + uint indexBufferStride; + + // Offset in bytes to the start of the index data in the index buffer. + uint indexOffset; + + // Index into the buffer heap view array for the vertex buffer of the mesh. + uint vertexBufferId; + // Vertex buffer stride in bytes. + uint vertexBufferStride; + + // Offset in bytes to the start of the position (POSITION0 semantics) data in the vertex buffer. + uint positionOffset; + // Data type of the position attribute. See constants in VertexBufferUtil.fxh for possible values. + uint positionType; + + // Offset in bytes to the start of the normal (NORMAL0 semantics) data in the vertex buffer. + uint normalOffset; + // Data type of the normal attribute. See constants in VertexBufferUtil.fxh for possible values. + uint normalType; + + // Offset in bytes to the start of the tangent (TANGENT0 semantics) data in the vertex buffer. + uint tangentOffset; + // Data type of the tangent attribute. See constants in VertexBufferUtil.fxh for possible values. + uint tangentType; + + // Offset in bytes to the start of the bitangent (BITANGENT0 semantics) data in the vertex buffer. + uint bitangentOffset; + // Data type of the bitangent attribute. See constants in VertexBufferUtil.fxh for possible values. + uint bitangentType; + + // Offset in bytes to the start of the first texture coordinate (TEXCOORD0 semantics) data in the vertex buffer. + uint texCoord0Offset; + // Data type of the first texture coordinate attribute. + uint texCoord0Type; + + // Offset in bytes to the start of the second texture coordinate (TEXCOORD1 semantics) data in the vertex buffer. + uint texCoord1Offset; + // Data type of the second texture coordinate attribute. + uint texCoord1Type; + + // Offset in bytes to the start of the third texture coordinate (TEXCOORD2 semantics) data in the vertex buffer. + uint texCoord2Offset; + // Data type of the third texture coordinate attribute. + uint texCoord2Type; + + uint padding; +}; + +// Reads trangle vertex indices from the index buffer for a given primitive index. Returns a uint3 containing the three vertex indices of the triangle. +// Handles both 16-bit and 32-bit index buffers based on the indexBufferStride in the RayTracingGeometryData. Assumes "triangle list" topology. +uint3 ReadIndices( Buffer indexBuffer, RayTracingGeometryData data, uint primitiveIndex ) +{ + uint indicesAddress = ( 3 * primitiveIndex ) * data.indexBufferStride + data.indexOffset; + if( data.indexBufferStride == 2 ) + { + return ReadUInt16_3( indexBuffer, indicesAddress ); + } + else + { + return ReadUInt32_3( indexBuffer, indicesAddress ); + } +} + +// Reads the position of a vertex (POSITION0 semantics) from the vertex buffer for a given vertex index. Returns a float3 containing the position. +// Assumes positions are stored as float32_3 in the vertex buffer. The position offset and stride are taken from the RayTracingGeometryData. +float3 ReadPosition( Buffer vertexBuffer, RayTracingGeometryData data, uint vertexIndex ) +{ + return ReadFloat32_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.positionOffset ); +} + +// Reads the normal, tangent, and bitangent of a vertex from the vertex buffer for a given vertex index. Returns a TangentSpace struct containing the three vectors. +// Supports both unpacked and packed tangent space representations based on the tangentType in the RayTracingGeometryData. +TangentSpace ReadNormalTangentBitangent( Buffer vertexBuffer, RayTracingGeometryData data, uint vertexIndex ) +{ + TangentSpace ts; + if( data.tangentType == FLOAT32_3 ) + { + ts.normal = ReadFloat32_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.normalOffset ); + ts.tangent = ReadFloat32_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.tangentOffset ); + ts.bitangent = ReadFloat32_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.bitangentOffset ); + } + else if( data.tangentType == FLOAT16_3 ) + { + ts.normal = ReadFloat16_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.normalOffset ); + ts.tangent = ReadFloat16_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.tangentOffset ); + ts.bitangent = ReadFloat16_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.bitangentOffset ); + } + else if( data.tangentType == UBYTE_4_NORM ) + { + // untested... + uint packed = vertexBuffer.Load( ( vertexIndex * data.vertexBufferStride + data.tangentOffset ) >> 2 ); + float4 tangents; + tangents.x = float( ( packed >> 0 ) & 0xFF ); + tangents.y = float( ( packed >> 8 ) & 0xFF ); + tangents.z = float( ( packed >> 16 ) & 0xFF ); + tangents.w = float( ( packed >> 24 ) & 0xFF ); + tangents *= ( 1. / 255. ); + ts = UnpackTangentSpace( tangents ); + } + else if( data.tangentType == USHORT_4_NORM ) + { + // untested... + uint packed0 = vertexBuffer.Load( ( vertexIndex * data.vertexBufferStride + data.tangentOffset + 0 ) >> 2 ); + uint packed1 = vertexBuffer.Load( ( vertexIndex * data.vertexBufferStride + data.tangentOffset + 4 ) >> 2 ); + float4 tangents; + tangents.x = float( ( packed0 >> 0 ) & 0xFFFF ); + tangents.y = float( ( packed0 >> 16 ) & 0xFFFF ); + tangents.z = float( ( packed1 >> 0 ) & 0xFFFF ); + tangents.w = float( ( packed1 >> 16 ) & 0xFFFF ); + tangents *= ( 1. / 65535. ); + ts = UnpackTangentSpace( tangents ); + } + else + { + ts.normal = 0; + ts.tangent = 0; + ts.bitangent = 0; + } + return ts; +} + +// Reads the texture coordinate (TEXCOORD0 semantics) of a vertex from the vertex buffer for a given vertex index. Returns a float2 containing the texture coordinate. +float2 ReadTexcoord0( Buffer vertexBuffer, RayTracingGeometryData data, uint vertexIndex ) +{ + return ReadFloat_2( vertexBuffer, vertexIndex * data.vertexBufferStride + data.texCoord0Offset, data.texCoord0Type ); +} + +// Reads the texture coordinate (TEXCOORD1 semantics) of a vertex from the vertex buffer for a given vertex index. Returns a float2 containing the texture coordinate. +float2 ReadTexcoord1( Buffer vertexBuffer, RayTracingGeometryData data, uint vertexIndex ) +{ + return ReadFloat_2( vertexBuffer, vertexIndex * data.vertexBufferStride + data.texCoord1Offset, data.texCoord1Type ); +} + +// Reads the texture coordinate (TEXCOORD2 semantics) of a vertex from the vertex buffer for a given vertex index. Returns a float2 containing the texture coordinate. +float2 ReadTexcoord2( Buffer vertexBuffer, RayTracingGeometryData data, uint vertexIndex ) +{ + return ReadFloat_2( vertexBuffer, vertexIndex * data.vertexBufferStride + data.texCoord2Offset, data.texCoord2Type ); +} + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/VertexBufferUtil.fxh b/shaders/include/Carbon/VertexBufferUtil.fxh new file mode 100644 index 000000000..6a1a25885 --- /dev/null +++ b/shaders/include/Carbon/VertexBufferUtil.fxh @@ -0,0 +1,346 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_VERTEX_BUFFER_UTIL_FXH +#define CARBON_VERTEX_BUFFER_UTIL_FXH + +// ------------------------------------------------------------------------ +// --- mirrors Tr2VertexDefinition::DataType, see Tr2VertexDefinition.h --- +// ------------------------------------------------------------------------ +static const uint DT_INT8 = 0u; +static const uint DT_INT16 = 1u; +static const uint DT_INT32 = 2u; +static const uint DT_FLOAT16 = 3u; +static const uint DT_FLOAT32 = 4u; +static const uint DT_TYPE_MASK = 7u; +static const uint DT_UNSIGNED_BIT = ( 1u << 3u ); +static const uint DT_NORMALIZED_BIT = ( 1u << 4u ); +static const uint DT_SIZE_OFFSET = 5u; +static const uint DT_SIZE_MASK = ( 3u << DT_SIZE_OFFSET ); +static const uint DT_SIZE_1 = ( 0u << DT_SIZE_OFFSET ); +static const uint DT_SIZE_2 = ( 1u << DT_SIZE_OFFSET ); +static const uint DT_SIZE_3 = ( 2u << DT_SIZE_OFFSET ); +static const uint DT_SIZE_4 = ( 3u << DT_SIZE_OFFSET ); +static const uint BYTE_1 = ( DT_INT8 | DT_SIZE_1 ); +static const uint BYTE_2 = ( DT_INT8 | DT_SIZE_2 ); +static const uint BYTE_3 = ( DT_INT8 | DT_SIZE_3 ); +static const uint BYTE_4 = ( DT_INT8 | DT_SIZE_4 ); +static const uint UBYTE_1 = ( DT_INT8 | DT_SIZE_1 | DT_UNSIGNED_BIT ); +static const uint UBYTE_2 = ( DT_INT8 | DT_SIZE_2 | DT_UNSIGNED_BIT ); +static const uint UBYTE_3 = ( DT_INT8 | DT_SIZE_3 | DT_UNSIGNED_BIT ); +static const uint UBYTE_4 = ( DT_INT8 | DT_SIZE_4 | DT_UNSIGNED_BIT ); +static const uint SHORT_1 = ( DT_INT16 | DT_SIZE_1 ); +static const uint SHORT_2 = ( DT_INT16 | DT_SIZE_2 ); +static const uint SHORT_3 = ( DT_INT16 | DT_SIZE_3 ); +static const uint SHORT_4 = ( DT_INT16 | DT_SIZE_4 ); +static const uint USHORT_1 = ( DT_INT16 | DT_SIZE_1 | DT_UNSIGNED_BIT ); +static const uint USHORT_2 = ( DT_INT16 | DT_SIZE_2 | DT_UNSIGNED_BIT ); +static const uint USHORT_3 = ( DT_INT16 | DT_SIZE_3 | DT_UNSIGNED_BIT ); +static const uint USHORT_4 = ( DT_INT16 | DT_SIZE_4 | DT_UNSIGNED_BIT ); +static const uint INT32_1 = ( DT_INT32 | DT_SIZE_1 ); +static const uint INT32_2 = ( DT_INT32 | DT_SIZE_2 ); +static const uint INT32_3 = ( DT_INT32 | DT_SIZE_3 ); +static const uint INT32_4 = ( DT_INT32 | DT_SIZE_4 ); +static const uint UINT32_1 = ( DT_INT32 | DT_SIZE_1 | DT_UNSIGNED_BIT ); +static const uint UINT32_2 = ( DT_INT32 | DT_SIZE_2 | DT_UNSIGNED_BIT ); +static const uint UINT32_3 = ( DT_INT32 | DT_SIZE_3 | DT_UNSIGNED_BIT ); +static const uint UINT32_4 = ( DT_INT32 | DT_SIZE_4 | DT_UNSIGNED_BIT ); +static const uint FLOAT16_1 = ( DT_FLOAT16 | DT_SIZE_1 ); +static const uint FLOAT16_2 = ( DT_FLOAT16 | DT_SIZE_2 ); +static const uint FLOAT16_3 = ( DT_FLOAT16 | DT_SIZE_3 ); +static const uint FLOAT16_4 = ( DT_FLOAT16 | DT_SIZE_4 ); +static const uint UFLOAT16_1 = ( DT_FLOAT16 | DT_SIZE_1 | DT_UNSIGNED_BIT ); +static const uint UFLOAT16_2 = ( DT_FLOAT16 | DT_SIZE_2 | DT_UNSIGNED_BIT ); +static const uint UFLOAT16_3 = ( DT_FLOAT16 | DT_SIZE_3 | DT_UNSIGNED_BIT ); +static const uint UFLOAT16_4 = ( DT_FLOAT16 | DT_SIZE_4 | DT_UNSIGNED_BIT ); +static const uint FLOAT32_1 = ( DT_FLOAT32 | DT_SIZE_1 ); +static const uint FLOAT32_2 = ( DT_FLOAT32 | DT_SIZE_2 ); +static const uint FLOAT32_3 = ( DT_FLOAT32 | DT_SIZE_3 ); +static const uint FLOAT32_4 = ( DT_FLOAT32 | DT_SIZE_4 ); +static const uint UFLOAT32_1 = ( DT_FLOAT32 | DT_SIZE_1 | DT_UNSIGNED_BIT ); +static const uint UFLOAT32_2 = ( DT_FLOAT32 | DT_SIZE_2 | DT_UNSIGNED_BIT ); +static const uint UFLOAT32_3 = ( DT_FLOAT32 | DT_SIZE_3 | DT_UNSIGNED_BIT ); +static const uint UFLOAT32_4 = ( DT_FLOAT32 | DT_SIZE_4 | DT_UNSIGNED_BIT ); +static const uint BYTE_1_NORM = ( BYTE_1 | DT_NORMALIZED_BIT ); +static const uint BYTE_2_NORM = ( BYTE_2 | DT_NORMALIZED_BIT ); +static const uint BYTE_3_NORM = ( BYTE_3 | DT_NORMALIZED_BIT ); +static const uint BYTE_4_NORM = ( BYTE_4 | DT_NORMALIZED_BIT ); +static const uint UBYTE_1_NORM = ( UBYTE_1 | DT_NORMALIZED_BIT ); +static const uint UBYTE_2_NORM = ( UBYTE_2 | DT_NORMALIZED_BIT ); +static const uint UBYTE_3_NORM = ( UBYTE_3 | DT_NORMALIZED_BIT ); +static const uint UBYTE_4_NORM = ( UBYTE_4 | DT_NORMALIZED_BIT ); +static const uint SHORT_1_NORM = ( SHORT_1 | DT_NORMALIZED_BIT ); +static const uint SHORT_2_NORM = ( SHORT_2 | DT_NORMALIZED_BIT ); +static const uint SHORT_3_NORM = ( SHORT_3 | DT_NORMALIZED_BIT ); +static const uint SHORT_4_NORM = ( SHORT_4 | DT_NORMALIZED_BIT ); +static const uint USHORT_1_NORM = ( USHORT_1 | DT_NORMALIZED_BIT ); +static const uint USHORT_2_NORM = ( USHORT_2 | DT_NORMALIZED_BIT ); +static const uint USHORT_3_NORM = ( USHORT_3 | DT_NORMALIZED_BIT ); +static const uint USHORT_4_NORM = ( USHORT_4 | DT_NORMALIZED_BIT ); +static const uint DT_UNKNOWN_TYPE = 0xffFFffFFu; + +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ + +// the following assumes addresses are aligned with size of the respective datatype +// I couldn't find vertex buffer alignment rules for dx12, so I'm basing this on vulkan... +// https://registry.khronos.org/vulkan/specs/latest/html/vkspec.html#fxvertex-input-extraction +// "attribAddress must be a multiple of the size in bytes of the size of the format" + + +// Read Write Buffers + +uint ReadUInt32( RWBuffer buffer, uint address ) +{ + return buffer[( address + 0 ) >> 2]; +} + +uint2 ReadUInt32_2( RWBuffer buffer, uint address ) +{ + uint2 result; + result.x = buffer[( address + 0 ) >> 2]; + result.y = buffer[( address + 4 ) >> 2]; + return result; +} + +uint3 ReadUInt32_3( RWBuffer buffer, uint address ) +{ + uint3 result; + result.x = buffer[( address + 0 ) >> 2]; + result.y = buffer[( address + 4 ) >> 2]; + result.z = buffer[( address + 8 ) >> 2]; + return result; +} + +float ReadFloat32( RWBuffer buffer, uint address ) +{ + return asfloat( ReadUInt32( buffer, address ) ); +} + +float2 ReadFloat32_2( RWBuffer buffer, uint address ) +{ + return asfloat( ReadUInt32_2( buffer, address ) ); +} + +float3 ReadFloat32_3( RWBuffer buffer, uint address ) +{ + return asfloat( ReadUInt32_3( buffer, address ) ); +} + +uint4 ReadUInt16_4( RWBuffer buffer, uint address ) +{ + uint4 result; + uint packed0 = buffer[( address + 0 ) >> 2]; + uint packed1 = buffer[( address + 4 ) >> 2]; + result.x = packed0 & 0xFFFF; + result.y = packed0 >> 16; + result.z = packed1 & 0xFFFF; + result.w = packed1 >> 16; + return result; +} + +int4 ReadInt16_4( RWBuffer buffer, uint address ) +{ + int4 result; + uint packed0 = buffer[( address + 0 ) >> 2]; + uint packed1 = buffer[( address + 4 ) >> 2]; + result.x = asint( ( packed0 & 0xFFFF ) << 16 ) >> 16; + result.y = asint( packed0 & 0xFFFF0000 ) >> 16; + result.z = asint( ( packed1 & 0xFFFF ) << 16 ) >> 16; + result.w = asint( packed1 & 0xFFFF0000 ) >> 16; + return result; +} + +// Read Only Buffers + +uint ReadUInt16( Buffer buffer, uint address ) +{ + uint result; + uint packed = buffer.Load( address >> 2 ); + if( ( address & 3 ) == 0 ) + { + result = packed & 0xFFFF; + } + else + { + result = packed >> 16; + } + return result; +} + +uint2 ReadUInt16_2( Buffer buffer, uint address ) +{ + uint2 result; + uint packed = buffer.Load( ( address + 0 ) >> 2 ); + result.x = packed & 0xFFFF; + result.y = packed >> 16; + return result; +} + +uint3 ReadUInt16_3( Buffer buffer, uint address ) +{ + uint3 result; + uint packed0 = buffer.Load( ( address + 0 ) >> 2 ); + uint packed1 = buffer.Load( ( address + 4 ) >> 2 ); + if( ( address & 3 ) == 0 ) + { + result.x = packed0 & 0xFFFF; + result.y = packed0 >> 16; + result.z = packed1 & 0xFFFF; + } + else + { + result.x = packed0 >> 16; + result.y = packed1 & 0xFFFF; + result.z = packed1 >> 16; + } + return result; +} + +uint4 ReadUInt16_4( Buffer buffer, uint address ) +{ + uint4 result; + uint packed0 = buffer.Load( ( address + 0 ) >> 2 ); + uint packed1 = buffer.Load( ( address + 4 ) >> 2 ); + result.x = packed0 & 0xFFFF; + result.y = packed0 >> 16; + result.z = packed1 & 0xFFFF; + result.w = packed1 >> 16; + return result; +} + +int4 ReadInt16_4( Buffer buffer, uint address ) +{ + int4 result; + uint packed0 = buffer.Load( ( address + 0 ) >> 2 ); + uint packed1 = buffer.Load( ( address + 4 ) >> 2 ); + result.x = asint( ( packed0 & 0xFFFF ) << 16 ) >> 16; + result.y = asint( packed0 & 0xFFFF0000 ) >> 16; + result.z = asint( ( packed1 & 0xFFFF ) << 16 ) >> 16; + result.w = asint( packed1 & 0xFFFF0000 ) >> 16; + return result; +} + + +uint ReadUInt32( Buffer buffer, uint address ) +{ + return buffer.Load( ( address + 0 ) >> 2 ); +} + +uint2 ReadUInt32_2( Buffer buffer, uint address ) +{ + uint2 result; + result.x = buffer.Load( ( address + 0 ) >> 2 ); + result.y = buffer.Load( ( address + 4 ) >> 2 ); + return result; +} + +uint3 ReadUInt32_3( Buffer buffer, uint address ) +{ + uint3 result; + result.x = buffer.Load( ( address + 0 ) >> 2 ); + result.y = buffer.Load( ( address + 4 ) >> 2 ); + result.z = buffer.Load( ( address + 8 ) >> 2 ); + return result; +} + +float ReadFloat16( Buffer buffer, uint address ) +{ + return f16tof32( ReadUInt16( buffer, address ) ); +} + +float2 ReadFloat16_2( Buffer buffer, uint address ) +{ + return f16tof32( ReadUInt16_2( buffer, address ) ); +} + +float3 ReadFloat16_3( Buffer buffer, uint address ) +{ + return f16tof32( ReadUInt16_3( buffer, address ) ); +} + +float ReadFloat32( Buffer buffer, uint address ) +{ + return asfloat( ReadUInt32( buffer, address ) ); +} + +float2 ReadFloat32_2( Buffer buffer, uint address ) +{ + return asfloat( ReadUInt32_2( buffer, address ) ); +} + +float3 ReadFloat32_3( Buffer buffer, uint address ) +{ + return asfloat( ReadUInt32_3( buffer, address ) ); +} + +float2 ReadFloat_2( Buffer buffer, uint address, uint dataType ) +{ + if( dataType == FLOAT16_2 ) + { + return ReadFloat16_2( buffer, address ); + } + else if( dataType == FLOAT32_2 ) + { + return ReadFloat32_2( buffer, address ); + } + else + { + return 0.0.xx; + } +} + +void WriteInt16_4( RWBuffer buffer, uint address, int4 data ) +{ + uint packed0 = ( ( asuint( data.x ) & 0xFFFF ) | ( asuint( data.y ) << 16 ) ); + uint packed1 = ( ( asuint( data.z ) & 0xFFFF ) | ( asuint( data.w ) << 16 ) ); + buffer[( address + 0 ) >> 2] = packed0; + buffer[( address + 4 ) >> 2] = packed1; +} + +void WriteUInt16_4( RWBuffer buffer, uint address, uint4 data ) +{ + uint packed0 = ( data.x & 0xFFFF ) | data.y << 16; + uint packed1 = ( data.z & 0xFFFF ) | data.w << 16; + + buffer[( address + 0 ) >> 2] = packed0; + buffer[( address + 4 ) >> 2] = packed1; +} + +void WriteUInt32_2( RWBuffer buffer, uint address, uint2 data ) +{ + buffer[( address + 0 ) >> 2] = data.x; + buffer[( address + 4 ) >> 2] = data.y; +} + +void WriteUInt32_3( RWBuffer buffer, uint address, uint3 data ) +{ + buffer[( address + 0 ) >> 2] = data.x; + buffer[( address + 4 ) >> 2] = data.y; + buffer[( address + 8 ) >> 2] = data.z; +} + +void WriteUInt32_4( RWBuffer buffer, uint address, uint4 data ) +{ + buffer[( address + 0 ) >> 2] = data.x; + buffer[( address + 4 ) >> 2] = data.y; + buffer[( address + 8 ) >> 2] = data.z; + buffer[( address + 12 ) >> 2] = data.w; +} + +void WriteFloat32_2( RWBuffer buffer, uint address, float2 data ) +{ + WriteUInt32_2( buffer, address, asuint( data ) ); +} + +void WriteFloat32_3( RWBuffer buffer, uint address, float3 data ) +{ + WriteUInt32_3( buffer, address, asuint( data ) ); +} + +void WriteFloat32_4( RWBuffer buffer, uint address, float4 data ) +{ + WriteUInt32_4( buffer, address, asuint( data ) ); +} + +#endif // VERTEX_BUFFER_UTIL_FXH From eb95f65d5211cc8368241083a587336745079567 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 13:08:34 +0000 Subject: [PATCH 21/83] Fixed a crash in the shader compiler when failing to compile a RT shader --- shadercompiler/EffectCompilerDX11.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/shadercompiler/EffectCompilerDX11.cpp b/shadercompiler/EffectCompilerDX11.cpp index 9512daa97..1ad97abea 100644 --- a/shadercompiler/EffectCompilerDX11.cpp +++ b/shadercompiler/EffectCompilerDX11.cpp @@ -1789,6 +1789,13 @@ bool EffectCompilerDX11::CompileEffect( const char* source, size_t sourceLength, CComPtr pCompileResult; HRESULT hrCompilation = compiler->Compile( &sourceBuffer, arguments, argumentsSize, nullptr, IID_PPV_ARGS( &pCompileResult ) ); + if( SUCCEEDED( hrCompilation ) ) + { + if( FAILED( pCompileResult->GetStatus( &hrCompilation ) ) ) + { + hrCompilation = E_FAIL; + } + } if( FAILED( hrCompilation ) ) { From cd0388704e987c4460dda22eeef5c75f1591e081 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 13:08:54 +0000 Subject: [PATCH 22/83] Raytracing header --- CMakeLists.txt | 1 + .../SpaceScene/Raytracing/ShadowData.fxh | 64 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index acf16de35..6266bf209 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,6 +133,7 @@ endif() set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh + shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh shaders/include/Carbon/SpaceScene/DepthMap.fxh shaders/include/Carbon/SpaceScene/DynamicLighting.fxh diff --git a/shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh b/shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh new file mode 100644 index 000000000..c397f8f54 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh @@ -0,0 +1,64 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_RAYTRACING_SHADOWDATA_FXH +#define CARBON_RAYTRACING_SHADOWDATA_FXH + + +// Data passed to the shadow ray tracing shaders when rendering main sun light shadows in a "b2" constant buffer using Tr2RaytracingManager. +// Can be used by declaring a constant buffer as follows: +// cbuffer RtShadowsPerFrameBuffer: register( b2 ) { RtShadowsSunData RtShadowsPerFrame; } +struct RtShadowsSunData +{ + // The inverse projection transform of the camera for the current frame. + float4x4 ProjectionInv; + // The inverse view transform of the camera for the current frame. + float4x4 ViewInv; + // XYZ - sun direction in world space, W - sun angular size in radians. + float4 SunDirection; + + // Planet positions and radii in world space. X, Y, Z - position, W - radius. + float4 Planets[2]; + + // The resolution of the render target in pixels. + float2 Resolution; + // The current frame index, used for temporal accumulation of shadows. + uint FrameIndex; +}; + +struct RtShadowsPerLightData +{ + float4 position; // xyz - world position, w - radius + float4 color; // xyz - color, w - bits 0..15 - innerRadius (float 16), bits 16..31 - flags + float4 direction; // see next few lines: + // x bits 0..15 - direction.x (float 16), x bits 16..31 - direction.y (float 16) + // y bits 0..15 - direction.z (float 16), y bits 16..31 - projectionPlaneDistance (float 16) + // z bits 0..15 - outerAngle (float 16), z bits 16..31 - innerAngle (float 16) + // w bits 0..1 - padding, w bits 2..11 - shadowMapScale, w bits 12..21 - shadowMapOffsetX, w bits 22..31 - shadowMapOffsetY +}; + +// Data passed to the shadow ray tracing shaders when rendering main sun light shadows in a "b7" constant buffer using Tr2LightManager. +// Can be used by declaring a constant buffer as follows: +// cbuffer RtShadowsPerFrameBuffer: register( b7 ) { RtShadowsPointLightsData RtShadowsPerFrame; } +struct RtShadowsPointLightsData +{ + // The inverse projection transform of the camera for the current frame. + float4x4 ProjectionInv; + // The inverse view transform of the camera for the current frame. + float4x4 ViewInv; + + // Planet positions and radii in world space. X, Y, Z - position, W - radius. + float4 Planets[2]; + + // The resolution of the render target in pixels. + float2 Resolution; + // Number of dynamic lights in DynamicLights array. + uint NumDynamicLights; + float Padding; + + // Per-light data for dynamic lights in the scene. Up to 16 shadow casting lights are supported. + RtShadowsPerLightData DynamicLights[16]; +}; + + + +#endif \ No newline at end of file From b10121542fbf657550fa59f7fec91c1bd389fd68 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 14:13:43 +0000 Subject: [PATCH 23/83] SkinVertices shader --- CMakeLists.txt | 1 + .../Space/System/Raytracing/SkinVertices.fx | 142 ++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 shaders/Managed/Space/System/Raytracing/SkinVertices.fx diff --git a/CMakeLists.txt b/CMakeLists.txt index 6266bf209..444fc9d53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,6 +186,7 @@ set(_SHADER_SOURCES shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx + shaders/Managed/Space/System/Raytracing/SkinVertices.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Managed/Space/System/Raytracing/SkinVertices.fx b/shaders/Managed/Space/System/Raytracing/SkinVertices.fx new file mode 100644 index 000000000..23a38f899 --- /dev/null +++ b/shaders/Managed/Space/System/Raytracing/SkinVertices.fx @@ -0,0 +1,142 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../include/Carbon/System.fxh" +#include "../../../../include/Carbon/BoneTransforms.fxh" +#include "../../../../include/Carbon/VertexBufferUtil.fxh" + +StructuredBuffer InVB; +RWStructuredBuffer OutVB; + +struct AnimationData +{ + uint index; + float weight; +}; +StructuredBuffer MorphTargetAnimations ; +RWBuffer BakedMorphTargetBuffer ; + +cbuffer PerObjectVS : register( b3 ) +{ + uint VertexCount; + uint Stride; + uint PositionOffset; + uint BoneOffset; + uint BoneWeightOffset; + uint TransformOffset; + uint InVBIndex; + uint OutVBIndex; + uint OutVBOffset; + uint MorphAnimationDataOffset; + uint MorphAnimationDataCount; + uint MorphTargetPositionOffset; + uint MorphTargetStride; + uint MorphTargetSize; + uint BakedMorphTargetPositionOffset; + uint Padding2; +}; + +#if PLATFORM==PLATFORM_DX12 + +StructuredBuffer HeapView_StructuredBuffer[] +< + bool IsHeapView = true; +>; + +RWStructuredBuffer HeapView_RWStructuredBuffer[] +< + bool IsHeapView = true; +>; + +float LoadVB( uint offset ) +{ + return HeapView_StructuredBuffer[InVBIndex][offset]; +} + +void StoreVB( uint offset, float value ) +{ + HeapView_RWStructuredBuffer[OutVBIndex][offset + OutVBOffset] = value; +} + +#else + +float LoadVB( uint offset ) +{ + return InVB[offset]; +} + +void StoreVB( uint offset, float value ) +{ + OutVB[offset + OutVBOffset] = value; +} + +#endif + +uint4 FromUByte4( uint x ) +{ + return uint4( x & 0xff, ( x >> 8 ) & 0xff, ( x >> 16 ) & 0xff, x >> 24 ); +} + +[numthreads( 64, 1, 1 )] +void SkinVertices( uint3 offset : SV_DispatchThreadID ) +{ + uint vtx = offset.x; + + if( vtx < VertexCount ) + { + uint poffset = ( vtx * Stride + PositionOffset ); + float3 pos = float3( LoadVB( poffset ), LoadVB( poffset + 1 ), LoadVB( poffset + 2 ) ); + + int morphOffset = vtx * MorphTargetStride + MorphTargetPositionOffset; + float3 tmpPos = pos; + for( uint i = 0; i < MorphAnimationDataCount; i++ ) + { + AnimationData data = MorphTargetAnimations[MorphAnimationDataOffset + i]; + int offset = morphOffset + MorphTargetSize * data.index; + float3 morphPos = float3( LoadVB( offset ), LoadVB( offset + 1 ), LoadVB( offset + 2 ) ); + pos += data.weight * ( morphPos - tmpPos ); + } + + if( BakedMorphTargetPositionOffset != 0xFFFFFFFF ) + { + int bakedPosOffset = BakedMorphTargetPositionOffset; // offset in shared index/vertex buffer, but for baked morphs + bakedPosOffset += ( vtx * MorphTargetStride ) << 2; + + float3 morphPos = ReadFloat32_3( BakedMorphTargetBuffer, bakedPosOffset ); + + pos += morphPos - tmpPos; + } + + uint boffset = vtx * Stride + BoneOffset; + + float4x4 boneMatrix; + uint boneIndices = asuint( LoadVB( boffset ) ); + if( BoneWeightOffset != 0xffffffff ) + { + uint4 bones = FromUByte4( boneIndices ); + uint4 w = FromUByte4( asuint( LoadVB( vtx * Stride + BoneWeightOffset ) ) ); + float4 weights = float4( float4( w ) / 255.0 ); + + boneMatrix = + GetBoneTransform( TransformOffset + bones.x ) * weights.x + + GetBoneTransform( TransformOffset + bones.y ) * weights.y + + GetBoneTransform( TransformOffset + bones.z ) * weights.z + + GetBoneTransform( TransformOffset + bones.w ) * weights.w; + } + else + { + boneMatrix = GetBoneTransform( TransformOffset + ( boneIndices & 0xff ) ); + } + pos = mul( float4( pos, 1 ), boneMatrix ).xyz; + StoreVB( vtx * 3, pos.x ); + StoreVB( vtx * 3 + 1, pos.y ); + StoreVB( vtx * 3 + 2, pos.z ); + } +} + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 SkinVertices(); + } +} From 024c834bccefca0c9db2b6b6bdd43be79ac3d355 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 15:03:54 +0000 Subject: [PATCH 24/83] System shaders --- CMakeLists.txt | 4 + .../Managed/Space/System/ComputeLightLists.fx | 355 ++++++++++++++++++ shaders/Managed/Space/System/Denoise1D.fx | 127 +++++++ .../Managed/Space/System/DenoiseEstimate.fx | 52 +++ shaders/Managed/Space/System/EstimateNoise.fx | 84 +++++ 5 files changed, 622 insertions(+) create mode 100644 shaders/Managed/Space/System/ComputeLightLists.fx create mode 100644 shaders/Managed/Space/System/Denoise1D.fx create mode 100644 shaders/Managed/Space/System/DenoiseEstimate.fx create mode 100644 shaders/Managed/Space/System/EstimateNoise.fx diff --git a/CMakeLists.txt b/CMakeLists.txt index 444fc9d53..a9c4c0d07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,6 +187,10 @@ set(_SHADER_SOURCES shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx shaders/Managed/Space/System/Raytracing/SkinVertices.fx + shaders/Managed/Space/System/ComputeLightLists.fx + shaders/Managed/Space/System/Denoise1D.fx + shaders/Managed/Space/System/DenoiseEstimate.fx + shaders/Managed/Space/System/EstimateNoise.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Managed/Space/System/ComputeLightLists.fx b/shaders/Managed/Space/System/ComputeLightLists.fx new file mode 100644 index 000000000..c4189c855 --- /dev/null +++ b/shaders/Managed/Space/System/ComputeLightLists.fx @@ -0,0 +1,355 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../include/Carbon/System.fxh" + +#define TILE_WIDTH 16 +#define TILE_HEIGHT 16 + +Texture2D DepthMap; + +struct PerLightData +{ + float4 position; // xyz - world position, w - radius + float4 color; // xyz - color, w - bits 0..15 - innerRadius (float 16), bits 16..31 - flags + float4 direction; // see next few lines: + // x bits 0..15 - direction.x (float 16), x bits 16..31 - direction.y (float 16) + // y bits 0..15 - direction.z (float 16), y bits 16..31 - projectionPlaneDistance (float 16) + // z bits 0..15 - outerAngle (float 16), z bits 16..31 - innerAngle (float 16) + // w bits 0..1 - padding, w bits 2..11 - shadowMapScale, w bits 12..21 - shadowMapOffsetX, w bits 22..31 - shadowMapOffsetY +}; +static const uint LIGHT_FLAG_AFFECTS_PARTICLES = 1 << 17; + + + +StructuredBuffer LightBuffer; +RWStructuredBuffer LightIndices : register( u1 ) < + // These annotations are used by Tr2LightManager + int TileWidth = TILE_WIDTH; + int TileHeight = TILE_HEIGHT; + >; +RWBuffer LightIndexCount; + +struct +{ + float4x4 ViewInverse; + float4x4 ProjInverse; + float4 CameraPosition; + uint4 FrameBufferSizes; // xy - frame buffer size; zw - tiles per width and height + uint LightCount; // number of lights in LightBuffer + uint IndexBufferSize; // number of elements in LightIndices +} PerFramePS : register( c200 ); + +float3 ComputeWorldPos( float2 pixel, float depth, float2 wh ) +{ + float2 uv = pixel / wh; + float2 clipPos = uv * 2 - 1; + clipPos.y = -clipPos.y; + + float4 pos = float4( clipPos, depth, 1 ); + pos = mul( pos, PerFramePS.ProjInverse ); + pos /= pos.w; + pos = mul( pos, PerFramePS.ViewInverse ); + return pos.xyz; +} + +float GetViewDepth( float depth ) +{ + float4 p = mul( float4( 0, 0, depth, 1 ), PerFramePS.ProjInverse ); + return p.z / p.w; +} + +float ConeSphereIntersect( float3 conePosition, float3 coneDirection, float sinAngle, float3 center, float radius ) +{ + float3 d = center - conePosition; + float c = length( d ); + d = normalize( d ); + float ca = dot( d, coneDirection ); + float a = c * ca; + float b = sqrt( c * c - a * a ); + + return saturate( radius + sinAngle * c - b ); +} + + +struct Frustum +{ + float3 coneDirection; + float coneAngleSine; + float3 cameraDirection; + // near/far planes constained to depth buffer contents (for opaque lists) + float nearDepth; + float farDepth; + // near/far planes from the camera (for transparent lists) + float nearPlane; + float farPlane; +}; + +void CreateFrustum( out Frustum frustum, float2 tile, float2 depths, float transparentDepth ) +{ + float2 screenSize = (float2)PerFramePS.FrameBufferSizes.xy; + float minD = depths.x; + float maxD = depths.y; + + // near, far + float minDV = GetViewDepth( minD ); + float maxDV = GetViewDepth( maxD ); + float3 viewDir = mul( float4( 0, 0, -1, 0 ), PerFramePS.ViewInverse ).xyz; + + frustum.cameraDirection = viewDir; + frustum.nearDepth = dot( PerFramePS.ViewInverse[3].xyz, -viewDir ) + minDV; + frustum.farDepth = dot( PerFramePS.ViewInverse[3].xyz, -viewDir ) + maxDV; + frustum.nearPlane = dot( PerFramePS.ViewInverse[3].xyz, -viewDir ) + GetViewDepth( 0 ); + frustum.farPlane = dot( PerFramePS.ViewInverse[3].xyz, -viewDir ) + GetViewDepth( transparentDepth ); + + float left = tile.x * TILE_WIDTH; + float top = tile.y * TILE_HEIGHT; + float right = min( screenSize.x, left + TILE_WIDTH ); + float bottom = min( screenSize.y, top + TILE_HEIGHT ); + + float3 ful = ComputeWorldPos( float2( left, top ), maxD, screenSize ); + float3 fbr = ComputeWorldPos( float2( right, bottom ), maxD, screenSize ); + + float3 c = PerFramePS.CameraPosition.xyz; + + float3 r0 = normalize( ful - c ); + float3 r1 = normalize( fbr - c ); + + float3 dir = normalize( r0 + r1 ); + frustum.coneDirection.xyz = dir; + frustum.coneAngleSine = sqrt( 1 - dot( dir, r0 ) * dot( dir, r0 ) ); +} + +bool SphereInFrustum( float3 center, float radius, Frustum frustum, out bool transparent ) +{ + // check depth: near/far planes + float inside = 1; + + inside *= ConeSphereIntersect( PerFramePS.CameraPosition.xyz, frustum.coneDirection, frustum.coneAngleSine, center, radius ); + + float transparentInside = inside; + + inside *= saturate( radius - dot( float4( center, 1 ), float4( -frustum.cameraDirection, -frustum.nearDepth ) ) ); + inside *= saturate( radius - dot( float4( center, 1 ), float4( frustum.cameraDirection, frustum.farDepth ) ) ); + + transparentInside *= saturate( radius - dot( float4( center, 1 ), float4( -frustum.cameraDirection, -frustum.nearPlane ) ) ); + transparentInside *= saturate( radius - dot( float4( center, 1 ), float4( frustum.cameraDirection, frustum.farPlane ) ) ); + + transparent = inside <= 0; + + return inside > 0 || transparentInside > 0; +} + +bool ConeInFrustum( float3 center, float radius, float3 spotlightDir, float spotlightAngleCos, Frustum frustum, out bool transparent ) +{ + // check first for a sphere that the cone is a subsection of. + float inside = ConeSphereIntersect( PerFramePS.CameraPosition.xyz, frustum.coneDirection, frustum.coneAngleSine, center, radius ); + + // this is a very gross approxomation of the spotlight occlusion... + float cosAngle = spotlightAngleCos; + float hypotenuse = radius / cosAngle; + float sphereRadius = 0.5f * hypotenuse / cosAngle; + float3 sphereCenter = clamp( 0.0, radius, sphereRadius ) * normalize( -spotlightDir ); + + inside *= ConeSphereIntersect( PerFramePS.CameraPosition.xyz, frustum.coneDirection, frustum.coneAngleSine, center + sphereCenter, sphereRadius ); + + float transparentInside = inside; + + inside *= saturate( radius - dot( float4( center, 1 ), float4( -frustum.cameraDirection, -frustum.nearDepth ) ) ); + inside *= saturate( radius - dot( float4( center, 1 ), float4( frustum.cameraDirection, frustum.farDepth ) ) ); + + transparentInside *= saturate( radius - dot( float4( center, 1 ), float4( -frustum.cameraDirection, -frustum.nearPlane ) ) ); + transparentInside *= saturate( radius - dot( float4( center, 1 ), float4( frustum.cameraDirection, frustum.farPlane ) ) ); + + transparent = inside <= 0; + + return inside > 0 || transparentInside > 0; +} + + +groupshared uint g_tileHeadIndex; +groupshared uint g_tileTransparentHeadIndex; +groupshared uint g_tileParticleHeadIndex; +groupshared uint g_tileTransparentTailIndex; + + +void AddLight( uint light, uint heapOffset, uint indexBufferSize, bool transparent ) +{ + int iHead; + InterlockedAdd( LightIndexCount[0], 1, iHead ); + uint head = iHead; + + head = head * 2 + heapOffset; + if( head < indexBufferSize ) + { + if( transparent ) + { + uint next; + InterlockedExchange( g_tileTransparentHeadIndex, head, next ); + + LightIndices[head] = light; + LightIndices[head + 1] = next; + + if( next == 0 ) + { + g_tileTransparentTailIndex = head + 1; + } + } + else + { + uint next; + InterlockedExchange( g_tileHeadIndex, head, next ); + + LightIndices[head] = light; + LightIndices[head + 1] = next; + } + } +} + +groupshared uint g_DepthMinShared; +groupshared uint g_DepthMaxShared; +groupshared uint g_DepthMaxTransparentShared; +groupshared Frustum g_frustum; + + +[numthreads( TILE_WIDTH, TILE_HEIGHT, 1 )] +void ComputeLightLists( uint3 nGid : SV_GroupID, uint groupIndex : SV_GroupIndex, uint3 offset : SV_DispatchThreadID ) +{ + if( groupIndex == 0 ) + { + g_DepthMinShared = asuint( 1.0 ); + g_DepthMaxShared = asuint( 0.0 ); + g_DepthMaxTransparentShared = asuint( 0.0 ); + } + + GroupMemoryBarrierWithGroupSync(); + + float minD = 1; + float minDD = 1; + float maxD = 0; + float d = DepthMap[offset.xy]; + minDD = min( d, minDD ); + if( d != 0 ) + { + minD = maxD = d; + } + if( maxD != 0 ) + { + // have to add epsilon values to depth range because of precision issues when depth buffer range is too large + minD = max( 0.0, minD - 1.19e-07 ); + minDD = max( 0.0, minDD - 1.19e-07 ); + maxD = min( 1.0, maxD + 1.19e-07 ); + } + InterlockedMin( g_DepthMinShared, asuint( 1 - maxD ) ); + InterlockedMax( g_DepthMaxShared, asuint( 1 - minD ) ); + InterlockedMax( g_DepthMaxTransparentShared, asuint( 1 - minDD ) ); + + GroupMemoryBarrierWithGroupSync(); + + if( groupIndex == 0 ) + { + float2 tileDepth = float2( asfloat( g_DepthMinShared ), asfloat( g_DepthMaxShared ) ); + float tileTransparentDepth = asfloat( g_DepthMaxTransparentShared ); + + Frustum frustum; + CreateFrustum( frustum, (float2)nGid.xy, tileDepth, tileTransparentDepth ); + g_frustum = frustum; + g_tileHeadIndex = 0; + g_tileTransparentHeadIndex = 0; + g_tileTransparentTailIndex = 0; + g_tileParticleHeadIndex = 0; + } + + GroupMemoryBarrierWithGroupSync(); + + uint numLights = PerFramePS.LightCount; + uint heapOffset = PerFramePS.FrameBufferSizes.z * PerFramePS.FrameBufferSizes.w * 3; + uint indexBufferSize = PerFramePS.IndexBufferSize; + + for( uint light = groupIndex; light < numLights; light += TILE_WIDTH * TILE_HEIGHT ) + { + PerLightData lightData = LightBuffer[light]; + float4 lightPos = lightData.position; + float3 lightDir = float3( + f16tof32( asuint( lightData.direction.x ) & 0xffff ), + f16tof32( asuint( lightData.direction.x ) >> 16 ), + f16tof32( asuint( lightData.direction.y ) & 0xffff ) + ); + float spotlightAngleCos = f16tof32( asuint( lightData.direction.z ) & 0xffff ); + + bool inside = false; + bool transparent = false; + + if( spotlightAngleCos <= 0 ) + { + if( SphereInFrustum( lightPos.xyz, lightPos.w, g_frustum, transparent ) ) + { + inside = true; + } + } + else + { + if( ConeInFrustum( lightPos.xyz, lightPos.w, lightDir.xyz, spotlightAngleCos, g_frustum, transparent ) ) + { + inside = true; + } + } + if( inside ) + { + AddLight( light, heapOffset, indexBufferSize, transparent ); + uint lightFlags = asuint( lightData.color.w ); + if( lightFlags & LIGHT_FLAG_AFFECTS_PARTICLES ) + { + int iHead; + InterlockedAdd( LightIndexCount[0], 1, iHead ); + uint head = iHead; + + head = head * 2 + heapOffset; + if( head < indexBufferSize ) + { + uint next; + InterlockedExchange( g_tileParticleHeadIndex, head, next ); + + LightIndices[head] = light; + LightIndices[head + 1] = next; + } + } + } + } + + GroupMemoryBarrierWithGroupSync(); + + if( groupIndex == 0 ) + { + uint linearTile = ( nGid.x + nGid.y * PerFramePS.FrameBufferSizes.z ) * 3; + LightIndices[linearTile] = g_tileHeadIndex; + LightIndices[linearTile + 1] = g_tileTransparentHeadIndex ? g_tileTransparentHeadIndex : g_tileHeadIndex; + LightIndices[linearTile + 2] = g_tileParticleHeadIndex; + if( g_tileTransparentTailIndex != 0 ) + { + LightIndices[g_tileTransparentTailIndex] = g_tileHeadIndex; + } + } +} + +[numthreads( 1, 1, 1 )] +void ClearLightListCounter() +{ + LightIndexCount[0] = 0; +} + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 ComputeLightLists(); + } +} + + +technique Clear +{ + pass p0 + { + ComputeShader = compile cs_5_0 ClearLightListCounter(); + } +} diff --git a/shaders/Managed/Space/System/Denoise1D.fx b/shaders/Managed/Space/System/Denoise1D.fx new file mode 100644 index 000000000..10c45c413 --- /dev/null +++ b/shaders/Managed/Space/System/Denoise1D.fx @@ -0,0 +1,127 @@ +// Copyright © 2026 CCP ehf. + +#pragma permutation(NORMALS_INPUT, values=(NORMALS_INPUT_NONE, NORMALS_INPUT_NORMALS)) + +#include "../../../include/Carbon/System.fxh" + +Texture2D Source; +Texture2D NoiseEstimate; +Texture2D DepthBuffer; +Texture2D NormalBuffer; +#define LOAD_TEX( tex, coord ) ( tex[coord] ) + +float DepthWeight; +float NormalWeight; +float PlaneWeight; +float PassThrough; +int Radius; + +float2 Axis; + +float2 ClipInfo; // x - projection[3][2], y - projection[2][2] +float4x4 ProjectionInv; + +float GetLinearDepth( float d ) +{ + return ClipInfo.x / ( d + ClipInfo.y ); +} + +float3 GetViewSpacePos( float2 xy, float depth ) +{ + float2 dd = ( xy * 2.f - 1.f ); + dd.y = -dd.y; + float4 projPos = float4( dd, depth, 1 ); + float4 viewPos = mul( projPos, ProjectionInv ); + viewPos /= viewPos.w; + return viewPos.xyz; +} + +struct TapKey +{ + float csZ; + float3 csPosition; + float3 normal; +}; + +TapKey GetTapKey( int2 C, float2 fragCoord ) +{ + TapKey key = (TapKey)0; + + if( ( DepthWeight != 0.0 ) || ( PlaneWeight != 0.0 ) ) + { + key.csZ = GetLinearDepth( LOAD_TEX( DepthBuffer, C ) ); + } + + if( PlaneWeight != 0.0 ) + { + key.csPosition = GetViewSpacePos( fragCoord.xy, key.csZ ); + } + + return key; +} + +float CalculateBilateralWeight( TapKey center, TapKey tap ) +{ + float depthWeight = 1.0; + float normalWeight = 1.0; + float planeWeight = 1.0; + + if( DepthWeight != 0.0 ) + { + depthWeight = max( 0.0, 1.0 - abs( tap.csZ - center.csZ ) / max( abs( tap.csZ ), 0.01 ) * DepthWeight ); + } + + return depthWeight * normalWeight * planeWeight; +} + +float4 VS( float4 pos : POSITION ) : SV_Position +{ + return pos; +} + +float4 PS( float4 pixelPos: SV_Position ) : SV_Target +{ + int2 ssC = int2( pixelPos.xy ); + + // 3* is because the estimator produces larger values than we want to use, for visualization purposes + float gaussianRadius = saturate( NoiseEstimate[ssC] * 10.5 ) * Radius; + + float result = 0; + + // Detect sky and noiseless pixels and reject them + if( ( PassThrough != 1 ) && ( LOAD_TEX( DepthBuffer, ssC ) > 0 ) && ( gaussianRadius > 0.5 ) ) + { + float sum0 = 0; + float totalWeight = 0.0; + TapKey key = GetTapKey( ssC, pixelPos.xy ); + + for( int r = -Radius; r <= Radius; ++r ) + { + int2 tapOffset = int2( Axis * r ); + int2 tapLoc = ssC + tapOffset; + + float gaussian = exp( -pow( float( r ) / gaussianRadius, 2 ) ); + float weight = gaussian * ( ( r == 0 ) ? 1.0 : CalculateBilateralWeight( key, GetTapKey( tapLoc, pixelPos.xy + float2(tapOffset) ) ) ); + sum0 += Source[tapLoc].r * weight; + totalWeight += weight; + } + + // totalWeight >= gaussian[0], so no division by zero here + result = sum0 / totalWeight; + } + else + { + // No denoising needed + result = Source[ssC]; + } + return result; +} + +technique Main +{ + pass P0 + { + VertexShader = compile vs_5_0 VS(); + PixelShader = compile ps_5_0 PS(); + } +} diff --git a/shaders/Managed/Space/System/DenoiseEstimate.fx b/shaders/Managed/Space/System/DenoiseEstimate.fx new file mode 100644 index 000000000..1cffd6b9f --- /dev/null +++ b/shaders/Managed/Space/System/DenoiseEstimate.fx @@ -0,0 +1,52 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../include/Carbon/System.fxh" + +Texture2D Source; +SamplerState SourceSampler +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = None; + AddressU = Clamp; + AddressV = Clamp; +}; + +float4 SourceDimensions; + + +float4 VS( float4 pos : POSITION ) : SV_Position +{ + return pos; +} + + +float4 PS( float4 pixelPos: SV_Position ) : SV_Target +{ + float2 center = ( pixelPos.xy + 0.5 ) * SourceDimensions.zw; + + float dst = 0.0; + const int R = 3; + for( int2 delta = int2( -R, -R ); delta.y <= R; delta.y += 2 ) + { + for( delta.x = -R; delta.x <= R; delta.x += 2 ) + { + dst += Source.SampleLevel( SourceSampler, center + float2(delta) * SourceDimensions.zw, 0); + } + } + int samples = R + 1; + + dst *= ( 1.0 / float( samples * samples ) ); + return dst; +} + + + +technique Main +{ + pass P0 + { + VertexShader = compile vs_5_0 VS(); + PixelShader = compile ps_5_0 PS(); + } +} diff --git a/shaders/Managed/Space/System/EstimateNoise.fx b/shaders/Managed/Space/System/EstimateNoise.fx new file mode 100644 index 000000000..d97f2a25e --- /dev/null +++ b/shaders/Managed/Space/System/EstimateNoise.fx @@ -0,0 +1,84 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../include/Carbon/System.fxh" + +Texture2D Source; + +// Pixel radius for noise search. It relates to dithering +static const int NOISE_ESTIMATION_RADIUS = 3; + + +/* Sample the signal used for the noise estimation at offset from ssC */ +float Tap( int2 ssC, int2 offset ) +{ + return Source[ssC + offset].r; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Estimate desired radius from the second derivative of the signal itself in source0 relative to baseline, +// which is the noisier image because it contains shadows +float EstimateNoise( int2 ssC, float2 axis ) +{ + float v2 = Tap( ssC, int2( -NOISE_ESTIMATION_RADIUS * axis ) ); + float v1 = Tap( ssC, int2( ( 1 - NOISE_ESTIMATION_RADIUS ) * axis ) ); + + float d2mag = 0.0; + // The first two points are accounted for above + for( int r = -NOISE_ESTIMATION_RADIUS + 2; r <= NOISE_ESTIMATION_RADIUS; ++r ) + { + float v0 = Tap( ssC, int2( axis * r ) ); + + // Second derivative + float d2 = v2 - v1 * 2.0 + v0; + + d2mag += abs( d2 ); + + // Shift weights in the window + v2 = v1; + v1 = v0; + } + + // Scaled value by 1.5 *before* clamping to visualize going out of range + // It is clamped again when applied. + return clamp( sqrt( d2mag * ( 1.0 / NOISE_ESTIMATION_RADIUS ) ) * ( 1.0 / 1.5 ), 0.0, 1.0 ); +} + + +float Hash( float n ) +{ + return frac( sin( n ) * 1e4 ); +} + + +float4 VS( float4 pos : POSITION ) : SV_Position +{ + return pos; +} + + +float4 PS( float4 pixelPos : SV_Position ) : SV_Target +{ + + float angle = Hash( pixelPos.x + pixelPos.y * 1920.0 ); + + float result = 0; + const int N = 3; + for( float t = 0; t < N; ++t, angle += 3.1428 / float( N ) ) + { + float c = cos( angle ), s = sin( angle ); + result = max( EstimateNoise( int2( pixelPos.xy ), float2( c, s ) ), result ); + } + return result; +} + + + +technique Main +{ + pass P0 + { + VertexShader = compile vs_5_0 VS(); + PixelShader = compile ps_5_0 PS(); + } +} From 5379f20f5446329746678fd8263706f47dab17e7 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 16:26:04 +0000 Subject: [PATCH 25/83] Fix "static const" variables getting into the "globals" constant buffer declaration and getting sorted incorrectly --- shadercompiler/ParserUtils.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/shadercompiler/ParserUtils.cpp b/shadercompiler/ParserUtils.cpp index d42566e00..2d0f33e76 100644 --- a/shadercompiler/ParserUtils.cpp +++ b/shadercompiler/ParserUtils.cpp @@ -905,23 +905,27 @@ int GetNodeOrder( ASTNode* t ) { if( child->GetNodeType() == NT_CBUFFER ) { - return 2; + return 3; } } if( auto child = t->GetChildOrNull( 1 ) ) { if( child->GetNodeType() == NT_CBUFFER ) { - return 2; + return 3; } } if( GetRegisterType( t->GetType() ) ) { - return 2; + return 3; } else { - return 1; + if ( t->GetType().modifier == OP_CONST && t->GetType().storageClass == OP_STATIC ) + { + return 1; + } + return 2; } case NT_TECHNIQUE: return 12; @@ -985,7 +989,7 @@ void CreateGlobalsCB( ParserState& state ) continue; } } - if( !GetRegisterType( child->GetType() ) ) + if( !GetRegisterType( child->GetType() ) && !( child->GetType().modifier == OP_CONST && child->GetType().storageClass == OP_STATIC ) ) { varStart = std::min( varStart, i ); varEnd = std::max( varEnd, i ); From efd3f50adf776c62a04b2b9e7ab0960c6ecdbabf Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 16:26:24 +0000 Subject: [PATCH 26/83] Turret data --- CMakeLists.txt | 1 + .../Carbon/SpaceScene/EveTurretSet.fxh | 103 ++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/EveTurretSet.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index a9c4c0d07..3fca069ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,6 +156,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveTransform.fxh shaders/include/Carbon/SpaceScene/EveStretch2.fxh shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh + shaders/include/Carbon/SpaceScene/EveTurretSet.fxh shaders/include/Carbon/SpaceScene/FroxelFog.fxh shaders/include/Carbon/SpaceScene/GpuParticles.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh diff --git a/shaders/include/Carbon/SpaceScene/EveTurretSet.fxh b/shaders/include/Carbon/SpaceScene/EveTurretSet.fxh new file mode 100644 index 000000000..88e51fac0 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveTurretSet.fxh @@ -0,0 +1,103 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVETURRETSET_FXH +#define CARBON_EVETURRETSET_FXH + +#include "PerObjectData.fxh" +#include "../Math.fxh" + +#define EVE_MAX_TURRETS_PER_SET 24 + +struct EveTurrentSetPerObjectDataVS +{ + // X - "height" of the clipping plane for the turret set, Y - unused, Z - unused, W - unused + float4 ClipData; + // X - number of bones in the turret skeleton, Y - unused, Z - unused, W - unused + float4 TurretData; + // World transform of this object + float4x4 WorldMat; + // World transform of this object in the previous frame + float4x4 WorldMatLast; + // X - current frame offset, Y - previous frame offset + uint4 BoneOffsets; + // Turret instances translation data (XYZ - position, W - 1.0) + float4 TurretTrans[EVE_MAX_TURRETS_PER_SET]; + // Turret instances rotation quaternions + float4 TurretRot[EVE_MAX_TURRETS_PER_SET]; +}; + +struct EveTurrentSetPerObjectDataPS +{ + // Additional ship-data ( components: .x = boosterGain, .y = activation, .z = dirt level, .w = boundingsphere radius ) + float4 Shipdata; + // Clip data for disolve fx ( components: .xyz = center, .w = signed size ) + float4 Clipdata1; + // Misc data ( components: .x = signed square of clip radius 2, .yzw = unused ) + float4 Miscdata; + // SH lighting coefficients + float4 ShLighting[7]; +}; + + +EveSpaceObjectData CreateEveSpaceObjectData( EveTurrentSetPerObjectDataVS PerObjectVS ) +{ + EveSpaceObjectData pod; + pod.WorldMat = PerObjectVS.WorldMat; + pod.WorldMatLast = PerObjectVS.WorldMatLast; + pod.BoneOffsets = PerObjectVS.BoneOffsets; + + pod.Shipdata = (float4)0; + pod.Clipdata1 = (float4)0; + pod.Miscdata = (float4)0; + pod.EllipsoidRadii = (float4)0; + pod.EllipsoidCenter = (float4)0; + pod.CustomMaskMatrix[0] = IDENTITY_MATRIX; + pod.CustomMaskMatrix[1] = IDENTITY_MATRIX; + pod.CustomMaskData[0] = (float4)0; + pod.CustomMaskData[1] = (float4)0; + pod.CustomMaskMaterialIDs[0] = (float4)0; + pod.CustomMaskMaterialIDs[1] = (float4)0; + pod.CustomMaskTargets[0] = (float4)0; + pod.CustomMaskTargets[1] = (float4)0; + pod.CustomMaskClamps = (float4)0; + pod.CustomData = (float4)0; + // SH lighting coefficients + for( int i = 0; i < 7; ++i ) + { + pod.ShLighting[i] = (float4)0; + } + return pod; +} + + +EveSpaceObjectData CreateEveSpaceObjectData( EveTurrentSetPerObjectDataPS PerObjectPS ) +{ + EveSpaceObjectData pod; + pod.WorldMat = (float4x4)0; + pod.WorldMatLast = (float4x4)0; + pod.BoneOffsets = (uint4)0; + + pod.Shipdata = PerObjectPS.Shipdata; + pod.Clipdata1 = PerObjectPS.Clipdata1; + pod.Miscdata = PerObjectPS.Miscdata; + pod.EllipsoidRadii = (float4)0; + pod.EllipsoidCenter = (float4)0; + pod.CustomMaskMatrix[0] = IDENTITY_MATRIX; + pod.CustomMaskMatrix[1] = IDENTITY_MATRIX; + pod.CustomMaskData[0] = (float4)0; + pod.CustomMaskData[1] = (float4)0; + pod.CustomMaskMaterialIDs[0] = (float4)0; + pod.CustomMaskMaterialIDs[1] = (float4)0; + pod.CustomMaskTargets[0] = (float4)0; + pod.CustomMaskTargets[1] = (float4)0; + pod.CustomMaskClamps = (float4)0; + pod.CustomData = (float4)0; + // SH lighting coefficients + for( int i = 0; i < 7; ++i ) + { + pod.ShLighting[i] = PerObjectPS.ShLighting[i]; + } + return pod; +} + +#endif \ No newline at end of file From 0a494a0df4d8b4c1f13417d80186dd741ec316c3 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 09:20:14 +0000 Subject: [PATCH 27/83] Add attribution --- shaders/Managed/Space/System/Denoise1D.fx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shaders/Managed/Space/System/Denoise1D.fx b/shaders/Managed/Space/System/Denoise1D.fx index 10c45c413..684d12db2 100644 --- a/shaders/Managed/Space/System/Denoise1D.fx +++ b/shaders/Managed/Space/System/Denoise1D.fx @@ -4,6 +4,8 @@ #include "../../../include/Carbon/System.fxh" +// The code is based on https://sourceforge.net/p/g3d/code/HEAD/tree/G3D10/data-files/shader/BilateralFilter/BilateralFilter_apply.pix + Texture2D Source; Texture2D NoiseEstimate; Texture2D DepthBuffer; From db0a6550e8831e1c833df87ae51216fdae8e5285 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 09:34:44 +0000 Subject: [PATCH 28/83] EveSpherePin header --- CMakeLists.txt | 1 + .../Carbon/SpaceScene/EveSpherePin.fxh | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/EveSpherePin.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fca069ed..28c0a7503 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh shaders/include/Carbon/SpaceScene/EveChildQuad.fxh shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh + shaders/include/Carbon/SpaceScene/EveSpherePin.fxh shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh shaders/include/Carbon/SpaceScene/EveStarfield.fxh diff --git a/shaders/include/Carbon/SpaceScene/EveSpherePin.fxh b/shaders/include/Carbon/SpaceScene/EveSpherePin.fxh new file mode 100644 index 000000000..c2dbf96d3 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveSpherePin.fxh @@ -0,0 +1,25 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVESPHEREPIN_FXH +#define CARBON_EVESPHEREPIN_FXH + +// Data passed from the engine to all shader stages for EveSpherePinData draw calls in "per object" constant buffer. +struct EveSpherePinData +{ + // World transform of this pin + float4x4 WorldMat; + // XYZ - pin position, W - pin radius + float4 PinPosition; + // X - pin rotation, YZW - unused + float4 PinRotation; + // RGBA - pin color + float4 PinColor; + // X - alpha testing threshold, YZW - unused + float4 PinThreshold; + // X - sin(pin radius), Y - cos(pin radius), Z - sin(pin rotation), W - cos(pin rotation) + float4 PinRadiusPrecalc; + // XY - pin UV scale, ZW - pin UV offset + float4 PinUV; +}; + +#endif \ No newline at end of file From 162f1530cbfcb38fa1fbc6c8c6c1cc2f049c92b8 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 10:39:29 +0000 Subject: [PATCH 29/83] Morph target helpers --- CMakeLists.txt | 1 + .../Space/System/Raytracing/SkinVertices.fx | 10 +- .../Carbon/SpaceScene/MeshMorphing.fxh | 113 ++++++++++++++++++ 3 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 shaders/include/Carbon/SpaceScene/MeshMorphing.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 28c0a7503..834ddd340 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,6 +160,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveTurretSet.fxh shaders/include/Carbon/SpaceScene/FroxelFog.fxh shaders/include/Carbon/SpaceScene/GpuParticles.fxh + shaders/include/Carbon/SpaceScene/MeshMorphing.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh diff --git a/shaders/Managed/Space/System/Raytracing/SkinVertices.fx b/shaders/Managed/Space/System/Raytracing/SkinVertices.fx index 23a38f899..d3b40c3da 100644 --- a/shaders/Managed/Space/System/Raytracing/SkinVertices.fx +++ b/shaders/Managed/Space/System/Raytracing/SkinVertices.fx @@ -3,16 +3,10 @@ #include "../../../../include/Carbon/System.fxh" #include "../../../../include/Carbon/BoneTransforms.fxh" #include "../../../../include/Carbon/VertexBufferUtil.fxh" +#include "../../../../include/Carbon/SpaceScene/MeshMorphing.fxh" StructuredBuffer InVB; RWStructuredBuffer OutVB; - -struct AnimationData -{ - uint index; - float weight; -}; -StructuredBuffer MorphTargetAnimations ; RWBuffer BakedMorphTargetBuffer ; cbuffer PerObjectVS : register( b3 ) @@ -90,7 +84,7 @@ void SkinVertices( uint3 offset : SV_DispatchThreadID ) float3 tmpPos = pos; for( uint i = 0; i < MorphAnimationDataCount; i++ ) { - AnimationData data = MorphTargetAnimations[MorphAnimationDataOffset + i]; + MorphTargetAnimationData data = MorphTargetAnimations[MorphAnimationDataOffset + i]; int offset = morphOffset + MorphTargetSize * data.index; float3 morphPos = float3( LoadVB( offset ), LoadVB( offset + 1 ), LoadVB( offset + 2 ) ); pos += data.weight * ( morphPos - tmpPos ); diff --git a/shaders/include/Carbon/SpaceScene/MeshMorphing.fxh b/shaders/include/Carbon/SpaceScene/MeshMorphing.fxh new file mode 100644 index 000000000..41c566326 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/MeshMorphing.fxh @@ -0,0 +1,113 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_MESHMORPHING_FXH +#define CARBON_MESHMORPHING_FXH + + +#include "../VertexBufferUtil.fxh" + +Buffer SharedIndexVertexBuffer ; + +struct MorphTargetAnimationData +{ + uint index; + float weight; +}; +StructuredBuffer MorphTargetAnimations ; + +// the following assumes that all morphed objects will be preprocessed and hence packed +// it also assumes no delta compression is being used +#define MORPH_TARGERT_CONSTANT_SIZE 24 +struct MorphTargetGeometryConstants +{ + uint vertexBufferStride; + uint positionOffset; + uint positionType; + uint tangentOffset; + uint tangentType; + uint vertexCount; +}; + +MorphTargetGeometryConstants GetMorphTargetGeometryConstants( uint4 MorphTargetData ) +{ + MorphTargetGeometryConstants constants; + constants.vertexBufferStride = ReadUInt32( SharedIndexVertexBuffer, MorphTargetData.x + 0 ); + constants.positionOffset = ReadUInt32( SharedIndexVertexBuffer, MorphTargetData.x + 4 ); + constants.positionType = ReadUInt32( SharedIndexVertexBuffer, MorphTargetData.x + 8 ); + constants.tangentOffset = ReadUInt32( SharedIndexVertexBuffer, MorphTargetData.x + 12 ); + constants.tangentType = ReadUInt32( SharedIndexVertexBuffer, MorphTargetData.x + 16 ); + constants.vertexCount = ReadUInt32( SharedIndexVertexBuffer, MorphTargetData.x + 20 ); + + return constants; +} + +void ProcessMorphs( MorphTargetGeometryConstants constants, uint vertexID, uint4 MorphTargetData, inout float3 vtxPos, inout float4 vtxPackedTangent ) +{ + float normalSign = vtxPackedTangent.w; + vtxPackedTangent.w = sqrt( saturate( 1. - dot( vtxPackedTangent.xyz, vtxPackedTangent.xyz ) ) ); + + int dataOffset = MORPH_TARGERT_CONSTANT_SIZE; // MorphTargetGeometryConstants size + dataOffset += MorphTargetData.x; // offset in shared index/vertex buffer + dataOffset += vertexID * constants.vertexBufferStride; + + int posOffset = dataOffset + constants.positionOffset; + int tangentOffset = dataOffset + constants.tangentOffset; + + int morphTargetSize = constants.vertexCount * constants.vertexBufferStride; + + float3 tempPos = vtxPos; + float4 tempPackedTangent = vtxPackedTangent; + for( uint i = 0; i < MorphTargetData.z; i++ ) + { + MorphTargetAnimationData data = MorphTargetAnimations[MorphTargetData.y + i]; + int morphTargetIndex = data.index; + int offset = morphTargetSize * morphTargetIndex; + + float3 pos = ReadFloat32_3( SharedIndexVertexBuffer, posOffset + offset ); + float4 packedTangent = float4( ReadInt16_4( SharedIndexVertexBuffer, tangentOffset + offset ) ); + packedTangent = max( packedTangent * ( 1. / 32767.0f ), float4( -1.0f, -1.0f, -1.0f, -1.0f ) ); + packedTangent.w = sqrt( saturate( 1. - dot( packedTangent.xyz, packedTangent.xyz ) ) ); + + [flatten] + if( dot( packedTangent, tempPackedTangent ) < 0. ) + { + packedTangent = -packedTangent; + } + + vtxPos += data.weight * ( pos - tempPos ); + vtxPackedTangent += data.weight * ( packedTangent - tempPackedTangent ); + } + vtxPackedTangent = normalize( vtxPackedTangent ); + + [flatten] + if( vtxPackedTangent.w < 0. ) + { + vtxPackedTangent = -vtxPackedTangent; + } + + vtxPackedTangent.w = normalSign; +} + +void ProcessMorphs( MorphTargetGeometryConstants constants, uint vertexID, uint4 MorphTargetData, inout float3 vtxPos ) +{ + int dataOffset = MORPH_TARGERT_CONSTANT_SIZE; // MorphTargetGeometryConstants size + dataOffset += MorphTargetData.x; // offset in shared index/vertex buffer + dataOffset += vertexID * constants.vertexBufferStride; + + int posOffset = dataOffset + constants.positionOffset; + + int morphTargetSize = constants.vertexCount * constants.vertexBufferStride; + + float3 tempPos = vtxPos; + for( uint i = 0; i < MorphTargetData.z; i++ ) + { + MorphTargetAnimationData data = MorphTargetAnimations[MorphTargetData.y + i]; + int morphTargetIndex = data.index; + int offset = morphTargetSize * morphTargetIndex; + float3 pos = ReadFloat32_3( SharedIndexVertexBuffer, posOffset + offset ); + vtxPos += data.weight * ( pos - tempPos ); + } +} + + +#endif \ No newline at end of file From 3b6c4a322673afe42dd55d039214abe2862fe0ba Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 11:09:55 +0000 Subject: [PATCH 30/83] Utility shaders --- CMakeLists.txt | 17 ++++ shaders/Managed/Utility/BillboardNoZ.fx | 72 ++++++++++++++++ shaders/Managed/Utility/BillboardPicking.fx | 58 +++++++++++++ shaders/Managed/Utility/Debug.fx | 59 +++++++++++++ shaders/Managed/Utility/DebugLine.fx | 59 +++++++++++++ shaders/Managed/Utility/DebugPrimitive.fx | 85 +++++++++++++++++++ .../Managed/Utility/DebugPrimitivePicking.fx | 50 +++++++++++ shaders/Managed/Utility/Lines.fxh | 42 +++++++++ shaders/Managed/Utility/LinesNoZ.fx | 20 +++++ shaders/Managed/Utility/LinesRotationTool.fx | 59 +++++++++++++ .../Managed/Utility/LinesRotationToolLH.fx | 59 +++++++++++++ shaders/Managed/Utility/LinesWithZ.fx | 20 +++++ shaders/Managed/Utility/PerFrameVSData.fxh | 18 ++++ shaders/Managed/Utility/PrimitivePicking.fx | 56 ++++++++++++ .../Utility/SolidNoLightNoCullWithZ.fx | 48 +++++++++++ shaders/Managed/Utility/Solids.fxh | 52 ++++++++++++ shaders/Managed/Utility/SolidsNoZ.fx | 20 +++++ shaders/Managed/Utility/SolidsWithZ.fx | 20 +++++ 18 files changed, 814 insertions(+) create mode 100644 shaders/Managed/Utility/BillboardNoZ.fx create mode 100644 shaders/Managed/Utility/BillboardPicking.fx create mode 100644 shaders/Managed/Utility/Debug.fx create mode 100644 shaders/Managed/Utility/DebugLine.fx create mode 100644 shaders/Managed/Utility/DebugPrimitive.fx create mode 100644 shaders/Managed/Utility/DebugPrimitivePicking.fx create mode 100644 shaders/Managed/Utility/Lines.fxh create mode 100644 shaders/Managed/Utility/LinesNoZ.fx create mode 100644 shaders/Managed/Utility/LinesRotationTool.fx create mode 100644 shaders/Managed/Utility/LinesRotationToolLH.fx create mode 100644 shaders/Managed/Utility/LinesWithZ.fx create mode 100644 shaders/Managed/Utility/PerFrameVSData.fxh create mode 100644 shaders/Managed/Utility/PrimitivePicking.fx create mode 100644 shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx create mode 100644 shaders/Managed/Utility/Solids.fxh create mode 100644 shaders/Managed/Utility/SolidsNoZ.fx create mode 100644 shaders/Managed/Utility/SolidsWithZ.fx diff --git a/CMakeLists.txt b/CMakeLists.txt index 834ddd340..4f535920d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,6 +194,23 @@ set(_SHADER_SOURCES shaders/Managed/Space/System/Denoise1D.fx shaders/Managed/Space/System/DenoiseEstimate.fx shaders/Managed/Space/System/EstimateNoise.fx + shaders/Managed/Utility/BillboardNoZ.fx + shaders/Managed/Utility/BillboardPicking.fx + shaders/Managed/Utility/Debug.fx + shaders/Managed/Utility/DebugLine.fx + shaders/Managed/Utility/DebugPrimitive.fx + shaders/Managed/Utility/DebugPrimitivePicking.fx + shaders/Managed/Utility/Lines.fxh + shaders/Managed/Utility/LinesNoZ.fx + shaders/Managed/Utility/LinesRotationTool.fx + shaders/Managed/Utility/LinesRotationToolLH.fx + shaders/Managed/Utility/LinesWithZ.fx + shaders/Managed/Utility/PerFrameVSData.fxh + shaders/Managed/Utility/PrimitivePicking.fx + shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx + shaders/Managed/Utility/Solids.fxh + shaders/Managed/Utility/SolidsNoZ.fx + shaders/Managed/Utility/SolidsWithZ.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Managed/Utility/BillboardNoZ.fx b/shaders/Managed/Utility/BillboardNoZ.fx new file mode 100644 index 000000000..76370afb2 --- /dev/null +++ b/shaders/Managed/Utility/BillboardNoZ.fx @@ -0,0 +1,72 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +Texture2D TextureMap +< + bool SasUiVisible = true; +>; + +SamplerState LinearSampler +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; + +struct SolidVertex +{ + float3 position : POSITION; + float4 color : TEXCOORD0; +}; + +struct SolidVertexPS +{ + float4 position : POSITION; + float2 texCoord : TEXCOORD0; + float4 color : TEXCOORD1; +}; + +SolidVertexPS SpriteVS( SolidVertex inVtx ) +{ + SolidVertexPS outVtx; + + float3 posWorld = mul( float4( 0, 0, 0, 1 ), PerObjectVS.WorldMat ).xyz; + float3 posView = mul( float4( posWorld, 1.0f ), PerFrameVS.ViewMat ).xyz; + posView += mul( inVtx.position, (float3x3)PerObjectVS.WorldMat ); + outVtx.position = mul( float4( posView, 1.0f ), PerFrameVS.ProjectionMat ); + outVtx.color = inVtx.color; + outVtx.texCoord = inVtx.position.xy * 0.5 + 0.5; + + return outVtx; +} + +float4 SpritePS( SolidVertexPS inVtx ) : SV_Target +{ + return inVtx.color * TextureMap.Sample( LinearSampler, inVtx.texCoord ); +} + +technique Main +{ + pass P0 + { + ZWriteEnable = False; + ZEnable = False; + AlphaBlendEnable = True; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + CullMode = NONE; + + VertexShader = compile vs_5_0 SpriteVS(); + PixelShader = compile ps_5_0 SpritePS(); + } +} \ No newline at end of file diff --git a/shaders/Managed/Utility/BillboardPicking.fx b/shaders/Managed/Utility/BillboardPicking.fx new file mode 100644 index 000000000..589212d64 --- /dev/null +++ b/shaders/Managed/Utility/BillboardPicking.fx @@ -0,0 +1,58 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +struct SolidVertex +{ + float3 position : POSITION; +}; + +struct SolidVertexPS +{ + float4 position : POSITION; + float2 texCoord : TEXCOORD0; +}; + +// selected.AddTriangle((-1, -1, 0), (1,1,1,1), (1, -1, 0), (1,1,1,1), (-1, 1, 0), (1,1,1,1)) + +SolidVertexPS SpriteVS( SolidVertex inVtx ) +{ + SolidVertexPS outVtx; + + float3 posWorld = mul( float4( 0, 0, 0, 1 ), PerObjectVS.WorldMat ).xyz; + float3 posView = mul( float4( posWorld, 1.0f ), PerFrameVS.ViewMat ).xyz; + posView += mul( inVtx.position, (float3x3)PerObjectVS.WorldMat ); + outVtx.position = mul( float4( posView, 1.0f ), PerFrameVS.ProjectionMat ); + outVtx.texCoord = inVtx.position.xy * 0.5 + 0.5; + + return outVtx; +} + +float objectId = 0; +float areaId = 0; + +float4 SpritePS( SolidVertexPS inVtx ) : SV_Target +{ + return float4( areaId + 1, objectId + 1, 1, 0 ); +} + +technique Main +{ + pass P0 + { + ZWriteEnable = TRUE; + ZEnable = TRUE; + ZFunc = LESSEQUAL; + AlphaBlendEnable = FALSE; + AlphaTestEnable = FALSE; + + VertexShader = compile vs_5_0 SpriteVS(); + PixelShader = compile ps_5_0 SpritePS(); + } +} \ No newline at end of file diff --git a/shaders/Managed/Utility/Debug.fx b/shaders/Managed/Utility/Debug.fx new file mode 100644 index 000000000..0b412a43f --- /dev/null +++ b/shaders/Managed/Utility/Debug.fx @@ -0,0 +1,59 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" + +float4x4 WorldMat; +float4x4 ViewProjectionMat; + +// ------------------------------------------------------------- +// Output channels +// ------------------------------------------------------------- +struct VS_OUTPUT +{ + float4 pos : SV_Position; + float4 col : COLOR0; +}; + +// ------------------------------------------------------------- +// vertex shader function (input channels) +// ------------------------------------------------------------- +VS_OUTPUT PerVertex(float3 pos : POSITION, float4 col : COLOR0 ) +{ + VS_OUTPUT Out = (VS_OUTPUT)0; + + float4 worldpos = mul( float4( pos, 1.0f), WorldMat ); + Out.pos = mul( worldpos, ViewProjectionMat ); + Out.col = col; + return Out; +} + + +// ------------------------------------------------------------- +// Pixel Shader (input channels):output channel +// ------------------------------------------------------------- +float4 PerPixel( VS_OUTPUT inVtx ) : SV_Target +{ + return inVtx.col; +} + + +// ------------------------------------------------------------- +// +// ------------------------------------------------------------- +technique Main +{ + pass P0 + { + ZEnable = FALSE; + ZWriteEnable = TRUE; + ZFunc = LESSEQUAL; + CullMode = NONE; + AlphaBlendEnable = TRUE; + AlphaTestEnable = FALSE; + FillMode = SOLID; + + // compile shaders + VertexShader = compile vs_5_0 PerVertex(); + PixelShader = compile ps_5_0 PerPixel(); + } +} diff --git a/shaders/Managed/Utility/DebugLine.fx b/shaders/Managed/Utility/DebugLine.fx new file mode 100644 index 000000000..caa213cb3 --- /dev/null +++ b/shaders/Managed/Utility/DebugLine.fx @@ -0,0 +1,59 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" + +float4x4 WorldMat; +float4x4 ViewProjectionMat; + +// ------------------------------------------------------------- +// Output channels +// ------------------------------------------------------------- +struct VS_OUTPUT +{ + float4 pos : SV_Position; + float4 col : COLOR0; +}; + +// ------------------------------------------------------------- +// vertex shader function (input channels) +// ------------------------------------------------------------- +VS_OUTPUT PerVertex( float3 pos : POSITION, float4 col : COLOR0 ) +{ + VS_OUTPUT Out = (VS_OUTPUT)0; + + float4 worldpos = mul( float4( pos, 1.0f ), WorldMat ); + Out.pos = mul( worldpos, ViewProjectionMat ); + Out.col = col; + return Out; +} + + +// ------------------------------------------------------------- +// Pixel Shader (input channels):output channel +// ------------------------------------------------------------- +float4 PerPixel( VS_OUTPUT inVtx ) : SV_Target +{ + return inVtx.col; +} + + +// ------------------------------------------------------------- +// +// ------------------------------------------------------------- +technique Main +{ + pass P0 + { + ZEnable = FALSE; + ZWriteEnable = FALSE; + ZFunc = LESSEQUAL; + CullMode = NONE; + AlphaBlendEnable = FALSE; + AlphaTestEnable = FALSE; + FillMode = Wireframe; + + // compile shaders + VertexShader = compile vs_5_0 PerVertex(); + PixelShader = compile ps_5_0 PerPixel(); + } +} \ No newline at end of file diff --git a/shaders/Managed/Utility/DebugPrimitive.fx b/shaders/Managed/Utility/DebugPrimitive.fx new file mode 100644 index 000000000..d67d7cd65 --- /dev/null +++ b/shaders/Managed/Utility/DebugPrimitive.fx @@ -0,0 +1,85 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" +#include "../../include/Carbon/SpaceScene/PerSceneData.fxh" + +struct PerFrameVSData +{ + // matrices + float4x4 ViewInverseTransposeMat; + float4x4 ViewProjectionMat; +} PerFrameVS : register( PERFRAME_VS_STARTREGISTER ); + +EveSpaceSceneDataPS PerFramePS : register( PERFRAME_PS_STARTREGISTER ); + +struct AppDebugVtx +{ + float3 position : POSITION; + float3 normal : NORMAL; + float4 zPassColor : COLOR1; + float4 zFailColor : COLOR2; +}; + +struct DebugVtx +{ + float4 position : SV_Position; + float3 normal : TEXCOORD0; + float4 color : TEXCOORD1; + float4 colorBack : TEXCOORD2; +}; + +Texture2D DepthMap ; +sampler DepthMapSamplerClamp = sampler_state +{ + MinFilter = Point; + MagFilter = Point; + MipFilter = None; + AddressU = Clamp; + AddressV = Clamp; +}; + + +float Get3dUISceneDepthOcclusion( float4 clipPos ) +{ + float depth = clipPos.z; + float sceneDepth = DepthMap.Sample( DepthMapSamplerClamp, clipPos.xy / PerFramePS.RenderTargetData.xy ).r; + return (float)( depth > sceneDepth ); +} + + +DebugVtx DebugVS( AppDebugVtx inVtx, uniform bool front ) +{ + DebugVtx outVtx; + outVtx.position = mul( float4( inVtx.position, 1 ), PerFrameVS.ViewProjectionMat ); + outVtx.normal = inVtx.normal; + outVtx.color = inVtx.zPassColor; + outVtx.colorBack = inVtx.zFailColor; + return outVtx; +} + +float4 DebugPS( DebugVtx inVtx ) : SV_Target +{ + float4 color = lerp( inVtx.colorBack, inVtx.color, Get3dUISceneDepthOcclusion( inVtx.position ) ); + color = color.bgra; + if( any( inVtx.normal != 0 ) ) + { + float3 normal = normalize( inVtx.normal ); + float diffuse = lerp( 0.3, 1, saturate( dot( normal, 1 ) ) ); + color.rgb *= diffuse; + } + return color; +} + +technique Main +{ + pass P0 + { + ZFunc = LessEqual; + AlphaTestEnable = False; + AlphaBlendEnable = True; + SrcBlend = SrcAlpha; + DestBlend = InvSrcAlpha; + VertexShader = compile vs_3_0 DebugVS( true ); + PixelShader = compile ps_3_0 DebugPS(); + } +} \ No newline at end of file diff --git a/shaders/Managed/Utility/DebugPrimitivePicking.fx b/shaders/Managed/Utility/DebugPrimitivePicking.fx new file mode 100644 index 000000000..6bcd29ef3 --- /dev/null +++ b/shaders/Managed/Utility/DebugPrimitivePicking.fx @@ -0,0 +1,50 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" + +struct PerFrameVSData +{ + // matrices + float4x4 ViewInverseTransposeMat; + float4x4 ViewProjectionMat; +} PerFrameVS : register( PERFRAME_VS_STARTREGISTER ); + +struct AppDebugVtx +{ + float3 position : POSITION; + float2 index : TEXCOORD0; +}; + +struct DebugVtx +{ + float4 position : SV_Position; + float4 output : TEXCOORD0; +}; + + +DebugVtx DebugVS( AppDebugVtx inVtx ) +{ + DebugVtx outVtx; + outVtx.position = mul( float4( inVtx.position, 1 ), PerFrameVS.ViewProjectionMat ); + outVtx.output = float4( inVtx.index, outVtx.position.zw ); + return outVtx; +} + +float4 DebugPS( DebugVtx inVtx ) : SV_Target +{ + return float4( inVtx.output.xy, inVtx.output.z / inVtx.output.w, 0 ); +} + +technique Main +{ + pass P0 + { + ZEnable = True; + ZWriteEnable = True; + ZFunc = GreaterEqual; + AlphaTestEnable = False; + AlphaBlendEnable = False; + VertexShader = compile vs_3_0 DebugVS(); + PixelShader = compile ps_3_0 DebugPS(); + } +} \ No newline at end of file diff --git a/shaders/Managed/Utility/Lines.fxh b/shaders/Managed/Utility/Lines.fxh new file mode 100644 index 000000000..d641820d9 --- /dev/null +++ b/shaders/Managed/Utility/Lines.fxh @@ -0,0 +1,42 @@ +// Copyright © 2026 CCP ehf. + +#ifndef LINES_FXH +#define LINES_FXH + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +struct LineVertex +{ + float3 position : POSITION; + float4 color : TEXCOORD0; +}; + +struct LineVertexPS +{ + float4 position : SV_Position; + float4 color : TEXCOORD0; +}; + +LineVertexPS SpriteVS( LineVertex inVtx ) +{ + LineVertexPS outVtx; + + const float4 posWorld = mul( float4( inVtx.position, 1.0f ), PerObjectVS.WorldMat ); + outVtx.position = mul( posWorld, PerFrameVS.ViewProjectionMat ); + outVtx.color = inVtx.color; + + return outVtx; +} + +float4 SpritePS( LineVertexPS inVtx ) : COLOR +{ + return inVtx.color; +} + +#endif \ No newline at end of file diff --git a/shaders/Managed/Utility/LinesNoZ.fx b/shaders/Managed/Utility/LinesNoZ.fx new file mode 100644 index 000000000..3e949afdb --- /dev/null +++ b/shaders/Managed/Utility/LinesNoZ.fx @@ -0,0 +1,20 @@ +// Copyright © 2026 CCP ehf. + +#include "Lines.fxh" + +technique Main +{ + pass P0 + { + ZWriteEnable = TRUE; + ZEnable = FALSE; + + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + VertexShader = compile vs_3_0 SpriteVS(); + PixelShader = compile ps_3_0 SpritePS(); + } +} diff --git a/shaders/Managed/Utility/LinesRotationTool.fx b/shaders/Managed/Utility/LinesRotationTool.fx new file mode 100644 index 000000000..6b8c04c72 --- /dev/null +++ b/shaders/Managed/Utility/LinesRotationTool.fx @@ -0,0 +1,59 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +struct LineVertex +{ + float3 position : POSITION; + float4 color : TEXCOORD0; +}; + +struct LineVertexPS +{ + float4 position : SV_Position; + float4 color : TEXCOORD0; +}; + +LineVertexPS SpriteVS( LineVertex inVtx ) +{ + LineVertexPS outVtx; + const float4 posCenter = mul( float4( 0.0, 0.0, 0.0, 1.0 ), PerObjectVS.WorldMat ); + const float4 normal = float4( PerFrameVS.ViewMat[0][2], PerFrameVS.ViewMat[1][2], PerFrameVS.ViewMat[2][2], 1.0 ); + + const float4 posWorld = mul( float4( inVtx.position, 1.0f ), PerObjectVS.WorldMat ); + outVtx.position = mul( posWorld, PerFrameVS.ViewProjectionMat ); + outVtx.color = inVtx.color; + if( dot( posWorld - posCenter, normal ) < 0.0 ) + { + outVtx.color.a = 0.0; + } + + return outVtx; +} +float4 SpritePS( LineVertexPS inVtx ) : SV_Target +{ + return inVtx.color; +} + +technique Main +{ + pass P0 + { + ZWriteEnable = FALSE; + ZEnable = FALSE; + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + + VertexShader = compile vs_3_0 SpriteVS(); + PixelShader = compile ps_3_0 SpritePS(); + } +} diff --git a/shaders/Managed/Utility/LinesRotationToolLH.fx b/shaders/Managed/Utility/LinesRotationToolLH.fx new file mode 100644 index 000000000..80228ccef --- /dev/null +++ b/shaders/Managed/Utility/LinesRotationToolLH.fx @@ -0,0 +1,59 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +struct LineVertex +{ + float3 position : POSITION; + float4 color : TEXCOORD0; +}; + +struct LineVertexPS +{ + float4 position : SV_Position; + float4 color : TEXCOORD0; +}; + +LineVertexPS SpriteVS( LineVertex inVtx ) +{ + LineVertexPS outVtx; + const float4 posCenter = mul( float4( 0.0, 0.0, 0.0, 1.0 ), PerObjectVS.WorldMat ); + const float4 normal = float4( PerFrameVS.ViewMat[0][2], PerFrameVS.ViewMat[1][2], PerFrameVS.ViewMat[2][2], 1.0 ); + + const float4 posWorld = mul( float4( inVtx.position, 1.0f ), PerObjectVS.WorldMat ); + outVtx.position = mul( posWorld, PerFrameVS.ViewProjectionMat ); + outVtx.color = inVtx.color; + if( dot( posWorld - posCenter, normal ) > 0.0 ) + { + outVtx.color.a = 0.0; + } + + return outVtx; +} +float4 SpritePS( LineVertexPS inVtx ) : SV_Target +{ + return inVtx.color; +} + +technique Main +{ + pass P0 + { + ZWriteEnable = FALSE; + ZEnable = FALSE; + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + + VertexShader = compile vs_3_0 SpriteVS(); + PixelShader = compile ps_3_0 SpritePS(); + } +} diff --git a/shaders/Managed/Utility/LinesWithZ.fx b/shaders/Managed/Utility/LinesWithZ.fx new file mode 100644 index 000000000..29fdb3356 --- /dev/null +++ b/shaders/Managed/Utility/LinesWithZ.fx @@ -0,0 +1,20 @@ +// Copyright © 2026 CCP ehf. + +#include "Lines.fxh" + +technique Main +{ + pass P0 + { + ZWriteEnable = TRUE; + ZEnable = TRUE; + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + DepthBias = 0.001; + VertexShader = compile vs_3_0 SpriteVS(); + PixelShader = compile ps_3_0 SpritePS(); + } +} diff --git a/shaders/Managed/Utility/PerFrameVSData.fxh b/shaders/Managed/Utility/PerFrameVSData.fxh new file mode 100644 index 000000000..22ade7000 --- /dev/null +++ b/shaders/Managed/Utility/PerFrameVSData.fxh @@ -0,0 +1,18 @@ +// Copyright © 2026 CCP ehf. + +#ifndef PERFRAMEVSDATA_FXH +#define PERFRAMEVSDATA_FXH + +#include "../../include/Carbon/System.fxh" + +struct PerFrameVSData +{ + float4x4 ViewInverseTransposeMat; + float4 SunWorldDir; + float4 SceneFogColor; + float4x4 ViewProjectionMat; + float4x4 ViewMat; + float4x4 ProjectionMat; +} PerFrameVS : register( PERFRAME_VS_STARTREGISTER ); + +#endif \ No newline at end of file diff --git a/shaders/Managed/Utility/PrimitivePicking.fx b/shaders/Managed/Utility/PrimitivePicking.fx new file mode 100644 index 000000000..d5bc0592a --- /dev/null +++ b/shaders/Managed/Utility/PrimitivePicking.fx @@ -0,0 +1,56 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +float objectId = 0; +float areaId = 0; + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +struct PickingAppVtx +{ + float3 pos : POSITION; + float2 tex : TEXCOORD0; +}; + +struct StandardShaderVtx +{ + float4 posClip : SV_Position; + float4 eyeDirWorld : TEXCOORD0; + float4 texcoord01 : TEXCOORD1; +}; + +float4 PickingPS( StandardShaderVtx inVtx ) : SV_Target +{ + return float4( areaId + 1, objectId + 1, inVtx.eyeDirWorld.w, 0 ); +} + +StandardShaderVtx PickingVS( PickingAppVtx inVtx ) +{ + StandardShaderVtx outVtx = (StandardShaderVtx)0; + + float4 posWorld = mul( float4( inVtx.pos, 1.0f ), PerObjectVS.WorldMat ); + outVtx.posClip = mul( posWorld, PerFrameVS.ViewProjectionMat ); + outVtx.eyeDirWorld = mul( posWorld, PerFrameVS.ViewMat ); + outVtx.texcoord01 = float4( inVtx.tex, 0, 0 ); + return outVtx; +} + +technique Main +{ + pass P0 + { + ZWriteEnable = TRUE; + ZEnable = TRUE; + ZFunc = LESSEQUAL; + AlphaBlendEnable = FALSE; + AlphaTestEnable = FALSE; + + VertexShader = compile vs_3_0 PickingVS(); + PixelShader = compile ps_3_0 PickingPS(); + } +} diff --git a/shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx b/shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx new file mode 100644 index 000000000..bd19b9ed9 --- /dev/null +++ b/shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx @@ -0,0 +1,48 @@ +// Copyright © 2026 CCP ehf. + +#include "Solids.fxh" + +struct SolidColorVertex +{ + float3 position : POSITION; + float4 color : TEXCOORD0; +}; + +struct SolidColorVertexPS +{ + float4 position : SV_Position; + float4 color : TEXCOORD0; +}; + +SolidColorVertexPS SpriteSolidColorVS( SolidColorVertex inVtx ) +{ + SolidColorVertexPS outVtx; + + const float4 posWorld = mul( float4( inVtx.position, 1.0f ), PerObjectVS.WorldMat ); + outVtx.position = mul( posWorld, PerFrameVS.ViewProjectionMat ); + + outVtx.color = inVtx.color; + return outVtx; +} + +float4 SpriteSolidColorPS( SolidColorVertexPS inVtx ) : SV_Target +{ + return inVtx.color; +} + +technique Main +{ + pass P0 + { + ZWriteEnable = FALSE; + ZEnable = TRUE; + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + CullMode = NONE; + VertexShader = compile vs_3_0 SpriteSolidColorVS(); + PixelShader = compile ps_3_0 SpriteSolidColorPS(); + } +} diff --git a/shaders/Managed/Utility/Solids.fxh b/shaders/Managed/Utility/Solids.fxh new file mode 100644 index 000000000..b5fd50c2a --- /dev/null +++ b/shaders/Managed/Utility/Solids.fxh @@ -0,0 +1,52 @@ +// Copyright © 2026 CCP ehf. + +#ifndef SOLIDS_FXH +#define SOLIDS_FXH + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +struct SolidVertex +{ + float3 position : POSITION; + float3 normal : NORMAL; + float4 color : TEXCOORD0; +}; + +struct SolidVertexPS +{ + float4 position : SV_Position; + float4 color : TEXCOORD0; + float3 viewNormal : TEXCOORD1; + float3 vtxNormal : TEXCOORD2; +}; + +SolidVertexPS SpriteVS( SolidVertex inVtx ) +{ + SolidVertexPS outVtx; + + const float4 posWorld = mul( float4( inVtx.position, 1.0f ), PerObjectVS.WorldMat ); + outVtx.position = mul( posWorld, PerFrameVS.ViewProjectionMat ); + const float4 normal = float4( PerFrameVS.ViewMat[0][2], PerFrameVS.ViewMat[1][2], PerFrameVS.ViewMat[2][2], 0.0 ); + + outVtx.color = inVtx.color; + outVtx.vtxNormal = normalize( mul( float4( inVtx.normal, 0.0f ), PerObjectVS.WorldMat ).xyz ); + outVtx.viewNormal = normal.xyz; + + return outVtx; +} + +float4 SpritePS( SolidVertexPS inVtx ) : SV_Target +{ + float alpha = inVtx.color.a; + float4 color = inVtx.color * saturate( dot( inVtx.vtxNormal, inVtx.viewNormal ) ); + color.a = alpha; + return color; +} + +#endif \ No newline at end of file diff --git a/shaders/Managed/Utility/SolidsNoZ.fx b/shaders/Managed/Utility/SolidsNoZ.fx new file mode 100644 index 000000000..6e9eea3c7 --- /dev/null +++ b/shaders/Managed/Utility/SolidsNoZ.fx @@ -0,0 +1,20 @@ +// Copyright © 2026 CCP ehf. + +#include "Solids.fxh" + +technique Main +{ + pass P0 + { + ZWriteEnable = TRUE; + ZEnable = FALSE; + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + + VertexShader = compile vs_3_0 SpriteVS(); + PixelShader = compile ps_3_0 SpritePS(); + } +} \ No newline at end of file diff --git a/shaders/Managed/Utility/SolidsWithZ.fx b/shaders/Managed/Utility/SolidsWithZ.fx new file mode 100644 index 000000000..48162dad5 --- /dev/null +++ b/shaders/Managed/Utility/SolidsWithZ.fx @@ -0,0 +1,20 @@ +// Copyright © 2026 CCP ehf. + +#include "Solids.fxh" + +technique Main +{ + pass P0 + { + ZWriteEnable = TRUE; + ZEnable = TRUE; + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + DepthBias = 0.0001; + VertexShader = compile vs_3_0 SpriteVS(); + PixelShader = compile ps_3_0 SpritePS(); + } +} From 02182434c025a5c69654c8a37e9f3b49ec7f59ac Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 11:40:12 +0000 Subject: [PATCH 31/83] UI shader include --- CMakeLists.txt | 1 + shaders/include/Carbon/UI/UI.fxh | 82 ++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 shaders/include/Carbon/UI/UI.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f535920d..2a3ac2f77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -164,6 +164,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh + shaders/include/Carbon/UI/UI.fxh shaders/include/Carbon/Bindless.fxh shaders/include/Carbon/BoneTransforms.fxh shaders/include/Carbon/Intersections.fxh diff --git a/shaders/include/Carbon/UI/UI.fxh b/shaders/include/Carbon/UI/UI.fxh new file mode 100644 index 000000000..4c2701558 --- /dev/null +++ b/shaders/include/Carbon/UI/UI.fxh @@ -0,0 +1,82 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_UI_FXH +#define CARBON_UI_FXH + + +// The following constants mirror the Tr2SpriteObjectBlendMode enum in C++ +static const uint TR2_SBM_NONE = 0; +static const uint TR2_SBM_BLEND = 1; +static const uint TR2_SBM_ADD = 2; +static const uint TR2_SBM_ADDX2 = 3; + +static const uint S2D_TS_TILE_X = 8; +static const uint S2D_TS_TILE_Y = 16; + +static const uint S2D_RT_COLOR = 1 << 3; +static const uint S2D_RT_GLOW = 1 << 4; + + +// The following constants mirror the Tr2SpriteObjectEffect enum in C++ +static const uint TR2_SFX_FILL = 0; +static const uint TR2_SFX_FILL_AA = 1; + +static const uint TR2_SFX_COPY = 32; +static const uint TR2_SFX_DOT = 33; +static const uint TR2_SFX_NOALPHA = 34; +static const uint TR2_SFX_DROPSHADOW = 35; +static const uint TR2_SFX_OUTLINE = 36; +static const uint TR2_SFX_COLOROVERLAY = 37; +static const uint TR2_SFX_SOFTLIGHT = 38; +static const uint TR2_SFX_BLUR = 39; +static const uint TR2_SFX_BLURBACKGROUNDCOLORED = 40; +static const uint TR2_SFX_BLURBACKGROUND = 41; +static const uint TR2_SFX_GLOW = 42; +static const uint TR2_SFX_FONT = 43; +static const uint TR2_SFX_NOISEFADE = 44; + +static const uint TR2_SFX_MODULATE = 64; +static const uint TR2_SFX_MASK = 65; + +#define TR2_SS_MAX_TRANSFORM_COUNT 32 + +// x, y = 1/width, 1/height of the containing atlas texture, always +// z, w = 0.5/width, 0.5/height of the atlas texture: the shift to apply to TEX2D to sample the texel center. +float4 g_texelSizeUI0; +float4 g_texelSizeUI1; + +// x, y = width, height of the viewport in pixels +float4 UIViewportSize; + +// UI transform stack +float4x4 g_uiTransforms[TR2_SS_MAX_TRANSFORM_COUNT] : register( c5 ); + +// Vertex as it is passed from the application to the vertex shader +struct UIVertexInput +{ + // Vertex position + float3 pos : POSITION; + // Sprite color + float4 color : COLOR0; + // Outline color + float4 outlineColor : COLOR1; + // Texture coordinates for the primary texture + float2 tex0 : TEXCOORD0; + // Texture coordinates for the secondary texture + float2 tex1 : TEXCOORD1; + // Clipping rectangle for the sprite (left, top, right, bottom) + float4 clipRect : TEXCOORD2; + // Glow brightness for the sprite + float glowBrightness : TEXCOORD3; + // Threshold value for the opacity of the outline effect + float outlineThreshold : TEXCOORD4; + + // data.x : transform index + // data.y : blend mode + // data.z : sprite effect (0-2 bits), glow bit (3 bit) + // data.w : tile mode + uint4 data : BLENDINDICES; +}; + + +#endif \ No newline at end of file From 218fb5e20d78806424da110b5462552a1a0db177 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 13:49:56 +0000 Subject: [PATCH 32/83] Utility shaders --- CMakeLists.txt | 4 + shaders/Utility/CubeTextureViewer.fx | 81 +++++++ shaders/Utility/GeometryViewer.fx | 175 +++++++++++++++ shaders/Utility/LineGraph.fx | 43 ++++ shaders/Utility/TextureViewer.fx | 323 +++++++++++++++++++++++++++ 5 files changed, 626 insertions(+) create mode 100644 shaders/Utility/CubeTextureViewer.fx create mode 100644 shaders/Utility/GeometryViewer.fx create mode 100644 shaders/Utility/LineGraph.fx create mode 100644 shaders/Utility/TextureViewer.fx diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a3ac2f77..17a6bd35b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,6 +212,10 @@ set(_SHADER_SOURCES shaders/Managed/Utility/Solids.fxh shaders/Managed/Utility/SolidsNoZ.fx shaders/Managed/Utility/SolidsWithZ.fx + shaders/Utility/CubeTextureViewer.fx + shaders/Utility/GeometryViewer.fx + shaders/Utility/LineGraph.fx + shaders/Utility/TextureViewer.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Utility/CubeTextureViewer.fx b/shaders/Utility/CubeTextureViewer.fx new file mode 100644 index 000000000..eee9e4eb6 --- /dev/null +++ b/shaders/Utility/CubeTextureViewer.fx @@ -0,0 +1,81 @@ +// Copyright © 2026 CCP ehf. + +#include "../include/Carbon/System.fxh" + +TextureCube Texture; +float4 ColorTransform0; +float4 ColorTransform1; +float4 ColorTransform2; +float4 ColorTransform3; +float4 MinValue; +float4 MaxValue; +float UseForceMipMap; +float ForceMipMap; +float MsaaType; + +float4x4 ViewMat; + +SamplerState AutoMipMapTexture +{ + AddressU = Border; + AddressV = Border; + BorderColor = 0; + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; +}; + +SamplerState NoMipMapTexture +{ + AddressU = Border; + AddressV = Border; + BorderColor = 0; + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; +}; + +struct BlitAppVertex +{ + float4 pos : POSITION; + float2 texCoord : TEXCOORD0; +}; + +struct BlitVertex +{ + float4 pos : SV_Position; + float2 texCoord : TEXCOORD0; +}; + + +BlitVertex BlitVS( BlitAppVertex inVtx ) +{ + BlitVertex outVtx = { inVtx.pos, inVtx.texCoord }; + return outVtx; +} + +float4 BlitPS( BlitVertex inVtx ) : SV_Target +{ + float2 pos = inVtx.texCoord * 2 - 1; + float3 viewDir = float3( pos.x, -pos.y, -1 ); + float3 dir = mul( (float3x3)ViewMat, viewDir ); + float4x4 ColorTransform = { ColorTransform0, ColorTransform1, ColorTransform2, ColorTransform3 }; + float4 color; + + color = lerp( Texture.Sample( AutoMipMapTexture, dir ), Texture.SampleLevel( NoMipMapTexture, dir, ForceMipMap ), UseForceMipMap ); + + color = mul( color, ColorTransform ); + color = ( color - MinValue ) / ( MaxValue - MinValue ); + return float4( color.rgb, 1 ); +} + +technique Main +{ + pass P0 + { + AlphaBlendEnable = False; + + VertexShader = compile vs_3_0 BlitVS(); + PixelShader = compile ps_3_0 BlitPS(); + } +} diff --git a/shaders/Utility/GeometryViewer.fx b/shaders/Utility/GeometryViewer.fx new file mode 100644 index 000000000..7971c2fd5 --- /dev/null +++ b/shaders/Utility/GeometryViewer.fx @@ -0,0 +1,175 @@ +// Copyright © 2026 CCP ehf. + +#pragma permutation(FILL_MODE, values=(FILL_SOLID, FILL_WIREFRAME, FILL_NORMALS, FILL_TANGENTS), default=FILL_WIREFRAME) +#pragma permutation(COLOR_MODE, values=(COLOR_SOLID, COLOR_LIT, COLOR_UV0, COLOR_UV1, COLOR_VERTEX_COLOR)) +#pragma permutation(TANGENT_PACKING, values=(TANGENT_NONE, TANGENT_PACKED, TANGENT_UNPACKED, TANGENT_NORMALS)) + +#include "../include/Carbon/System.fxh" +#include "../include/Carbon/Math.fxh" +#include "../include/Carbon/PackedTangents.fxh" + +struct VSIn +{ + float3 position : POSITION; +#if TANGENT_PACKING == TANGENT_PACKED + float4 tangents : TANGENT; +#elif TANGENT_PACKING == TANGENT_UNPACKED + float3 normal : NORMAL; + float3 tangent : TANGENT; + float3 binormal : BINORMAL; +#elif TANGENT_PACKING == TANGENT_NORMALS + float3 normal : NORMAL; +#endif + +#if COLOR_MODE == COLOR_UV0 + float2 texCoord : TEXCOORD0; +#elif COLOR_MODE == COLOR_UV1 + float2 texCoord : TEXCOORD1; +#elif COLOR_MODE == COLOR_VERTEX_COLOR + float4 color : COLOR; +#endif +}; + +struct VSOut +{ + float4 position : SV_Position; + float4 normal : TEXCOORD0; + float3 tangent : TEXCOORD1; + float3 bitangent : TEXCOORD2; + float3 modelPos : TEXCOORD3; +}; + +struct PerFrameVSData +{ + float4x4 ViewInverseTransposeMat; + float4x4 ViewProjectionMat; +} PerFrameVS : register( PERFRAME_VS_STARTREGISTER ); + + +TangentSpace UnpackTangentSpace( VSIn inVtx ) +{ + TangentSpace ts; +#if TANGENT_PACKING == TANGENT_PACKED + ts = UnpackTangentSpaceLegacy( inVtx.tangents ); +#elif TANGENT_PACKING == TANGENT_NORMALS + ts.normal = inVtx.normal; + ts.tangent = 0; + ts.bitangent = 0; +#elif TANGENT_PACKING == TANGENT_UNPACKED + ts.normal = inVtx.normal; + ts.tangent = inVtx.tangent; + ts.bitangent = inVtx.binormal; +#else + ts.normal = 1; + ts.tangent = 1; + ts.bitangent = 1; +#endif + return ts; +} + +VSOut VS( VSIn inVtx ) +{ + VSOut outVtx; + outVtx.position = mul( float4( inVtx.position, 1 ), PerFrameVS.ViewProjectionMat ); + outVtx.normal = 1; + outVtx.tangent = 1; + outVtx.bitangent = 1; + outVtx.modelPos = inVtx.position; +#if COLOR_MODE == COLOR_LIT || FILL_MODE == FILL_NORMALS || FILL_MODE == FILL_TANGENTS + TangentSpace ts = UnpackTangentSpace( inVtx ); + outVtx.normal.xyz = ts.normal; + outVtx.tangent = ts.tangent; + outVtx.bitangent = ts.bitangent; +#elif COLOR_MODE == COLOR_UV0 || COLOR_MODE == COLOR_UV1 + outVtx.normal.xy = inVtx.texCoord; +#elif COLOR_MODE == COLOR_VERTEX_COLOR + outVtx.normal = inVtx.color; +#endif + return outVtx; +} + +void AddVector( VSOut vertex, float3 direction, float4 color, inout LineStream triStream ) +{ + float4 p0 = mul( float4( vertex.modelPos, 1 ), PerFrameVS.ViewProjectionMat ); + float length = p0.z; + float4 p1 = mul( float4( vertex.modelPos + normalize( direction ) * length, 1 ), PerFrameVS.ViewProjectionMat ); + + VSOut p = (VSOut)0; + p.normal = color; + + triStream.RestartStrip(); + + p.position = p0; + triStream.Append( p ); + + p.position = p1; + triStream.Append( p ); +} + +[maxvertexcount( 18 )] +void GS( triangle VSOut inVtx[3], inout LineStream triStream, uint primitiveID : SV_PrimitiveID ) +{ + for( int i = 0; i < 3; ++i ) + { + VSOut vertex = inVtx[i]; + AddVector( vertex, vertex.normal.xyz, float4( 0, 0, 1, 1 ), triStream ); +#if FILL_MODE == FILL_TANGENTS + AddVector( vertex, vertex.tangent, float4( 1, 0, 0, 1 ), triStream ); + AddVector( vertex, vertex.bitangent, float4( 0, 1, 0, 1 ), triStream ); +#endif + } +} + +float4 SolidPS( VSOut inVtx ) : SV_Target +{ + return inVtx.normal; +} + +float4 PS( VSOut inVtx ) : SV_Target +{ +#if COLOR_MODE == COLOR_LIT + return saturate( dot( normalize( inVtx.normal.xyz ), normalize( float3( 1, 1, 1 ) ) ) ) * 0.9 + 0.1; +#elif COLOR_MODE == COLOR_UV0 || COLOR_MODE == COLOR_UV1 + return float4( inVtx.normal.xy, 0, 1 ); +#elif COLOR_MODE == COLOR_VERTEX_COLOR + return inVtx.normal; +#endif + return 1; +} + +technique Main +{ +#if FILL_MODE == FILL_WIREFRAME + pass p0 + { + FillMode = Solid; + ColorWriteEnable = 0; + + VertexShader = compile vs_3_0 VS(); + PixelShader = compile ps_3_0 PS(); + } + pass p1 + { + ColorWriteEnable = 0xf; + FillMode = Wireframe; + SlopeScaleDepthBias = 0.5; + + VertexShader = compile vs_3_0 VS(); + PixelShader = compile ps_3_0 PS(); + } +#elif (FILL_MODE == FILL_TANGENTS || FILL_MODE == FILL_NORMALS) && PLATFORM_SUPPORTS_GEOMETRY_SHADERS + pass p1 + { + CullMode = None; + VertexShader = compile vs_3_0 VS(); + GeometryShader = compile gs_5_0 GS(); + PixelShader = compile ps_3_0 SolidPS(); + } +#else + pass p1 + { + VertexShader = compile vs_3_0 VS(); + PixelShader = compile ps_3_0 PS(); + } +#endif +} \ No newline at end of file diff --git a/shaders/Utility/LineGraph.fx b/shaders/Utility/LineGraph.fx new file mode 100644 index 000000000..43894d488 --- /dev/null +++ b/shaders/Utility/LineGraph.fx @@ -0,0 +1,43 @@ +// Copyright © 2026 CCP ehf. + +#include "../include/Carbon/System.fxh" + +float4 lineGraphColor; +float lineGraphScale; + +struct AppVertex +{ + float2 pos : POSITION; +}; + +struct ShaderVertex +{ + float4 posClip : SV_Position; +}; + +ShaderVertex VS( AppVertex inVtx ) +{ + ShaderVertex outVtx; + outVtx.posClip.x = inVtx.pos.x; + outVtx.posClip.y = inVtx.pos.y * lineGraphScale * 2.0f - 1.0f; + outVtx.posClip.z = 0; + outVtx.posClip.w = 1; + return outVtx; +} + +float4 PS( ShaderVertex inVtx ) : SV_Target +{ + return lineGraphColor; +} + +technique Main +{ + pass P0 + { + ZEnable = False; + AlphaBlendEnable = False; + AlphaTestEnable = False; + VertexShader = compile vs_3_0 VS(); + PixelShader = compile ps_3_0 PS(); + } +} diff --git a/shaders/Utility/TextureViewer.fx b/shaders/Utility/TextureViewer.fx new file mode 100644 index 000000000..3a161719b --- /dev/null +++ b/shaders/Utility/TextureViewer.fx @@ -0,0 +1,323 @@ +// Copyright © 2026 CCP ehf. + +#pragma permutation(TEXTURE_TYPE, values=(TEXTURE_2D, TEXTURE_CUBE, TEXTURE_3D), default=TEXTURE_2D, description="Texture type") +#pragma permutation(TEXTURE_MSAA, values=(MSAA_NO, MSAA_YES), default=MSAA_NO, description="Texture MSAA type") +#pragma permutation(TEXTURE_ARRAY, values=(ARRAY_NO, ARRAY_YES), default=ARRAY_NO, description="Texture array type") +#pragma permutation(TEXTURE_FORMAT, values=(FORMAT_FLOAT, FORMAT_INT, FORMAT_UINT)) +#pragma permutation(COLOR_SPACE, values = ( LINEAR_SPACE, SRGB_SPACE, LOGARITHMIC_SPACE ) ) +#pragma permutation(CUBE_RENDERING_MODE, values=(VIEW, CROSS, ROWS, FORWARD, BACKWARD, RIGHT, LEFT, UP, DOWN), default=VIEW, description="Cube Texture Rendering Mode") + +#include "../include/Carbon/System.fxh" + + +// TODO: Support metal and CubeArrays +#if PLATFORM == PLATFORM_METAL +#define TEXTURE_ARRAY ARRAY_NO +#endif + +#if TEXTURE_ARRAY == ARRAY_NO + +#if TEXTURE_TYPE == TEXTURE_2D +#if TEXTURE_MSAA == MSAA_NO +#define _TEXTURE_TYPE Texture2D +#else // TEXTURE_MSAA == MSAA_NO +#define _TEXTURE_TYPE Texture2DMS +#endif // TEXTURE_MSAA == MSAA_NO +#elif TEXTURE_TYPE == TEXTURE_CUBE +#define _TEXTURE_TYPE TextureCube +#else // TEXTURE_TYPE +#define _TEXTURE_TYPE Texture3D +#endif // TEXTURE_TYPE + +#else // TEXTURE_ARRAY + +#if TEXTURE_TYPE == TEXTURE_2D +#if TEXTURE_MSAA == MSAA_NO +#define _TEXTURE_TYPE Texture2DArray +#else // TEXTURE_MSAA == MSAA_NO +#define _TEXTURE_TYPE Texture2DMSArray +#endif // TEXTURE_MSAA == MSAA_NO +#elif TEXTURE_TYPE == TEXTURE_CUBE +#define _TEXTURE_TYPE TextureCubeArray +#else // TEXTURE_TYPE +// There is no 3DArray +#define _TEXTURE_TYPE Texture3D +#endif // TEXTURE_TYPE + +#endif // TEXTURE_ARRAY + +#if TEXTURE_FORMAT == FORMAT_INT +#define _TEXTURE_FORMAT +#elif TEXTURE_FORMAT == FORMAT_UINT +#define _TEXTURE_FORMAT +#else +#define _TEXTURE_FORMAT +#endif + +_TEXTURE_TYPE _TEXTURE_FORMAT Texture; + +float4 ColorTransform0; +float4 ColorTransform1; +float4 ColorTransform2; +float4 ColorTransform3; +float4 MinValue; +float4 MaxValue; +float UseForceMipMap; +float ForceMipMap; +float VolumeSlice = 0; +float ArraySlice = 0; + + +float4x4 ViewMat; + +SamplerState AutoMipMapTexture +{ + AddressU = Border; + AddressV = Border; + AddressW = Clamp; + BorderColor = 0; + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; +}; + +SamplerState NoMipMapTexture +{ + AddressU = Border; + AddressV = Border; + AddressW = Clamp; + BorderColor = 0; + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; +}; + +struct BlitAppVertex +{ + float4 pos : POSITION; + float2 texCoord : TEXCOORD0; +}; + +struct BlitVertex +{ + float4 pos : SV_Position; + float2 texCoord : TEXCOORD0; +}; + + +BlitVertex BlitVS( BlitAppVertex inVtx ) +{ + BlitVertex outVtx = { inVtx.pos, inVtx.texCoord }; + return outVtx; +} + +float4 LinearToSRGB( float4 inColor ) +{ + float4 result; + result.r = inColor.r < 0.0031308 ? inColor.r * 12.92 : pow( saturate( inColor.r ), 1 / 2.4 ) * 1.055 - 0.055; + result.g = inColor.g < 0.0031308 ? inColor.g * 12.92 : pow( saturate( inColor.g ), 1 / 2.4 ) * 1.055 - 0.055; + result.b = inColor.b < 0.0031308 ? inColor.b * 12.92 : pow( saturate( inColor.b ), 1 / 2.4 ) * 1.055 - 0.055; + result.a = inColor.w; + return result; +} + +float4 SRGBToLinear( float4 inColor ) +{ + float4 result; + result.r = inColor.r < 0.040449936 ? inColor.r / 12.92 : pow( abs( ( inColor.r + 0.055 ) / 1.055 ), 2.4 ); + result.g = inColor.g < 0.040449936 ? inColor.g / 12.92 : pow( abs( ( inColor.g + 0.055 ) / 1.055 ), 2.4 ); + result.b = inColor.b < 0.040449936 ? inColor.b / 12.92 : pow( abs( ( inColor.b + 0.055 ) / 1.055 ), 2.4 ); + result.a = inColor.a < 0.040449936 ? inColor.a / 12.92 : pow( abs( ( inColor.a + 0.055 ) / 1.055 ), 2.4 ); + return result; +} + +float4 LogarithmicToLinearish( float4 inColor ) +{ + // Avert your eyes! Extreme HACK ahead! + return pow( abs( inColor ), float4( 0.25, 0.25, 0.25, 0.25 ) ); +} + + +#if TEXTURE_TYPE == TEXTURE_CUBE && TEXTURE_ARRAY == ARRAY_NO + +static const float3x3 POS_X_ROTATION = float3x3( 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 0.0 ); +static const float3x3 NEG_X_ROTATION = float3x3( 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0 ); +static const float3x3 POS_Z_ROTATION = float3x3( -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0 ); +static const float3x3 NEG_Z_ROTATION = float3x3( 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ); +static const float3x3 POS_Y_ROTATION = float3x3( -1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, -1.0, 0.0 ); +static const float3x3 NEG_Y_ROTATION = float3x3( -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0 ); +static const float3x3 ERROR_ROTATION = float3x3( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ); + +float3 ConvertUvToViewDir( float2 uv ) +{ + float2 pos = uv * 2 - 1; + return float3( pos.x, -pos.y, -1 ); +} +// returns the correct 3d view direction +float3 GetView( float2 uv, float2 columnRow, float2 size, float3x3 rotation ) +{ + uv -= columnRow * size; + uv /= size; + // rotate the view direction + return mul( rotation, ConvertUvToViewDir( uv ) ); +} +// returns the column and row for a specific grid size +float2 GetColumnRow( float2 uv, float columns, float rows ) +{ + return float2( floor( uv.x * columns ), floor( uv.y * rows ) ); +} +// moves a float value to a new min max +float MoveValueToRange( float2 oldMinMax, float2 newMinMax, float value ) +{ + return newMinMax.x + ( newMinMax.y - newMinMax.x ) / ( oldMinMax.y - oldMinMax.x ) * ( value - oldMinMax.x ); +} +// returns a +float4 CubeColor( float2 uv ) +{ + float3 viewDir; +#if CUBE_RENDERING_MODE == CROSS + // up + // left forward right back + // down + float gutter = 1.0 / 8.0; + if( uv.y < gutter || uv.y > 1.0 - gutter ) + { + // gutter + return float4( 0, 0, 0, 0 ); + } + // rejig the uv to go from float2([0-1], [gutter - (1 - gutter)]) to float2([0-1], [0-1]) + float2 transformedUv = float2( uv.x, MoveValueToRange( float2( gutter, 1.0 - gutter ), float2( 0, 1 ), uv.y ) ); + float3x3 ROTATION_MATRICES[12] = + { + ERROR_ROTATION, POS_Y_ROTATION, ERROR_ROTATION, ERROR_ROTATION, + NEG_X_ROTATION, POS_Z_ROTATION, POS_X_ROTATION, NEG_Z_ROTATION, + ERROR_ROTATION, NEG_Y_ROTATION, ERROR_ROTATION, ERROR_ROTATION + }; + float2 gridSize = float2( 4.0, 3.0 ); + float2 columnRow = GetColumnRow( transformedUv, gridSize.x, gridSize.y ); + + float3x3 rotation = ROTATION_MATRICES[columnRow.x + 4 * columnRow.y]; + // check the dead zone + if( !any( mul( rotation, float3( 1, 1, 1 ) ) ) ) + { + return float4( 0, 0, 0, 0 ); + } + viewDir = GetView( transformedUv, columnRow, 1.0 / gridSize, rotation ); +#elif CUBE_RENDERING_MODE == ROWS + // recalculate the direction to show all rows + // left right up + // forward back down + float gutter = 1.0 / 6.0; + if(uv.y < gutter || uv.y > 1.0 - gutter ) + { + // gutter + return float4(0, 0, 0, 0); + } + + float3x3 ROTATION_MATRICES[6] = { + NEG_X_ROTATION, POS_X_ROTATION, POS_Y_ROTATION, + POS_Z_ROTATION, NEG_Z_ROTATION, NEG_Y_ROTATION + }; + // rejig the uv to go from float2([0-1], [gutter - (1 - gutter)]) to float2([0-1], [0-1]) + float2 transformedUv = float2(uv.x, MoveValueToRange(float2(gutter, 1.0 - gutter), float2(0, 1), uv.y)); + float2 gridSize = float2(3.0, 2.0); + float2 columnRow = GetColumnRow(transformedUv, gridSize.x, gridSize.y); + viewDir = GetView(transformedUv, columnRow, 1.0 / gridSize, ROTATION_MATRICES[columnRow.x + 3 * columnRow.y]); +#elif CUBE_RENDERING_MODE == FORWARD + // recalculate the direction to show only -z + viewDir = mul( POS_Z_ROTATION, ConvertUvToViewDir(uv) ); +#elif CUBE_RENDERING_MODE == BACKWARD + // recalculate the direction to show only z + viewDir = mul( NEG_Z_ROTATION, ConvertUvToViewDir(uv) ); + +#elif CUBE_RENDERING_MODE == RIGHT + // recalculate the direction to show only x + viewDir = mul( POS_X_ROTATION, ConvertUvToViewDir(uv) ); + +#elif CUBE_RENDERING_MODE == LEFT + // recalculate the direction to show only -x + viewDir = mul( NEG_X_ROTATION, ConvertUvToViewDir(uv) ); + +#elif CUBE_RENDERING_MODE == UP + // recalculate the direction to show only y + viewDir = mul( POS_Y_ROTATION, ConvertUvToViewDir(uv) ); + +#elif CUBE_RENDERING_MODE == DOWN + // recalculate the direction to show only -y + viewDir = mul( NEG_Y_ROTATION, ConvertUvToViewDir(uv) ); +#else // CUBE + viewDir = mul( ( float3x3 )ViewMat, ConvertUvToViewDir(uv) ); +#endif + return lerp( Texture.Sample( AutoMipMapTexture, viewDir ), Texture.SampleLevel( NoMipMapTexture, viewDir, ForceMipMap ), UseForceMipMap ); +} +#endif + + +float4 BlitPS( BlitVertex inVtx ) : COLOR +{ + float2 UV = inVtx.texCoord; // * Zoom.xy + Zoom.zw; + float4x4 ColorTransform = { ColorTransform0, ColorTransform1, ColorTransform2, ColorTransform3 }; + float4 color; + +#if TEXTURE_TYPE == TEXTURE_2D +#if TEXTURE_MSAA == MSAA_YES + uint w, h, d, s; +#if TEXTURE_ARRAY == ARRAY_NO + Texture.GetDimensions( w, h, d ); + color = float4( Texture.Load( UV * float2( w, h ), 0 ) ); +#else + Texture.GetDimensions( w, h, d, s ); + color = float4( Texture.Load( float3(UV * float2( w, h ), ArraySlice), 0 ) ); +#endif +#elif ( TEXTURE_FORMAT == FORMAT_INT || TEXTURE_FORMAT == FORMAT_UINT || TEXTURE_ARRAY == ARRAY_YES ) + uint w, h, d; + uint mip = UseForceMipMap ? ForceMipMap : 0; +#if TEXTURE_ARRAY == ARRAY_NO + Texture.GetDimensions( w, h ); + color = float4( Texture.Load( float3( UV * float2( w, h ), mip ) ) ); +#else + Texture.GetDimensions( w, h, d ); + color = float4( Texture.Load( float4( UV * float2( w, h ), ArraySlice, mip ) ) ); +#endif +#else + color = lerp( Texture.Sample( AutoMipMapTexture, UV ), Texture.SampleLevel( NoMipMapTexture, UV, ForceMipMap ), UseForceMipMap ); +#endif +#elif TEXTURE_TYPE == TEXTURE_3D +#if ( TEXTURE_FORMAT == FORMAT_INT || TEXTURE_FORMAT == FORMAT_UINT ) + uint w, h, d; + Texture.GetDimensions( w, h, d ); + uint mip = UseForceMipMap ? ForceMipMap : 0; + color = float4( Texture.Load( float4( UV * float2( w, h ), VolumeSlice * d, mip ) ) ); +#else + color = lerp( Texture.Sample( AutoMipMapTexture, float3( UV, VolumeSlice ) ), Texture.SampleLevel( NoMipMapTexture, float3( UV, VolumeSlice ), ForceMipMap ), UseForceMipMap ); +#endif +#else +#if ( TEXTURE_FORMAT == FORMAT_INT || TEXTURE_FORMAT == FORMAT_UINT || TEXTURE_ARRAY == ARRAY_YES ) + color = 0; +#else + color = CubeColor(inVtx.texCoord); +#endif +#endif + +#if COLOR_SPACE == SRGB_SPACE + color = SRGBToLinear( color ); +#elif COLOR_SPACE == LOGARITHMIC_SPACE + color = LogarithmicToLinearish( color ); +#endif + + color = mul( color, ColorTransform ); + color = ( color - MinValue ) / ( MaxValue - MinValue ); + color = LinearToSRGB( color ); + return float4( color.rgb, 1 ); +} + +technique Main +{ + pass P0 + { + AlphaBlendEnable = False; + + VertexShader = compile vs_3_0 BlitVS(); + PixelShader = compile ps_3_0 BlitPS(); + } +} From 569e9f8061ebd8e5b34a27ebeeaa9ba8a00c7486 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 14:25:35 +0000 Subject: [PATCH 33/83] Interior includes --- CMakeLists.txt | 2 + .../Carbon/InteriorScene/PerObjectData.fxh | 59 +++++++++++++++++++ .../Carbon/InteriorScene/PerSceneData.fxh | 39 ++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 shaders/include/Carbon/InteriorScene/PerObjectData.fxh create mode 100644 shaders/include/Carbon/InteriorScene/PerSceneData.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 17a6bd35b..74477cc74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,6 +132,8 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() set(_SHADER_SOURCES + shaders/include/Carbon/InteriorScene/PerObjectData.fxh + shaders/include/Carbon/InteriorScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh diff --git a/shaders/include/Carbon/InteriorScene/PerObjectData.fxh b/shaders/include/Carbon/InteriorScene/PerObjectData.fxh new file mode 100644 index 000000000..e17020513 --- /dev/null +++ b/shaders/include/Carbon/InteriorScene/PerObjectData.fxh @@ -0,0 +1,59 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_INTERIOR_PEROBJECTDATA_FXH +#define CARBON_INTERIOR_PEROBJECTDATA_FXH + +#include "../System.fxh" + +// Constant buffer format for per-object data for interior scene objects. This data is provided by the engine to the vertex shader stage. +struct InteriorObjectDataVS +{ + // World transform of this object + float4x4 WorldMat; + float4 boundingBoxData; +}; + +struct InteriorSkinnedObjectDataVS +{ + // Set this up as a column-major 4x3 matrix, which is like a + // row-major 3x4. This allows us to use the same mul syntax + // as we normally do, but still allow packing of a 3x4 into + // 3 registers. + column_major float4x3 JointMat[69]; + float4x4 WorldMat; + float3 WorldPos; +}; + + +// interior +struct InteriorObjectLightData +{ + float4 position; // position in [x,y,z], radius in [w] + float4 color; // color in [r,g,b], falloff in [a] + float4 exData; // additional data: [x] = shadow0 influence, [y] = shadow1 influence, [z] = cos of spotlight outer cone alpha, [w] = cos of spotlight inner cone alpha + // or box light's world to box transform row 1 for box lights + float4 spotDirection; // spotlight's direction: [x,y,z} = normalized direction + // or box light's world to box transform row 2 for box lights + float4 boxTransformRow3; // box light's world to box transform row 3 + float4 boxTransformRow4; // box light's world to box transform row 4 +}; + +#define NUM_INTERIORLIGHTS 10 + +// Constant buffer format for per-object data for interior scene objects. This data is provided by the engine to the pixel shader stage. +struct InteriorObjectDataPS +{ + int4 pointLightsCount; // yzw - unused + + // data on lights + InteriorObjectLightData lights[NUM_INTERIORLIGHTS]; + // data on the shadow casting point lights: [x,y,z] = position, [w] = radius + float4 shadowCaster0; + float4 shadowCaster1; + // spotlight view projection matrices + float4x4 spotLights[4]; +}; + + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/InteriorScene/PerSceneData.fxh b/shaders/include/Carbon/InteriorScene/PerSceneData.fxh new file mode 100644 index 000000000..a5452c3a1 --- /dev/null +++ b/shaders/include/Carbon/InteriorScene/PerSceneData.fxh @@ -0,0 +1,39 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_INTERIOR_PERSCENEDATA_FXH +#define CARBON_INTERIOR_PERSCENEDATA_FXH + + +#include "../System.fxh" + + +// Per-scene (per-frame) constant buffer data for the vertex shader. +struct InteriorSceneDataVS +{ + float4x4 ViewInverseTransposeMat; + float4 sunDirWorld; + float4 sceneFogColor; + + float4x4 ViewProjectionMat; + float4x4 ViewMat; + float4x4 ProjectionMat; +}; + +// Per-scene (per-frame) constant buffer data for the pixel shader. +struct InteriorSceneDataPS +{ + float4x4 ViewInverseTransposeMat; + float4 sceneAmbientColor; + float4 sceneFogColor; + float4 sunDirWorld; + float4 sunDiffuseColor; + float4 sunSpecularColor; + float4 fogValues; // x = maxFogAmount, y = maxFogDistance, z = minFogDistance, w unused + float4x4 ViewProjectionMat; + float4 misc; // x = Global spherical harmonic scale factor, y = shadow count, z = inv.shadow size, w = radius + float4 viewPort; // xy - viewport width/height, zw - viewport offset + float4x4 ViewProjInverse; +}; + + +#endif \ No newline at end of file From dd15d4f94c6d4ef255eee10f3758b127d9f1024f Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 14:38:12 +0000 Subject: [PATCH 34/83] Moved shaders into src directory --- .../Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx | 0 shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx | 0 shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx | 0 .../Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx | 0 .../Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx | 0 shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx | 0 .../{ => src}/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx | 0 .../{ => src}/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx | 0 shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Update.fx | 0 .../Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx | 0 .../Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx | 0 .../Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx | 0 .../Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx | 0 .../Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx | 0 .../Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx | 0 shaders/{ => src}/Managed/Space/System/ComputeLightLists.fx | 0 shaders/{ => src}/Managed/Space/System/Denoise1D.fx | 0 shaders/{ => src}/Managed/Space/System/DenoiseEstimate.fx | 0 shaders/{ => src}/Managed/Space/System/EstimateNoise.fx | 0 shaders/{ => src}/Managed/Space/System/Raytracing/SkinVertices.fx | 0 shaders/{ => src}/Managed/Utility/BillboardNoZ.fx | 0 shaders/{ => src}/Managed/Utility/BillboardPicking.fx | 0 shaders/{ => src}/Managed/Utility/Debug.fx | 0 shaders/{ => src}/Managed/Utility/DebugLine.fx | 0 shaders/{ => src}/Managed/Utility/DebugPrimitive.fx | 0 shaders/{ => src}/Managed/Utility/DebugPrimitivePicking.fx | 0 shaders/{ => src}/Managed/Utility/Lines.fxh | 0 shaders/{ => src}/Managed/Utility/LinesNoZ.fx | 0 shaders/{ => src}/Managed/Utility/LinesRotationTool.fx | 0 shaders/{ => src}/Managed/Utility/LinesRotationToolLH.fx | 0 shaders/{ => src}/Managed/Utility/LinesWithZ.fx | 0 shaders/{ => src}/Managed/Utility/PerFrameVSData.fxh | 0 shaders/{ => src}/Managed/Utility/PrimitivePicking.fx | 0 shaders/{ => src}/Managed/Utility/SolidNoLightNoCullWithZ.fx | 0 shaders/{ => src}/Managed/Utility/Solids.fxh | 0 shaders/{ => src}/Managed/Utility/SolidsNoZ.fx | 0 shaders/{ => src}/Managed/Utility/SolidsWithZ.fx | 0 shaders/{ => src}/Utility/CubeTextureViewer.fx | 0 shaders/{ => src}/Utility/GeometryViewer.fx | 0 shaders/{ => src}/Utility/LineGraph.fx | 0 shaders/{ => src}/Utility/TextureViewer.fx | 0 41 files changed, 0 insertions(+), 0 deletions(-) rename shaders/{ => src}/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Update.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx (100%) rename shaders/{ => src}/Managed/Space/System/ComputeLightLists.fx (100%) rename shaders/{ => src}/Managed/Space/System/Denoise1D.fx (100%) rename shaders/{ => src}/Managed/Space/System/DenoiseEstimate.fx (100%) rename shaders/{ => src}/Managed/Space/System/EstimateNoise.fx (100%) rename shaders/{ => src}/Managed/Space/System/Raytracing/SkinVertices.fx (100%) rename shaders/{ => src}/Managed/Utility/BillboardNoZ.fx (100%) rename shaders/{ => src}/Managed/Utility/BillboardPicking.fx (100%) rename shaders/{ => src}/Managed/Utility/Debug.fx (100%) rename shaders/{ => src}/Managed/Utility/DebugLine.fx (100%) rename shaders/{ => src}/Managed/Utility/DebugPrimitive.fx (100%) rename shaders/{ => src}/Managed/Utility/DebugPrimitivePicking.fx (100%) rename shaders/{ => src}/Managed/Utility/Lines.fxh (100%) rename shaders/{ => src}/Managed/Utility/LinesNoZ.fx (100%) rename shaders/{ => src}/Managed/Utility/LinesRotationTool.fx (100%) rename shaders/{ => src}/Managed/Utility/LinesRotationToolLH.fx (100%) rename shaders/{ => src}/Managed/Utility/LinesWithZ.fx (100%) rename shaders/{ => src}/Managed/Utility/PerFrameVSData.fxh (100%) rename shaders/{ => src}/Managed/Utility/PrimitivePicking.fx (100%) rename shaders/{ => src}/Managed/Utility/SolidNoLightNoCullWithZ.fx (100%) rename shaders/{ => src}/Managed/Utility/Solids.fxh (100%) rename shaders/{ => src}/Managed/Utility/SolidsNoZ.fx (100%) rename shaders/{ => src}/Managed/Utility/SolidsWithZ.fx (100%) rename shaders/{ => src}/Utility/CubeTextureViewer.fx (100%) rename shaders/{ => src}/Utility/GeometryViewer.fx (100%) rename shaders/{ => src}/Utility/LineGraph.fx (100%) rename shaders/{ => src}/Utility/TextureViewer.fx (100%) diff --git a/shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx b/shaders/src/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx rename to shaders/src/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Update.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Update.fx diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx b/shaders/src/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx rename to shaders/src/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx b/shaders/src/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx rename to shaders/src/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx b/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx rename to shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx b/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx rename to shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx b/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx rename to shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx b/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx rename to shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx diff --git a/shaders/Managed/Space/System/ComputeLightLists.fx b/shaders/src/Managed/Space/System/ComputeLightLists.fx similarity index 100% rename from shaders/Managed/Space/System/ComputeLightLists.fx rename to shaders/src/Managed/Space/System/ComputeLightLists.fx diff --git a/shaders/Managed/Space/System/Denoise1D.fx b/shaders/src/Managed/Space/System/Denoise1D.fx similarity index 100% rename from shaders/Managed/Space/System/Denoise1D.fx rename to shaders/src/Managed/Space/System/Denoise1D.fx diff --git a/shaders/Managed/Space/System/DenoiseEstimate.fx b/shaders/src/Managed/Space/System/DenoiseEstimate.fx similarity index 100% rename from shaders/Managed/Space/System/DenoiseEstimate.fx rename to shaders/src/Managed/Space/System/DenoiseEstimate.fx diff --git a/shaders/Managed/Space/System/EstimateNoise.fx b/shaders/src/Managed/Space/System/EstimateNoise.fx similarity index 100% rename from shaders/Managed/Space/System/EstimateNoise.fx rename to shaders/src/Managed/Space/System/EstimateNoise.fx diff --git a/shaders/Managed/Space/System/Raytracing/SkinVertices.fx b/shaders/src/Managed/Space/System/Raytracing/SkinVertices.fx similarity index 100% rename from shaders/Managed/Space/System/Raytracing/SkinVertices.fx rename to shaders/src/Managed/Space/System/Raytracing/SkinVertices.fx diff --git a/shaders/Managed/Utility/BillboardNoZ.fx b/shaders/src/Managed/Utility/BillboardNoZ.fx similarity index 100% rename from shaders/Managed/Utility/BillboardNoZ.fx rename to shaders/src/Managed/Utility/BillboardNoZ.fx diff --git a/shaders/Managed/Utility/BillboardPicking.fx b/shaders/src/Managed/Utility/BillboardPicking.fx similarity index 100% rename from shaders/Managed/Utility/BillboardPicking.fx rename to shaders/src/Managed/Utility/BillboardPicking.fx diff --git a/shaders/Managed/Utility/Debug.fx b/shaders/src/Managed/Utility/Debug.fx similarity index 100% rename from shaders/Managed/Utility/Debug.fx rename to shaders/src/Managed/Utility/Debug.fx diff --git a/shaders/Managed/Utility/DebugLine.fx b/shaders/src/Managed/Utility/DebugLine.fx similarity index 100% rename from shaders/Managed/Utility/DebugLine.fx rename to shaders/src/Managed/Utility/DebugLine.fx diff --git a/shaders/Managed/Utility/DebugPrimitive.fx b/shaders/src/Managed/Utility/DebugPrimitive.fx similarity index 100% rename from shaders/Managed/Utility/DebugPrimitive.fx rename to shaders/src/Managed/Utility/DebugPrimitive.fx diff --git a/shaders/Managed/Utility/DebugPrimitivePicking.fx b/shaders/src/Managed/Utility/DebugPrimitivePicking.fx similarity index 100% rename from shaders/Managed/Utility/DebugPrimitivePicking.fx rename to shaders/src/Managed/Utility/DebugPrimitivePicking.fx diff --git a/shaders/Managed/Utility/Lines.fxh b/shaders/src/Managed/Utility/Lines.fxh similarity index 100% rename from shaders/Managed/Utility/Lines.fxh rename to shaders/src/Managed/Utility/Lines.fxh diff --git a/shaders/Managed/Utility/LinesNoZ.fx b/shaders/src/Managed/Utility/LinesNoZ.fx similarity index 100% rename from shaders/Managed/Utility/LinesNoZ.fx rename to shaders/src/Managed/Utility/LinesNoZ.fx diff --git a/shaders/Managed/Utility/LinesRotationTool.fx b/shaders/src/Managed/Utility/LinesRotationTool.fx similarity index 100% rename from shaders/Managed/Utility/LinesRotationTool.fx rename to shaders/src/Managed/Utility/LinesRotationTool.fx diff --git a/shaders/Managed/Utility/LinesRotationToolLH.fx b/shaders/src/Managed/Utility/LinesRotationToolLH.fx similarity index 100% rename from shaders/Managed/Utility/LinesRotationToolLH.fx rename to shaders/src/Managed/Utility/LinesRotationToolLH.fx diff --git a/shaders/Managed/Utility/LinesWithZ.fx b/shaders/src/Managed/Utility/LinesWithZ.fx similarity index 100% rename from shaders/Managed/Utility/LinesWithZ.fx rename to shaders/src/Managed/Utility/LinesWithZ.fx diff --git a/shaders/Managed/Utility/PerFrameVSData.fxh b/shaders/src/Managed/Utility/PerFrameVSData.fxh similarity index 100% rename from shaders/Managed/Utility/PerFrameVSData.fxh rename to shaders/src/Managed/Utility/PerFrameVSData.fxh diff --git a/shaders/Managed/Utility/PrimitivePicking.fx b/shaders/src/Managed/Utility/PrimitivePicking.fx similarity index 100% rename from shaders/Managed/Utility/PrimitivePicking.fx rename to shaders/src/Managed/Utility/PrimitivePicking.fx diff --git a/shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx b/shaders/src/Managed/Utility/SolidNoLightNoCullWithZ.fx similarity index 100% rename from shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx rename to shaders/src/Managed/Utility/SolidNoLightNoCullWithZ.fx diff --git a/shaders/Managed/Utility/Solids.fxh b/shaders/src/Managed/Utility/Solids.fxh similarity index 100% rename from shaders/Managed/Utility/Solids.fxh rename to shaders/src/Managed/Utility/Solids.fxh diff --git a/shaders/Managed/Utility/SolidsNoZ.fx b/shaders/src/Managed/Utility/SolidsNoZ.fx similarity index 100% rename from shaders/Managed/Utility/SolidsNoZ.fx rename to shaders/src/Managed/Utility/SolidsNoZ.fx diff --git a/shaders/Managed/Utility/SolidsWithZ.fx b/shaders/src/Managed/Utility/SolidsWithZ.fx similarity index 100% rename from shaders/Managed/Utility/SolidsWithZ.fx rename to shaders/src/Managed/Utility/SolidsWithZ.fx diff --git a/shaders/Utility/CubeTextureViewer.fx b/shaders/src/Utility/CubeTextureViewer.fx similarity index 100% rename from shaders/Utility/CubeTextureViewer.fx rename to shaders/src/Utility/CubeTextureViewer.fx diff --git a/shaders/Utility/GeometryViewer.fx b/shaders/src/Utility/GeometryViewer.fx similarity index 100% rename from shaders/Utility/GeometryViewer.fx rename to shaders/src/Utility/GeometryViewer.fx diff --git a/shaders/Utility/LineGraph.fx b/shaders/src/Utility/LineGraph.fx similarity index 100% rename from shaders/Utility/LineGraph.fx rename to shaders/src/Utility/LineGraph.fx diff --git a/shaders/Utility/TextureViewer.fx b/shaders/src/Utility/TextureViewer.fx similarity index 100% rename from shaders/Utility/TextureViewer.fx rename to shaders/src/Utility/TextureViewer.fx From 4f0c05f57c23dde07bcb9cff6958d2ec73576e9b Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 14:48:51 +0000 Subject: [PATCH 35/83] Sparate CMakeLists.txt for shaders --- CMakeLists.txt | 97 +------------------------------------- shaders/CMakeLists.txt | 103 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 96 deletions(-) create mode 100644 shaders/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 74477cc74..c73a925cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ endif () add_subdirectory(trinityal) add_subdirectory(trinity) +add_subdirectory(shaders) if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) # Determine if/when to generate/build documentation. The rules are as follows: @@ -131,99 +132,3 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() endif() -set(_SHADER_SOURCES - shaders/include/Carbon/InteriorScene/PerObjectData.fxh - shaders/include/Carbon/InteriorScene/PerSceneData.fxh - shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh - shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh - shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh - shaders/include/Carbon/SpaceScene/DepthMap.fxh - shaders/include/Carbon/SpaceScene/DynamicLighting.fxh - shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh - shaders/include/Carbon/SpaceScene/EveBannerSet.fxh - shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh - shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh - shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh - shaders/include/Carbon/SpaceScene/EveChildCloud.fxh - shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh - shaders/include/Carbon/SpaceScene/EveHazeSet.fxh - shaders/include/Carbon/SpaceScene/EveLensflare.fxh - shaders/include/Carbon/SpaceScene/EveOccluder.fxh - shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh - shaders/include/Carbon/SpaceScene/EveChildQuad.fxh - shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh - shaders/include/Carbon/SpaceScene/EveSpherePin.fxh - shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh - shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh - shaders/include/Carbon/SpaceScene/EveStarfield.fxh - shaders/include/Carbon/SpaceScene/EveTransform.fxh - shaders/include/Carbon/SpaceScene/EveStretch2.fxh - shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh - shaders/include/Carbon/SpaceScene/EveTurretSet.fxh - shaders/include/Carbon/SpaceScene/FroxelFog.fxh - shaders/include/Carbon/SpaceScene/GpuParticles.fxh - shaders/include/Carbon/SpaceScene/MeshMorphing.fxh - shaders/include/Carbon/SpaceScene/PerObjectData.fxh - shaders/include/Carbon/SpaceScene/PerSceneData.fxh - shaders/include/Carbon/SpaceScene/Volumetrics.fxh - shaders/include/Carbon/UI/UI.fxh - shaders/include/Carbon/Bindless.fxh - shaders/include/Carbon/BoneTransforms.fxh - shaders/include/Carbon/Intersections.fxh - shaders/include/Carbon/Math.fxh - shaders/include/Carbon/PackedTangents.fxh - shaders/include/Carbon/ParticleAnnotations.fxh - shaders/include/Carbon/RandomXOrShift.fxh - shaders/include/Carbon/System.fxh - shaders/include/Carbon/Tr2CurveLineSet.fxh - shaders/include/Carbon/VertexBufferUtil.fxh - shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx - shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx - shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx - shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx - shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx - shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx - shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx - shaders/Managed/Space/System/Raytracing/SkinVertices.fx - shaders/Managed/Space/System/ComputeLightLists.fx - shaders/Managed/Space/System/Denoise1D.fx - shaders/Managed/Space/System/DenoiseEstimate.fx - shaders/Managed/Space/System/EstimateNoise.fx - shaders/Managed/Utility/BillboardNoZ.fx - shaders/Managed/Utility/BillboardPicking.fx - shaders/Managed/Utility/Debug.fx - shaders/Managed/Utility/DebugLine.fx - shaders/Managed/Utility/DebugPrimitive.fx - shaders/Managed/Utility/DebugPrimitivePicking.fx - shaders/Managed/Utility/Lines.fxh - shaders/Managed/Utility/LinesNoZ.fx - shaders/Managed/Utility/LinesRotationTool.fx - shaders/Managed/Utility/LinesRotationToolLH.fx - shaders/Managed/Utility/LinesWithZ.fx - shaders/Managed/Utility/PerFrameVSData.fxh - shaders/Managed/Utility/PrimitivePicking.fx - shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx - shaders/Managed/Utility/Solids.fxh - shaders/Managed/Utility/SolidsNoZ.fx - shaders/Managed/Utility/SolidsWithZ.fx - shaders/Utility/CubeTextureViewer.fx - shaders/Utility/GeometryViewer.fx - shaders/Utility/LineGraph.fx - shaders/Utility/TextureViewer.fx - ) - -add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) -source_group( - TREE "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - FILES ${_SHADER_SOURCES} -) - -install(DIRECTORY shaders/ DESTINATION shaders) diff --git a/shaders/CMakeLists.txt b/shaders/CMakeLists.txt new file mode 100644 index 000000000..89812b3f4 --- /dev/null +++ b/shaders/CMakeLists.txt @@ -0,0 +1,103 @@ +# Copyright © 2026 CCP ehf. + +cmake_minimum_required(VERSION 3.16) + +project(TrinityShaders VERSION 1.0.0) + +set(_SHADER_SOURCES + include/Carbon/InteriorScene/PerObjectData.fxh + include/Carbon/InteriorScene/PerSceneData.fxh + include/Carbon/SpaceScene/Raytracing/GeometryData.fxh + include/Carbon/SpaceScene/Raytracing/ShadowData.fxh + include/Carbon/SpaceScene/BehaviorGroupBooster.fxh + include/Carbon/SpaceScene/DepthMap.fxh + include/Carbon/SpaceScene/DynamicLighting.fxh + include/Carbon/SpaceScene/EnvironmentMap.fxh + include/Carbon/SpaceScene/EveBannerSet.fxh + include/Carbon/SpaceScene/EveBoosterSet.fxh + include/Carbon/SpaceScene/EveChildBoosterSet.fxh + include/Carbon/SpaceScene/EveChildBulletStorm.fxh + include/Carbon/SpaceScene/EveChildCloud.fxh + include/Carbon/SpaceScene/EveChildCloud2.fxh + include/Carbon/SpaceScene/EveHazeSet.fxh + include/Carbon/SpaceScene/EveLensflare.fxh + include/Carbon/SpaceScene/EveOccluder.fxh + include/Carbon/SpaceScene/EvePlaneSet.fxh + include/Carbon/SpaceScene/EveChildQuad.fxh + include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh + include/Carbon/SpaceScene/EveSpherePin.fxh + include/Carbon/SpaceScene/EveSpotlightSet.fxh + include/Carbon/SpaceScene/EveSpriteSet.fxh + include/Carbon/SpaceScene/EveStarfield.fxh + include/Carbon/SpaceScene/EveTransform.fxh + include/Carbon/SpaceScene/EveStretch2.fxh + include/Carbon/SpaceScene/EveTacticalOverlay.fxh + include/Carbon/SpaceScene/EveTurretSet.fxh + include/Carbon/SpaceScene/FroxelFog.fxh + include/Carbon/SpaceScene/GpuParticles.fxh + include/Carbon/SpaceScene/MeshMorphing.fxh + include/Carbon/SpaceScene/PerObjectData.fxh + include/Carbon/SpaceScene/PerSceneData.fxh + include/Carbon/SpaceScene/Volumetrics.fxh + include/Carbon/UI/UI.fxh + include/Carbon/Bindless.fxh + include/Carbon/BoneTransforms.fxh + include/Carbon/Intersections.fxh + include/Carbon/Math.fxh + include/Carbon/PackedTangents.fxh + include/Carbon/ParticleAnnotations.fxh + include/Carbon/RandomXOrShift.fxh + include/Carbon/System.fxh + include/Carbon/Tr2CurveLineSet.fxh + include/Carbon/VertexBufferUtil.fxh + src/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx + src/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx + src/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx + src/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx + src/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx + src/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx + src/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx + src/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx + src/Managed/Space/SpecialFX/Particles/Gpu/Update.fx + src/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx + src/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx + src/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx + src/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx + src/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx + src/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx + src/Managed/Space/System/Raytracing/SkinVertices.fx + src/Managed/Space/System/ComputeLightLists.fx + src/Managed/Space/System/Denoise1D.fx + src/Managed/Space/System/DenoiseEstimate.fx + src/Managed/Space/System/EstimateNoise.fx + src/Managed/Utility/BillboardNoZ.fx + src/Managed/Utility/BillboardPicking.fx + src/Managed/Utility/Debug.fx + src/Managed/Utility/DebugLine.fx + src/Managed/Utility/DebugPrimitive.fx + src/Managed/Utility/DebugPrimitivePicking.fx + src/Managed/Utility/Lines.fxh + src/Managed/Utility/LinesNoZ.fx + src/Managed/Utility/LinesRotationTool.fx + src/Managed/Utility/LinesRotationToolLH.fx + src/Managed/Utility/LinesWithZ.fx + src/Managed/Utility/PerFrameVSData.fxh + src/Managed/Utility/PrimitivePicking.fx + src/Managed/Utility/SolidNoLightNoCullWithZ.fx + src/Managed/Utility/Solids.fxh + src/Managed/Utility/SolidsNoZ.fx + src/Managed/Utility/SolidsWithZ.fx + src/Utility/CubeTextureViewer.fx + src/Utility/GeometryViewer.fx + src/Utility/LineGraph.fx + src/Utility/TextureViewer.fx + ) + +add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) +source_group( + TREE "${CMAKE_CURRENT_SOURCE_DIR}" + FILES ${_SHADER_SOURCES} +) + +install(DIRECTORY shaders/include DESTINATION shaders) +install(DIRECTORY shaders/src DESTINATION shaders) From faa72ee080f96fbde52bb3108b5abb88f4774a8a Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 12 Oct 2026 10:26:01 +0000 Subject: [PATCH 36/83] Fix the build and address some PR comments --- shadercompiler/CachingIncludeHandler.cpp | 24 ++++++++++++++++++++++-- shadercompiler/MSLInclude.h | 7 +++++-- shadercompiler/ModifiedTime.cpp | 11 ++++++----- shadercompiler/ParserUtils.cpp | 2 +- shaders/CMakeLists.txt | 4 ++-- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/shadercompiler/CachingIncludeHandler.cpp b/shadercompiler/CachingIncludeHandler.cpp index 00f89401e..d80eadccc 100644 --- a/shadercompiler/CachingIncludeHandler.cpp +++ b/shadercompiler/CachingIncludeHandler.cpp @@ -61,6 +61,26 @@ std::optional JoinPath( const char* path1, const char* path2 ) #endif } +std::optional JoinPathAndCheckExists( const char* path1, const char* path2 ) +{ + if( auto joined = JoinPath( path1, path2 ) ) + { +#if _WIN32 + if( PathFileExists( joined->c_str() ) ) + { + return joined; + } +#else + struct stat buffer; + if( stat( joined->c_str(), &buffer ) == 0 ) + { + return joined; + } +#endif + } + return std::nullopt; +} + } @@ -110,7 +130,7 @@ std::optional CachingIncludeHandler::Open( parentPath = ""; } } - if( auto joined = JoinPath( parentPath.c_str(), fileName ) ) + if( auto joined = JoinPathAndCheckExists( parentPath.c_str(), fileName ) ) { fullPath = *joined; return true; @@ -120,7 +140,7 @@ std::optional CachingIncludeHandler::Open( auto FindSystemPath = [&]() -> bool { for( auto it = m_systemIncludePaths.begin(); it != m_systemIncludePaths.end(); ++it ) { - if( auto joined = JoinPath( it->c_str(), fileName ) ) + if( auto joined = JoinPathAndCheckExists( it->c_str(), fileName ) ) { fullPath = *joined; return true; diff --git a/shadercompiler/MSLInclude.h b/shadercompiler/MSLInclude.h index 8916757f1..df28ca854 100644 --- a/shadercompiler/MSLInclude.h +++ b/shadercompiler/MSLInclude.h @@ -335,11 +335,14 @@ void GetDimensions( texturecube tex, thread W& w, thread H& h ) template void GetDimensions( texturecube tex, uint mip, thread W& w, thread H& h, thread M& m ) { - w = W( tex.get_width() ); - h = H( tex.get_height() ); + w = W( tex.get_width( mip ) ); + h = H( tex.get_height( mip ) ); m = M( tex.get_num_mip_levels() ); } +)MSL" +R"MSL( + template void GetDimensions( texture3d tex, thread W& w, thread H& h, thread D& d ) { diff --git a/shadercompiler/ModifiedTime.cpp b/shadercompiler/ModifiedTime.cpp index b741bdd24..4dbee5566 100644 --- a/shadercompiler/ModifiedTime.cpp +++ b/shadercompiler/ModifiedTime.cpp @@ -47,7 +47,7 @@ struct HashCheckArguments std::mutex s_modifiedOutputsCS; std::set s_modifiedOutputs; -const std::regex s_include( "#[[:space:]]*include[[:space:]]*[<\"]([^>\"]*)" ); +const std::regex s_include( "#[[:space:]]*include[[:space:]]*([<\"])([^>\"]*)" ); bool IsOutputUpToDate( const char* path, const std::string& sourceHash ) { @@ -112,14 +112,14 @@ bool CheckHash( const HashCheckArguments& query ) return true; } -void GetSourceHash( const char* sourcePath, const char* parentData, const char* rootPath, std::set& visited, MD5& md5 ) +void GetSourceHash( const char* sourcePath, const char* parentData, const char* rootPath, CachingIncludeHandler::IncludeType includeType, std::set& visited, MD5& md5 ) { if( visited.find( sourcePath ) != end( visited ) ) { return; } visited.insert( sourcePath ); - if( auto opened = s_includeHandler.Open( sourcePath, CachingIncludeHandler::IncludeLocal, parentData, rootPath ) ) + if( auto opened = s_includeHandler.Open( sourcePath, includeType, parentData, rootPath ) ) { md5.add( opened->data, opened->size ); @@ -127,7 +127,8 @@ void GetSourceHash( const char* sourcePath, const char* parentData, const char* auto begin = opened->data; while( std::regex_search( begin, opened->data + opened->size, match, s_include ) ) { - GetSourceHash( match[1].str().c_str(), opened->data, rootPath, visited, md5 ); + CachingIncludeHandler::IncludeType it = match[1].str() == "<" ? CachingIncludeHandler::IncludeSystem : CachingIncludeHandler::IncludeLocal; + GetSourceHash( match[2].str().c_str(), opened->data, rootPath, it, visited, md5 ); begin += match.position() + match.length(); } } @@ -159,7 +160,7 @@ std::string GetSourceHash( const char* sourcePath, const std::vector& def md5.add( &g_generatePDB, sizeof( g_generatePDB ) ); md5.add( &g_skipOptimization, sizeof( g_skipOptimization ) ); - GetSourceHash( sourcePath, nullptr, sourcePath, visited, md5 ); + GetSourceHash( sourcePath, nullptr, sourcePath, CachingIncludeHandler::IncludeLocal, visited, md5 ); return md5.getHash(); } diff --git a/shadercompiler/ParserUtils.cpp b/shadercompiler/ParserUtils.cpp index 2d0f33e76..a3c313409 100644 --- a/shadercompiler/ParserUtils.cpp +++ b/shadercompiler/ParserUtils.cpp @@ -921,7 +921,7 @@ int GetNodeOrder( ASTNode* t ) } else { - if ( t->GetType().modifier == OP_CONST && t->GetType().storageClass == OP_STATIC ) + if( t->GetType().modifier == OP_CONST && t->GetType().storageClass == OP_STATIC ) { return 1; } diff --git a/shaders/CMakeLists.txt b/shaders/CMakeLists.txt index 89812b3f4..3f6da3262 100644 --- a/shaders/CMakeLists.txt +++ b/shaders/CMakeLists.txt @@ -99,5 +99,5 @@ source_group( FILES ${_SHADER_SOURCES} ) -install(DIRECTORY shaders/include DESTINATION shaders) -install(DIRECTORY shaders/src DESTINATION shaders) +install(DIRECTORY include DESTINATION shaders) +install(DIRECTORY src DESTINATION shaders) From f47af7167fa5eec5c0bd3fd60d0c461f9a63ea3b Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 12 Oct 2026 10:38:11 +0000 Subject: [PATCH 37/83] Formatting --- shadercompiler/MSLInclude.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shadercompiler/MSLInclude.h b/shadercompiler/MSLInclude.h index df28ca854..0bf2a50a4 100644 --- a/shadercompiler/MSLInclude.h +++ b/shadercompiler/MSLInclude.h @@ -341,7 +341,7 @@ void GetDimensions( texturecube tex, uint mip, thread W& w, thread H& h, thre } )MSL" -R"MSL( + R"MSL( template void GetDimensions( texture3d tex, thread W& w, thread H& h, thread D& d ) From 6f4c172baf6f80de51c9c4b8d4d2d946b5f56ef9 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 12 Oct 2026 10:57:19 +0000 Subject: [PATCH 38/83] Move "src" files back up the directory so that local includes are still valid --- .../Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx | 0 shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx | 0 shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx | 0 .../Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx | 0 .../Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx | 0 shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx | 0 .../{src => }/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx | 0 .../{src => }/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx | 0 shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Update.fx | 0 .../Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx | 0 .../Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx | 0 .../Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx | 0 .../Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx | 0 .../Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx | 0 .../Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx | 0 shaders/{src => }/Managed/Space/System/ComputeLightLists.fx | 0 shaders/{src => }/Managed/Space/System/Denoise1D.fx | 0 shaders/{src => }/Managed/Space/System/DenoiseEstimate.fx | 0 shaders/{src => }/Managed/Space/System/EstimateNoise.fx | 0 shaders/{src => }/Managed/Space/System/Raytracing/SkinVertices.fx | 0 shaders/{src => }/Managed/Utility/BillboardNoZ.fx | 0 shaders/{src => }/Managed/Utility/BillboardPicking.fx | 0 shaders/{src => }/Managed/Utility/Debug.fx | 0 shaders/{src => }/Managed/Utility/DebugLine.fx | 0 shaders/{src => }/Managed/Utility/DebugPrimitive.fx | 0 shaders/{src => }/Managed/Utility/DebugPrimitivePicking.fx | 0 shaders/{src => }/Managed/Utility/Lines.fxh | 0 shaders/{src => }/Managed/Utility/LinesNoZ.fx | 0 shaders/{src => }/Managed/Utility/LinesRotationTool.fx | 0 shaders/{src => }/Managed/Utility/LinesRotationToolLH.fx | 0 shaders/{src => }/Managed/Utility/LinesWithZ.fx | 0 shaders/{src => }/Managed/Utility/PerFrameVSData.fxh | 0 shaders/{src => }/Managed/Utility/PrimitivePicking.fx | 0 shaders/{src => }/Managed/Utility/SolidNoLightNoCullWithZ.fx | 0 shaders/{src => }/Managed/Utility/Solids.fxh | 0 shaders/{src => }/Managed/Utility/SolidsNoZ.fx | 0 shaders/{src => }/Managed/Utility/SolidsWithZ.fx | 0 shaders/{src => }/Utility/CubeTextureViewer.fx | 0 shaders/{src => }/Utility/GeometryViewer.fx | 0 shaders/{src => }/Utility/LineGraph.fx | 0 shaders/{src => }/Utility/TextureViewer.fx | 0 41 files changed, 0 insertions(+), 0 deletions(-) rename shaders/{src => }/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Update.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx (100%) rename shaders/{src => }/Managed/Space/System/ComputeLightLists.fx (100%) rename shaders/{src => }/Managed/Space/System/Denoise1D.fx (100%) rename shaders/{src => }/Managed/Space/System/DenoiseEstimate.fx (100%) rename shaders/{src => }/Managed/Space/System/EstimateNoise.fx (100%) rename shaders/{src => }/Managed/Space/System/Raytracing/SkinVertices.fx (100%) rename shaders/{src => }/Managed/Utility/BillboardNoZ.fx (100%) rename shaders/{src => }/Managed/Utility/BillboardPicking.fx (100%) rename shaders/{src => }/Managed/Utility/Debug.fx (100%) rename shaders/{src => }/Managed/Utility/DebugLine.fx (100%) rename shaders/{src => }/Managed/Utility/DebugPrimitive.fx (100%) rename shaders/{src => }/Managed/Utility/DebugPrimitivePicking.fx (100%) rename shaders/{src => }/Managed/Utility/Lines.fxh (100%) rename shaders/{src => }/Managed/Utility/LinesNoZ.fx (100%) rename shaders/{src => }/Managed/Utility/LinesRotationTool.fx (100%) rename shaders/{src => }/Managed/Utility/LinesRotationToolLH.fx (100%) rename shaders/{src => }/Managed/Utility/LinesWithZ.fx (100%) rename shaders/{src => }/Managed/Utility/PerFrameVSData.fxh (100%) rename shaders/{src => }/Managed/Utility/PrimitivePicking.fx (100%) rename shaders/{src => }/Managed/Utility/SolidNoLightNoCullWithZ.fx (100%) rename shaders/{src => }/Managed/Utility/Solids.fxh (100%) rename shaders/{src => }/Managed/Utility/SolidsNoZ.fx (100%) rename shaders/{src => }/Managed/Utility/SolidsWithZ.fx (100%) rename shaders/{src => }/Utility/CubeTextureViewer.fx (100%) rename shaders/{src => }/Utility/GeometryViewer.fx (100%) rename shaders/{src => }/Utility/LineGraph.fx (100%) rename shaders/{src => }/Utility/TextureViewer.fx (100%) diff --git a/shaders/src/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx b/shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx rename to shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Update.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Update.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx b/shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx rename to shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx b/shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx rename to shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx rename to shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx rename to shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx rename to shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx rename to shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx diff --git a/shaders/src/Managed/Space/System/ComputeLightLists.fx b/shaders/Managed/Space/System/ComputeLightLists.fx similarity index 100% rename from shaders/src/Managed/Space/System/ComputeLightLists.fx rename to shaders/Managed/Space/System/ComputeLightLists.fx diff --git a/shaders/src/Managed/Space/System/Denoise1D.fx b/shaders/Managed/Space/System/Denoise1D.fx similarity index 100% rename from shaders/src/Managed/Space/System/Denoise1D.fx rename to shaders/Managed/Space/System/Denoise1D.fx diff --git a/shaders/src/Managed/Space/System/DenoiseEstimate.fx b/shaders/Managed/Space/System/DenoiseEstimate.fx similarity index 100% rename from shaders/src/Managed/Space/System/DenoiseEstimate.fx rename to shaders/Managed/Space/System/DenoiseEstimate.fx diff --git a/shaders/src/Managed/Space/System/EstimateNoise.fx b/shaders/Managed/Space/System/EstimateNoise.fx similarity index 100% rename from shaders/src/Managed/Space/System/EstimateNoise.fx rename to shaders/Managed/Space/System/EstimateNoise.fx diff --git a/shaders/src/Managed/Space/System/Raytracing/SkinVertices.fx b/shaders/Managed/Space/System/Raytracing/SkinVertices.fx similarity index 100% rename from shaders/src/Managed/Space/System/Raytracing/SkinVertices.fx rename to shaders/Managed/Space/System/Raytracing/SkinVertices.fx diff --git a/shaders/src/Managed/Utility/BillboardNoZ.fx b/shaders/Managed/Utility/BillboardNoZ.fx similarity index 100% rename from shaders/src/Managed/Utility/BillboardNoZ.fx rename to shaders/Managed/Utility/BillboardNoZ.fx diff --git a/shaders/src/Managed/Utility/BillboardPicking.fx b/shaders/Managed/Utility/BillboardPicking.fx similarity index 100% rename from shaders/src/Managed/Utility/BillboardPicking.fx rename to shaders/Managed/Utility/BillboardPicking.fx diff --git a/shaders/src/Managed/Utility/Debug.fx b/shaders/Managed/Utility/Debug.fx similarity index 100% rename from shaders/src/Managed/Utility/Debug.fx rename to shaders/Managed/Utility/Debug.fx diff --git a/shaders/src/Managed/Utility/DebugLine.fx b/shaders/Managed/Utility/DebugLine.fx similarity index 100% rename from shaders/src/Managed/Utility/DebugLine.fx rename to shaders/Managed/Utility/DebugLine.fx diff --git a/shaders/src/Managed/Utility/DebugPrimitive.fx b/shaders/Managed/Utility/DebugPrimitive.fx similarity index 100% rename from shaders/src/Managed/Utility/DebugPrimitive.fx rename to shaders/Managed/Utility/DebugPrimitive.fx diff --git a/shaders/src/Managed/Utility/DebugPrimitivePicking.fx b/shaders/Managed/Utility/DebugPrimitivePicking.fx similarity index 100% rename from shaders/src/Managed/Utility/DebugPrimitivePicking.fx rename to shaders/Managed/Utility/DebugPrimitivePicking.fx diff --git a/shaders/src/Managed/Utility/Lines.fxh b/shaders/Managed/Utility/Lines.fxh similarity index 100% rename from shaders/src/Managed/Utility/Lines.fxh rename to shaders/Managed/Utility/Lines.fxh diff --git a/shaders/src/Managed/Utility/LinesNoZ.fx b/shaders/Managed/Utility/LinesNoZ.fx similarity index 100% rename from shaders/src/Managed/Utility/LinesNoZ.fx rename to shaders/Managed/Utility/LinesNoZ.fx diff --git a/shaders/src/Managed/Utility/LinesRotationTool.fx b/shaders/Managed/Utility/LinesRotationTool.fx similarity index 100% rename from shaders/src/Managed/Utility/LinesRotationTool.fx rename to shaders/Managed/Utility/LinesRotationTool.fx diff --git a/shaders/src/Managed/Utility/LinesRotationToolLH.fx b/shaders/Managed/Utility/LinesRotationToolLH.fx similarity index 100% rename from shaders/src/Managed/Utility/LinesRotationToolLH.fx rename to shaders/Managed/Utility/LinesRotationToolLH.fx diff --git a/shaders/src/Managed/Utility/LinesWithZ.fx b/shaders/Managed/Utility/LinesWithZ.fx similarity index 100% rename from shaders/src/Managed/Utility/LinesWithZ.fx rename to shaders/Managed/Utility/LinesWithZ.fx diff --git a/shaders/src/Managed/Utility/PerFrameVSData.fxh b/shaders/Managed/Utility/PerFrameVSData.fxh similarity index 100% rename from shaders/src/Managed/Utility/PerFrameVSData.fxh rename to shaders/Managed/Utility/PerFrameVSData.fxh diff --git a/shaders/src/Managed/Utility/PrimitivePicking.fx b/shaders/Managed/Utility/PrimitivePicking.fx similarity index 100% rename from shaders/src/Managed/Utility/PrimitivePicking.fx rename to shaders/Managed/Utility/PrimitivePicking.fx diff --git a/shaders/src/Managed/Utility/SolidNoLightNoCullWithZ.fx b/shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx similarity index 100% rename from shaders/src/Managed/Utility/SolidNoLightNoCullWithZ.fx rename to shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx diff --git a/shaders/src/Managed/Utility/Solids.fxh b/shaders/Managed/Utility/Solids.fxh similarity index 100% rename from shaders/src/Managed/Utility/Solids.fxh rename to shaders/Managed/Utility/Solids.fxh diff --git a/shaders/src/Managed/Utility/SolidsNoZ.fx b/shaders/Managed/Utility/SolidsNoZ.fx similarity index 100% rename from shaders/src/Managed/Utility/SolidsNoZ.fx rename to shaders/Managed/Utility/SolidsNoZ.fx diff --git a/shaders/src/Managed/Utility/SolidsWithZ.fx b/shaders/Managed/Utility/SolidsWithZ.fx similarity index 100% rename from shaders/src/Managed/Utility/SolidsWithZ.fx rename to shaders/Managed/Utility/SolidsWithZ.fx diff --git a/shaders/src/Utility/CubeTextureViewer.fx b/shaders/Utility/CubeTextureViewer.fx similarity index 100% rename from shaders/src/Utility/CubeTextureViewer.fx rename to shaders/Utility/CubeTextureViewer.fx diff --git a/shaders/src/Utility/GeometryViewer.fx b/shaders/Utility/GeometryViewer.fx similarity index 100% rename from shaders/src/Utility/GeometryViewer.fx rename to shaders/Utility/GeometryViewer.fx diff --git a/shaders/src/Utility/LineGraph.fx b/shaders/Utility/LineGraph.fx similarity index 100% rename from shaders/src/Utility/LineGraph.fx rename to shaders/Utility/LineGraph.fx diff --git a/shaders/src/Utility/TextureViewer.fx b/shaders/Utility/TextureViewer.fx similarity index 100% rename from shaders/src/Utility/TextureViewer.fx rename to shaders/Utility/TextureViewer.fx From 55f482454cb0313d52e5ff5d09a412868be55a31 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 12 Oct 2026 12:44:26 +0000 Subject: [PATCH 39/83] Update shader paths --- shaders/CMakeLists.txt | 85 +++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/shaders/CMakeLists.txt b/shaders/CMakeLists.txt index 3f6da3262..d8146bab9 100644 --- a/shaders/CMakeLists.txt +++ b/shaders/CMakeLists.txt @@ -50,47 +50,47 @@ set(_SHADER_SOURCES include/Carbon/System.fxh include/Carbon/Tr2CurveLineSet.fxh include/Carbon/VertexBufferUtil.fxh - src/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx - src/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx - src/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx - src/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx - src/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx - src/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx - src/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx - src/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx - src/Managed/Space/SpecialFX/Particles/Gpu/Update.fx - src/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx - src/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx - src/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx - src/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx - src/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx - src/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx - src/Managed/Space/System/Raytracing/SkinVertices.fx - src/Managed/Space/System/ComputeLightLists.fx - src/Managed/Space/System/Denoise1D.fx - src/Managed/Space/System/DenoiseEstimate.fx - src/Managed/Space/System/EstimateNoise.fx - src/Managed/Utility/BillboardNoZ.fx - src/Managed/Utility/BillboardPicking.fx - src/Managed/Utility/Debug.fx - src/Managed/Utility/DebugLine.fx - src/Managed/Utility/DebugPrimitive.fx - src/Managed/Utility/DebugPrimitivePicking.fx - src/Managed/Utility/Lines.fxh - src/Managed/Utility/LinesNoZ.fx - src/Managed/Utility/LinesRotationTool.fx - src/Managed/Utility/LinesRotationToolLH.fx - src/Managed/Utility/LinesWithZ.fx - src/Managed/Utility/PerFrameVSData.fxh - src/Managed/Utility/PrimitivePicking.fx - src/Managed/Utility/SolidNoLightNoCullWithZ.fx - src/Managed/Utility/Solids.fxh - src/Managed/Utility/SolidsNoZ.fx - src/Managed/Utility/SolidsWithZ.fx - src/Utility/CubeTextureViewer.fx - src/Utility/GeometryViewer.fx - src/Utility/LineGraph.fx - src/Utility/TextureViewer.fx + Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx + Managed/Space/SpecialFX/Particles/Gpu/Clear.fx + Managed/Space/SpecialFX/Particles/Gpu/Emit.fx + Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx + Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx + Managed/Space/SpecialFX/Particles/Gpu/Sort.fx + Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx + Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx + Managed/Space/SpecialFX/Particles/Gpu/Update.fx + Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx + Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx + Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx + Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx + Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx + Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx + Managed/Space/System/Raytracing/SkinVertices.fx + Managed/Space/System/ComputeLightLists.fx + Managed/Space/System/Denoise1D.fx + Managed/Space/System/DenoiseEstimate.fx + Managed/Space/System/EstimateNoise.fx + Managed/Utility/BillboardNoZ.fx + Managed/Utility/BillboardPicking.fx + Managed/Utility/Debug.fx + Managed/Utility/DebugLine.fx + Managed/Utility/DebugPrimitive.fx + Managed/Utility/DebugPrimitivePicking.fx + Managed/Utility/Lines.fxh + Managed/Utility/LinesNoZ.fx + Managed/Utility/LinesRotationTool.fx + Managed/Utility/LinesRotationToolLH.fx + Managed/Utility/LinesWithZ.fx + Managed/Utility/PerFrameVSData.fxh + Managed/Utility/PrimitivePicking.fx + Managed/Utility/SolidNoLightNoCullWithZ.fx + Managed/Utility/Solids.fxh + Managed/Utility/SolidsNoZ.fx + Managed/Utility/SolidsWithZ.fx + Utility/CubeTextureViewer.fx + Utility/GeometryViewer.fx + Utility/LineGraph.fx + Utility/TextureViewer.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) @@ -99,5 +99,4 @@ source_group( FILES ${_SHADER_SOURCES} ) -install(DIRECTORY include DESTINATION shaders) -install(DIRECTORY src DESTINATION shaders) +install(DIRECTORY . DESTINATION shaders FILES_MATCHING PATTERN "*.fx" PATTERN "*.fxh") From ce8de026420e92bd3d221e5526ac27d1f62fd04c Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Tue, 13 Oct 2026 13:01:09 +0000 Subject: [PATCH 40/83] Address PR comments --- shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx | 2 ++ shaders/Managed/Space/System/ComputeLightLists.fx | 2 +- shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx index d7c94669d..f778edf3b 100644 --- a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx @@ -121,6 +121,8 @@ void Emit( uint3 grid : SV_GroupID, uint groupIndex : SV_GroupIndex, uint3 threa } else { + int ignored; + InterlockedAdd( ParticleCounters[0], 1, ignored ); break; } } diff --git a/shaders/Managed/Space/System/ComputeLightLists.fx b/shaders/Managed/Space/System/ComputeLightLists.fx index c4189c855..62614cb23 100644 --- a/shaders/Managed/Space/System/ComputeLightLists.fx +++ b/shaders/Managed/Space/System/ComputeLightLists.fx @@ -179,7 +179,7 @@ void AddLight( uint light, uint heapOffset, uint indexBufferSize, bool transpare uint head = iHead; head = head * 2 + heapOffset; - if( head < indexBufferSize ) + if( head + 1 < indexBufferSize ) { if( transparent ) { diff --git a/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh b/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh index f856aa356..e551c5937 100644 --- a/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh +++ b/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh @@ -47,6 +47,7 @@ EveSpaceObjectData CreateEveSpaceObjectData( EveSpaceObjectDecalDataVS perObject EveSpaceObjectData pod; pod.WorldMat = perObjectData.WorldMat; pod.WorldMatLast = (float4x4)0; + pod.InvWorldMat = perObjectData.InvWorldMat; pod.BoneOffsets = (uint4)0; pod.Shipdata = (float4)0; From 1c8aa77772cf8bd30469bc353b1365df2f061a0b Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Tue, 22 Sep 2026 14:53:28 +0000 Subject: [PATCH 41/83] Add CLI argument to specify additional include directories for the shader compiler --- shadercompiler/CachingIncludeHandler.cpp | 63 ++++++++++++++++++------ shadercompiler/CachingIncludeHandler.h | 11 ++++- shadercompiler/HLSLScanner.re | 19 +++---- shadercompiler/ModifiedTime.cpp | 2 +- shadercompiler/ParserState.cpp | 4 +- shadercompiler/ParserState.h | 3 +- shadercompiler/ShaderCompiler.cpp | 17 ++++++- 7 files changed, 87 insertions(+), 32 deletions(-) diff --git a/shadercompiler/CachingIncludeHandler.cpp b/shadercompiler/CachingIncludeHandler.cpp index 7f2150290..00f89401e 100644 --- a/shadercompiler/CachingIncludeHandler.cpp +++ b/shadercompiler/CachingIncludeHandler.cpp @@ -85,37 +85,62 @@ CachingIncludeHandler::~CachingIncludeHandler() // used for resolving relative paths // rootPath - Custom root path for resolving relative paths // -------------------------------------------------------------------------------------- -std::optional CachingIncludeHandler::Open( const char* fileName, const char* parentData, const char* rootPath ) +std::optional CachingIncludeHandler::Open( const char* fileName, IncludeType includeType, const char* parentData, const char* rootPath ) { std::lock_guard scope( m_cs ); std::string fullPath; if( PathIsRelative( fileName ) ) { - std::string parentPath; - if( parentData == nullptr ) - { - parentPath = rootPath ? rootPath : m_rootPath; - } - else - { - auto parent = m_pathFromFile.find( parentData - 1 ); - if( parent != m_pathFromFile.end() ) + auto FindLocalPath = [&]() -> bool { + std::string parentPath; + if( parentData == nullptr ) { - parentPath = parent->second; + parentPath = rootPath ? rootPath : m_rootPath; } else { - parentPath = ""; + auto parent = m_pathFromFile.find( parentData - 1 ); + if( parent != m_pathFromFile.end() ) + { + parentPath = parent->second; + } + else + { + parentPath = ""; + } } - } - if( auto joined = JoinPath( parentPath.c_str(), fileName ) ) + if( auto joined = JoinPath( parentPath.c_str(), fileName ) ) + { + fullPath = *joined; + return true; + } + return false; + }; + auto FindSystemPath = [&]() -> bool { + for( auto it = m_systemIncludePaths.begin(); it != m_systemIncludePaths.end(); ++it ) + { + if( auto joined = JoinPath( it->c_str(), fileName ) ) + { + fullPath = *joined; + return true; + } + } + return false; + }; + if( includeType == IncludeLocal ) { - fullPath = *joined; + if( !FindLocalPath() && !FindSystemPath() ) + { + return std::nullopt; + } } else { - return std::nullopt; + if( !FindSystemPath() && !FindLocalPath() ) + { + return std::nullopt; + } } } else @@ -221,6 +246,12 @@ std::optional CachingIncludeHandler::AddPre return info; } +void CachingIncludeHandler::AddSystemIncludePath( const char* path ) +{ + std::lock_guard scope( m_cs ); + m_systemIncludePaths.push_back( path ); +} + // -------------------------------------------------------------------------------------- // Description: // Assigns path to the "root", entry point file. diff --git a/shadercompiler/CachingIncludeHandler.h b/shadercompiler/CachingIncludeHandler.h index 48672b78d..91333c648 100644 --- a/shadercompiler/CachingIncludeHandler.h +++ b/shadercompiler/CachingIncludeHandler.h @@ -22,12 +22,20 @@ class CachingIncludeHandler time_t modifiedTime; }; - std::optional Open( const char* fileName, const char* parentData = nullptr, const char* rootPath = nullptr ); + enum IncludeType + { + IncludeLocal, + IncludeSystem + }; + + std::optional Open( const char* fileName, IncludeType includeType, const char* parentData = nullptr, const char* rootPath = nullptr ); void SetRootPath( const char* shaderPath ); std::optional AddPrefix( const char* fileName, const char* prefix ); + void AddSystemIncludePath( const char* path ); + private: typedef std::map PathFromFile; typedef std::map FileFromPath; @@ -38,6 +46,7 @@ class CachingIncludeHandler FileFromPath m_fileFromPath; // Path of the entry point file std::string m_rootPath; + std::vector m_systemIncludePaths; std::mutex m_cs; }; diff --git a/shadercompiler/HLSLScanner.re b/shadercompiler/HLSLScanner.re index ee976dec2..259505133 100644 --- a/shadercompiler/HLSLScanner.re +++ b/shadercompiler/HLSLScanner.re @@ -41,16 +41,16 @@ ID = LETTER(LETTER|DECIMAL)*; #define YYMARKER (marker) #define YYCTXMARKER (ctxMarker) -bool GetIncludePath( ParserState &state, InlineString& path ) +bool GetIncludePath( ParserState &state, InlineString& path, CachingIncludeHandler::IncludeType& includeType ) { - bool local; + includeType = CachingIncludeHandler::IncludeLocal; if( *YYCURSOR == '"' ) { - local = true; + includeType = CachingIncludeHandler::IncludeLocal; } else if( *YYCURSOR == '<' ) { - local = false; + includeType = CachingIncludeHandler::IncludeSystem; } else { @@ -61,7 +61,7 @@ bool GetIncludePath( ParserState &state, InlineString& path ) { if( *YYCURSOR == '"' ) { - if( local ) + if( includeType == CachingIncludeHandler::IncludeLocal ) { path.end = ++YYCURSOR; return true; @@ -69,7 +69,7 @@ bool GetIncludePath( ParserState &state, InlineString& path ) } else if( *YYCURSOR == '>' ) { - if( !local ) + if( includeType == CachingIncludeHandler::IncludeSystem ) { path.end = ++YYCURSOR; return true; @@ -141,14 +141,15 @@ std: { state.GetCurrentLocation().lineNumber++; InlineString path; - if( !GetIncludePath( state, path ) ) + CachingIncludeHandler::IncludeType includeType; + if( !GetIncludePath( state, path, includeType ) ) { state.ShowMessage( EC_INVALID_INCLUDE_PATH ); return PPSR_ERROR; } if( !state.InSkipMode() ) { - state.IncludeFile( path ); + state.IncludeFile( path, includeType ); } start = YYCURSOR; continue; @@ -566,7 +567,7 @@ std: ++YYCURSOR; } - if( !state.InSkipMode() ) + if( !state.InSkipMode() && !state.InDiscoverMode() ) { state.ShowMessage( EC_USER_ERROR, std::string( start, YYCURSOR ).c_str() ); return PPSR_ERROR; diff --git a/shadercompiler/ModifiedTime.cpp b/shadercompiler/ModifiedTime.cpp index bd11d80ad..b741bdd24 100644 --- a/shadercompiler/ModifiedTime.cpp +++ b/shadercompiler/ModifiedTime.cpp @@ -119,7 +119,7 @@ void GetSourceHash( const char* sourcePath, const char* parentData, const char* return; } visited.insert( sourcePath ); - if( auto opened = s_includeHandler.Open( sourcePath, parentData, rootPath ) ) + if( auto opened = s_includeHandler.Open( sourcePath, CachingIncludeHandler::IncludeLocal, parentData, rootPath ) ) { md5.add( opened->data, opened->size ); diff --git a/shadercompiler/ParserState.cpp b/shadercompiler/ParserState.cpp index 6883c82b1..3e604aec0 100644 --- a/shadercompiler/ParserState.cpp +++ b/shadercompiler/ParserState.cpp @@ -988,12 +988,12 @@ bool ParserState::InMacro() const return m_fileStack.back().isMacro; } -void ParserState::IncludeFile( const InlineString& fileName ) +void ParserState::IncludeFile( const InlineString& fileName, CachingIncludeHandler::IncludeType includeType ) { extern CachingIncludeHandler g_includeHandler; std::string path( fileName.start + 1, fileName.end - 1 ); - if( auto file = g_includeHandler.Open( path.c_str(), m_fileStack.back().code.start + 1 ) ) + if( auto file = g_includeHandler.Open( path.c_str(), includeType, m_fileStack.back().code.start + 1 ) ) { FileContents fileContents; diff --git a/shadercompiler/ParserState.h b/shadercompiler/ParserState.h index 1bafdde7f..73cdc73d7 100644 --- a/shadercompiler/ParserState.h +++ b/shadercompiler/ParserState.h @@ -3,6 +3,7 @@ #pragma once #include "InlineString.h" +#include "CachingIncludeHandler.h" class SymbolTable; class ASTNode; @@ -234,7 +235,7 @@ class ParserState bool InDiscoverMode() const; PreprocessorScanResult GetPreprocessorToken( PreprocessorToken& token ); - void IncludeFile( const InlineString& fileName ); + void IncludeFile( const InlineString& fileName, CachingIncludeHandler::IncludeType includeType ); void ParseDefine( const PreprocessorDefine& define, const FileLocation& location, const std::vector& arguments ); PreprocessorDefine* FindDefine( const InlineString& name ); diff --git a/shadercompiler/ShaderCompiler.cpp b/shadercompiler/ShaderCompiler.cpp index 294755c73..00d410db8 100644 --- a/shadercompiler/ShaderCompiler.cpp +++ b/shadercompiler/ShaderCompiler.cpp @@ -208,6 +208,7 @@ void PrintUsage() printf( " /E{e,w,d}[extension] - Specify support for all or certain GLES extensions\n" ); printf( " /novalidate - Skip validating converted GLSL code\n" ); printf( " /permutations - Print permutations of the shader\n" ); + printf( " /I - Specify additional include directory\n" ); #if CCP_TELEMETRY_ENABLED printf( " /telemetry - Enable RAD Telemetry\n" ); #endif @@ -302,6 +303,18 @@ bool ExtractCommandLineArguments( ProgramArguments& args, int argc, char* argv[] { args.ignorePermutations = true; } + else if( strcmp( argv[i], "/I" ) == 0 ) + { + ++i; + if( i < argc ) + { + g_includeHandler.AddSystemIncludePath( argv[i] ); + } + else + { + return false; + } + } else if( strcmp( argv[i], "/define" ) == 0 ) { Macro define; @@ -411,7 +424,7 @@ bool ExtractCommandLineArguments( ProgramArguments& args, int argc, char* argv[] bool PrintPermutations( const char* shaderPath ) { - auto shader = g_includeHandler.Open( shaderPath ); + auto shader = g_includeHandler.Open( shaderPath, CachingIncludeHandler::IncludeLocal ); if( !shader ) { @@ -624,7 +637,7 @@ int main( int argc, char* argv[] ) } // Preload shader file - auto shader = g_includeHandler.Open( args.shaderPath ); + auto shader = g_includeHandler.Open( args.shaderPath, CachingIncludeHandler::IncludeLocal ); if( !shader ) { printf( "%s: error X0000: Could not open input file \"%s\"\n", args.shaderPath, args.shaderPath ); From 89abc92ba8e335f60b554a82d2220a127fdff155 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Tue, 22 Sep 2026 15:00:05 +0000 Subject: [PATCH 42/83] Add some shader includes --- CMakeLists.txt | 2 + shaders/include/carbon/bindless.fxh | 97 +++++++++++++++++++ shaders/include/carbon/packedtangents.fxh | 81 ++++++++++++++++ .../include/carbon/particleannotations.fxh | 37 +++++++ shaders/include/carbon/system.fxh | 81 ++++++++++++++++ 5 files changed, 298 insertions(+) create mode 100644 shaders/include/carbon/bindless.fxh create mode 100644 shaders/include/carbon/packedtangents.fxh create mode 100644 shaders/include/carbon/particleannotations.fxh create mode 100644 shaders/include/carbon/system.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 907ca6a8d..9f77d9142 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,3 +139,5 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) ) endif() endif() + +install(DIRECTORY shaders/ DESTINATION shaders) diff --git a/shaders/include/carbon/bindless.fxh b/shaders/include/carbon/bindless.fxh new file mode 100644 index 000000000..7f4b20c41 --- /dev/null +++ b/shaders/include/carbon/bindless.fxh @@ -0,0 +1,97 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_BINDLESS_FXH +#define CARBON_BINDLESS_FXH + +#include "system.fxh" + +// Support for bindless rendering with Trinity. Difines types and functions to work with +// bindless resources and heap views in a platform-independent manner. + +// BINDLESS_RENDERING define controls whether bindless rendering is enabled. + +// Don't even try to use bindless rendering on platforms that don't support it (DirectX 11) +#if !PLATFORM_SUPPORTS_SUPPORTS_HEAP_VIEW +#define BINDLESS_RENDERING 0 +#endif + +#ifndef BINDLESS_RENDERING +#define BINDLESS_RENDERING 1 +#endif + +#if BINDLESS_RENDERING + +Texture2D HeapView_Texture2D[] +< + bool IsHeapView = true; +>; + +Texture3D HeapView_Texture3D[] +< + bool IsHeapView = true; +>; + +TextureCube HeapView_TextureCube[] +< + bool IsHeapView = true; +>; + +SamplerState HeapView_Sampler[] +< + bool IsHeapView = true; +>; + +#endif + +// Convenient shortcut to declaring bindless/class texture variables +#if BINDLESS_RENDERING +// CCP Shader compiler defines custom types BindlessHandleTexture... that map to uint on DX12 and Metal +#define BindlessTexture2D BindlessHandleTexture2D +#define BindlessTexture3D BindlessHandleTexture3D +#define BindlessTextureCube BindlessHandleTextureCube +#define BindlessSampler BindlessHandleSampler +#else +#define BindlessTexture2D Texture2D +#define BindlessTexture3D Texture3D +#define BindlessTextureCube TextureCube +#define BindlessSampler SamplerState +#endif + +Texture2D Deref2D( BindlessTexture2D tex ) +{ +#if BINDLESS_RENDERING + return HeapView_Texture2D[tex]; +#else + return tex; +#endif +} + +Texture3D Deref3D( BindlessTexture3D tex ) +{ +#if BINDLESS_RENDERING + return HeapView_Texture3D[tex]; +#else + return tex; +#endif +} + +TextureCube DerefCube( BindlessTextureCube tex ) +{ +#if BINDLESS_RENDERING + return HeapView_TextureCube[tex]; +#else + return tex; +#endif +} + +SamplerState DerefSampler( BindlessSampler sampl ) +{ +#if BINDLESS_RENDERING + return HeapView_Sampler[sampl]; +#else + return sampl; +#endif +} + + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/packedtangents.fxh b/shaders/include/carbon/packedtangents.fxh new file mode 100644 index 000000000..745b88ee8 --- /dev/null +++ b/shaders/include/carbon/packedtangents.fxh @@ -0,0 +1,81 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_PACKEDTANGENTS_FXH +#define CARBON_PACKEDTANGENTS_FXH + + +struct TangentSpace +{ + float3 tangent; + float3 bitangent; + float3 normal; +}; + +// Support for fma insrinsic varies for dx11 +float _Fma( float a, float b, float c ) +{ + return a * b + c; +} + +// Unpacks a tangent space using quaternion representation corresponding to +// cmf::Usage::PackedTangent in carbon-mesh. +TangentSpace UnpackTangentSpace( float4 t ) +{ + // Heavily optimized shader code that constructs the TBN matrix. + + // Extract the xyz components and square them + float x = t.x; + float y = t.y; + float z = t.z; + float x2 = x * x; + float y2 = y * y; + float z2 = z * z; + + // Optimized fma() chain to reconstruct W = sqrt(1 - x2 - y2 - z2) + // Don't use the above x2, y2 and z2 values, to reduce pipeline dependencies. + float w2 = saturate( _Fma( z, -z, _Fma( y, -y, _Fma( x, -x, 1.0f ) ) ) ); + float w = sqrt( w2 ); + + // Calculate shared values. + // These multiplications by 2.0f are free on some GPUs. + float xy = x * y * 2.0f; + float xz = x * z * 2.0f; + float yz = y * z * 2.0f; + float xw = x * w * 2.0f; + float yw = y * w * 2.0f; + float zw = z * w * 2.0f; + + // Compute the three vectors. + TangentSpace space; + + space.tangent = float3( _Fma( -2.0f, y2, _Fma( -2.0f, z2, 1.0f ) ), + xy + zw, + xz - yw ); + space.bitangent = float3( - zw + xy, _Fma( -2.0f, x2, _Fma( -2.0f, z2, 1.0f ) ), + yz + xw ); + space.normal = float3( + yw + xz, + yz - xw, _Fma( -2.0f, x2, _Fma( -2.0f, y2, 1.0f ) ) ) * t.w; // packed normal sign multiplication + + return space; +} + + +// Unpacks a tangent space using angle representation corresponding to +// cmf::Usage::PackedTangentLegacy in carbon-mesh. +TangentSpace UnpackTangentSpaceLegacy( float4 tangents ) +{ + float pi = 3.1415926535897932384626433832795; + + float4 angles = tangents * 2.0 * pi - pi; + float4 sc0, sc1; + sincos( angles.x, sc0.x, sc0.y ); + sincos( angles.y, sc0.z, sc0.w ); + sincos( angles.z, sc1.x, sc1.y ); + sincos( angles.w, sc1.z, sc1.w ); + TangentSpace space; + space.tangent = float3( sc0.y * abs( sc0.z ), sc0.x * abs( sc0.z ), sc0.w ); + space.bitangent = float3( sc1.y * abs( sc1.z ), sc1.x * abs( sc1.z ), sc1.w ); + space.normal = -cross( space.tangent, space.bitangent ); + space.normal = all( angles.yw > 0.0 ) ? -space.normal : space.normal; + return space; +} + + + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/particleannotations.fxh b/shaders/include/carbon/particleannotations.fxh new file mode 100644 index 000000000..679ec6242 --- /dev/null +++ b/shaders/include/carbon/particleannotations.fxh @@ -0,0 +1,37 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_PARTICLEANNOTATIONS_FXH +#define CARBON_PARTICLEANNOTATIONS_FXH + +// This file contains definitions for particle system shader annotations. +// These annotations are used to provide metadata and hints to the editor. +// These annotations should be specified for the particle system vertex shader, and +// they describe the particle attributes used by the shader. +// For example: +// ParticleVtx ParticleVS( ParticleAppVtx inVtx ) +// < +// DESC_PARTICLE_POSITION; +// DESC_PARTICLE_LIFETIME; +// DESC_PARTICLE_CUSTOM( 0, "size", 2 ); +// > +// { +// ... +// } + +#define DESC_PARTICLE_CONCAT( x, y ) x##y + +#define DESC_PARTICLE_ELEMENT( usage, index, name, dimension ) \ + string DESC_PARTICLE_CONCAT( ParticleElement_Name_, __LINE__ ) = name; \ + int DESC_PARTICLE_CONCAT( ParticleElement_Dimension_, __LINE__ ) = dimension; \ + int DESC_PARTICLE_CONCAT( ParticleElement_Usage_, __LINE__ ) = usage; \ + int DESC_PARTICLE_CONCAT( ParticleElement_Index_, __LINE__ ) = index + +#define DESC_PARTICLE_POSITION DESC_PARTICLE_ELEMENT( 1, 0, "POSITION", 3 ) +#define DESC_PARTICLE_VELOCITY DESC_PARTICLE_ELEMENT( 2, 0, "VELOCITY", 3 ) +#define DESC_PARTICLE_LIFETIME DESC_PARTICLE_ELEMENT( 0, 0, "LIFETIME", 2 ) +#define DESC_PARTICLE_MASS DESC_PARTICLE_ELEMENT( 3, 0, "MASS", 1 ) + +#define DESC_PARTICLE_CUSTOM( index, name, dimension ) DESC_PARTICLE_ELEMENT( 4, index, name, dimension ) + + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/system.fxh b/shaders/include/carbon/system.fxh new file mode 100644 index 000000000..75b1f4eda --- /dev/null +++ b/shaders/include/carbon/system.fxh @@ -0,0 +1,81 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_SYSTEM_FXH +#define CARBON_SYSTEM_FXH + +// This file contains definitions for backend API, including capability flags, and shader quality setting defines. + +// Trinity graphics API backend +#define PLATFORM_DX11 2 +#define PLATFORM_DX12 6 +#define PLATFORM_METAL 10 + +#ifndef PLATFORM +#error Missing value for PLATFORM macro +#endif + +// API supports compute shaders +#define PLATFORM_SUPPORTS_COMPUTE 1 + +// API supports geometry shaders +#if PLATFORM==PLATFORM_DX11 || PLATFORM==PLATFORM_DX12 +#define PLATFORM_SUPPORTS_GEOMETRY_SHADERS 1 +#else +#define PLATFORM_SUPPORTS_GEOMETRY_SHADERS 0 +#endif + +// API supports reading MSAA textures +#define PLATFORM_SUPPORTS_MSAA_READS 1 +// API supports GetDimensions method for textures +#define PLATFORM_SUPPORTS_TEXTURE_SIZE_QUERIES 1 +// API supports .Load methods for textures +#define PLATFORM_SUPPORTS_TEXTURE_LOAD 1 + +// API supports SRV/UAV/Sampler heap views +#if PLATFORM==PLATFORM_METAL || PLATFORM==PLATFORM_DX12 +#define PLATFORM_SUPPORTS_SUPPORTS_HEAP_VIEW 1 +#else +#define PLATFORM_SUPPORTS_SUPPORTS_HEAP_VIEW 0 +#endif + +// Maximum size of constant buffer in bytes +#if PLATFORM==PLATFORM_DX11 || PLATFORM==PLATFORM_DX12 +#define PLATFORM_MAX_CONSTANT_BUFFER_SIZE 65536 +#else +#define PLATFORM_MAX_CONSTANT_BUFFER_SIZE 4096 +#endif + +// API supports ray tracing +#if PLATFORM==PLATFORM_DX12 || PLATFORM==PLATFORM_METAL +#define PLATFORM_SUPPORTS_RAY_TRACING 1 +#else +#define PLATFORM_SUPPORTS_RAY_TRACING 0 +#endif + +// Support for "precise" keyword is for DirectX only +#if PLATFORM==PLATFORM_DX11 || PLATFORM==PLATFORM_DX12 +#define DX11_PRECISE precise +#else +#define DX11_PRECISE +#endif + + +// Shader quality setting. Comes from project user settings via Trinity +#define SHADER_QUALITY_LOW 3 +#define SHADER_QUALITY_MEDIUM 4 +#define SHADER_QUALITY_HIGH 5 + +// Legacy quality defines +#define SM_3_0_LO SHADER_QUALITY_LOW +#define SM_3_0_HI SHADER_QUALITY_MEDIUM +#define SM_3_0_DEPTH SHADER_QUALITY_HIGH + +#ifndef SHADERMODEL +#define SHADERMODEL SHADER_QUALITY_HIGH +#endif + +#ifndef SHADER_QUALITY +#define SHADER_QUALITY SHADERMODEL +#endif + +#endif \ No newline at end of file From 627f6dbfd7a14ba2f29f0cf4d09e24bd6c367926 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Wed, 23 Sep 2026 11:51:01 +0000 Subject: [PATCH 43/83] Capitalize filenames --- shaders/include/carbon/{bindless.fxh => Bindless.fxh} | 0 shaders/include/carbon/{packedtangents.fxh => PackedTangents.fxh} | 0 .../carbon/{particleannotations.fxh => ParticleAnnotations.fxh} | 0 shaders/include/carbon/{system.fxh => System.fxh} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename shaders/include/carbon/{bindless.fxh => Bindless.fxh} (100%) rename shaders/include/carbon/{packedtangents.fxh => PackedTangents.fxh} (100%) rename shaders/include/carbon/{particleannotations.fxh => ParticleAnnotations.fxh} (100%) rename shaders/include/carbon/{system.fxh => System.fxh} (100%) diff --git a/shaders/include/carbon/bindless.fxh b/shaders/include/carbon/Bindless.fxh similarity index 100% rename from shaders/include/carbon/bindless.fxh rename to shaders/include/carbon/Bindless.fxh diff --git a/shaders/include/carbon/packedtangents.fxh b/shaders/include/carbon/PackedTangents.fxh similarity index 100% rename from shaders/include/carbon/packedtangents.fxh rename to shaders/include/carbon/PackedTangents.fxh diff --git a/shaders/include/carbon/particleannotations.fxh b/shaders/include/carbon/ParticleAnnotations.fxh similarity index 100% rename from shaders/include/carbon/particleannotations.fxh rename to shaders/include/carbon/ParticleAnnotations.fxh diff --git a/shaders/include/carbon/system.fxh b/shaders/include/carbon/System.fxh similarity index 100% rename from shaders/include/carbon/system.fxh rename to shaders/include/carbon/System.fxh From 141b46ae251cbd5c4702617dedb433ca600fd05d Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 24 Sep 2026 10:23:43 +0000 Subject: [PATCH 44/83] Populating shaders; dummy cmake project for shaders --- CMakeLists.txt | 18 + shaders/include/carbon/Bindless.fxh | 2 +- shaders/include/carbon/Intersections.fxh | 421 ++++++++++++++++++ shaders/include/carbon/Math.fxh | 331 ++++++++++++++ .../carbon/SpaceScene/EnvironmentMap.fxh | 73 +++ .../carbon/SpaceScene/PerSceneData.fxh | 86 ++++ .../include/carbon/SpaceScene/Volumetrics.fxh | 223 ++++++++++ shaders/include/carbon/System.fxh | 10 + 8 files changed, 1163 insertions(+), 1 deletion(-) create mode 100644 shaders/include/carbon/Intersections.fxh create mode 100644 shaders/include/carbon/Math.fxh create mode 100644 shaders/include/carbon/SpaceScene/EnvironmentMap.fxh create mode 100644 shaders/include/carbon/SpaceScene/PerSceneData.fxh create mode 100644 shaders/include/carbon/SpaceScene/Volumetrics.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f77d9142..6599d02d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,4 +140,22 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() endif() +set(_SHADER_SOURCES + shaders/include/carbon/SpaceScene/EnvironmentMap.fxh + shaders/include/carbon/SpaceScene/PerSceneData.fxh + shaders/include/carbon/SpaceScene/Volumetrics.fxh + shaders/include/carbon/Bindless.fxh + shaders/include/carbon/Intersections.fxh + shaders/include/carbon/Math.fxh + shaders/include/carbon/PackedTangents.fxh + shaders/include/carbon/ParticleAnnotations.fxh + shaders/include/carbon/System.fxh + ) + +add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) +source_group( + TREE "${CMAKE_CURRENT_SOURCE_DIR}/shaders" + FILES ${_SHADER_SOURCES} +) + install(DIRECTORY shaders/ DESTINATION shaders) diff --git a/shaders/include/carbon/Bindless.fxh b/shaders/include/carbon/Bindless.fxh index 7f4b20c41..04be0b958 100644 --- a/shaders/include/carbon/Bindless.fxh +++ b/shaders/include/carbon/Bindless.fxh @@ -3,7 +3,7 @@ #ifndef CARBON_BINDLESS_FXH #define CARBON_BINDLESS_FXH -#include "system.fxh" +#include "System.fxh" // Support for bindless rendering with Trinity. Difines types and functions to work with // bindless resources and heap views in a platform-independent manner. diff --git a/shaders/include/carbon/Intersections.fxh b/shaders/include/carbon/Intersections.fxh new file mode 100644 index 000000000..8b7c049dd --- /dev/null +++ b/shaders/include/carbon/Intersections.fxh @@ -0,0 +1,421 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_INTERSECTIONS_FXH +#define CARBON_INTERSECTIONS_FXH + + + +struct Ray +{ + float3 origin; + float3 dir; +}; + +Ray InitRay(float3 o, float3 d) +{ + Ray r; + r.origin = o; + r.dir = d; + return r; +} + + +struct Plane +{ + float3 normal; + float3 planePoint; +}; + +Plane InitPlane(float3 normal, float3 planePoint) +{ + Plane p; + p.normal = normal; + p.planePoint = planePoint; + return p; +} + +float GetDistanceToPlane( Plane plane, Ray ray ) +{ + float denom = dot( ray.dir, plane.normal ); + float denom2 = dot( ray.dir, -plane.normal ); + float d = max( denom, denom2 ); + if( d == denom2 ) + { + plane.normal = -plane.normal; + } + + const float FLT_EPSILON = 0.0000001; + if( d >= FLT_EPSILON ) + { + float3 rayToPlanePoint = plane.planePoint - ray.origin; + + return dot( rayToPlanePoint, plane.normal ) / d; + } + return -1; +} + +bool PointOnPlane( Ray ray, float t, float3 planePoint, float radius ) +{ + if( t < 0 ) + { + return false; + } + float3 pointInPlaneSpace = ray.origin + t * ray.dir; + float3 dist = planePoint - pointInPlaneSpace; + float r = radius; + + return dot( dist, dist ) - r * r <= 0; +} + +float GetDistanceToCircle(float3 normal, float3 planePoint, float radius, Ray ray) +{ + float t = GetDistanceToPlane( InitPlane( normal, planePoint ), ray); + if( PointOnPlane( ray, t, planePoint, radius ) ) + { + return t; + } + return -1; +} + +// ------------------------------------------------------------------------------- +// Sphere +// ------------------------------------------------------------------------------- +struct Sphere +{ + float3 center; + float radius; +}; + +Sphere InitSphere( float3 center, float radius ) +{ + Sphere s; + s.center = center; + s.radius = radius; + return s; +} + +struct SphereHitInfo +{ + bool occurred; + float4 firstIntersection; // xyz - position, w - distance from eye + float4 secondIntersection; // xyz - position, w - distance from eye +}; + +SphereHitInfo SphereRayHitTest( Sphere sphere, Ray ray ) +{ + SphereHitInfo info; + info.occurred = false; + info.firstIntersection = float4(0, 0, 0, 0); + info.secondIntersection = float4(0, 0, 0, 0); + + // algorithm taken from Real Time Rendering fourth edition, page 958 + float3 originToSphereCenter = sphere.center - ray.origin; + float s = dot( originToSphereCenter, ray.dir ); + float originToSphereCenterLengthSq = dot(originToSphereCenter, originToSphereCenter); + float radSq = sphere.radius * sphere.radius; + + if( s < 0 && originToSphereCenterLengthSq > radSq ) + { + return info; + } + + float mSq = originToSphereCenterLengthSq - s*s; + if( mSq > radSq ) + { + return info; + } + + float intersectionPerpendicularToCenter = sqrt( radSq - mSq ); + float minT = max( 0.0, min( s - intersectionPerpendicularToCenter, s + intersectionPerpendicularToCenter ) ); + float maxT = max( s - intersectionPerpendicularToCenter, s + intersectionPerpendicularToCenter ); + + info.firstIntersection = float4( ray.origin + ray.dir * minT - sphere.center, minT ); + info.secondIntersection = float4( ray.origin + ray.dir * maxT - sphere.center, maxT ); + info.occurred = true; + + return info; +} + + +// ------------------------------------------------------------------------------- +// Cones +// ------------------------------------------------------------------------------- +struct Cone +{ + float height; + float3 tip; + float cosa; // half cone angle + // float tipRadius; + float3 axis; + float baseRadius; + float tipOffset; +}; + +struct ConeHitInfo +{ + float4 firstIntersection; // xyz - position, w - distance from eye + float4 secondIntersection; // xyz - position, w - distance from eye + float4 hits; // frontCone, backCone, base, tip + float shadowConeHit; + bool occurred; + float4 tmp; +}; + +bool PointInCone( Ray ray, float t, Cone cone ) +{ + if( t < 0 ) + { + return false; + } + + float3 pointInConeSpace = ray.origin + t * ray.dir - cone.tip; + + float cone_dist = dot( pointInConeSpace, cone.axis ); + const float FLT_EPSILON = 0.0000001; + + if( cone.tipOffset - cone_dist > 0 || cone_dist > cone.height + FLT_EPSILON ) + { + return false; + } + + float cone_radius_at_dist = ( cone_dist / cone.height ) * cone.baseRadius; + float3 orth_point = pointInConeSpace - cone_dist * cone.axis; + float orth_distance_sq = dot(orth_point, orth_point); + return cone.baseRadius * cone.baseRadius - orth_distance_sq >= 0; +} + +bool GetConeIntersectionDistances(Cone cone, Ray ray, out float t1, out float t2, out float baseT, out float tipT ) +{ + t1 = -1; + t2 = -1; + baseT = -1; + tipT = -1; + + baseT = GetDistanceToCircle(cone.axis, cone.tip + cone.axis * cone.height, cone.baseRadius, ray); + + float tipOffsetRadius = cone.tipOffset / cone.cosa; + tipOffsetRadius = sqrt(tipOffsetRadius * tipOffsetRadius - cone.tipOffset * cone.tipOffset); + tipT = GetDistanceToCircle(cone.axis, cone.tip + cone.axis * cone.tipOffset, tipOffsetRadius, ray); + + // code comes from here http://lousodrome.net/blog/light/2017/01/03/intersection-of-a-ray-and-a-cone/ + float3 co = ray.origin - cone.tip; + + float dirAxisDot = dot(ray.dir, cone.axis); + float coAxisDot = dot(co, cone.axis); + + float a = dirAxisDot * dirAxisDot - cone.cosa * cone.cosa; + float b = 2. * (dirAxisDot * coAxisDot - dot(ray.dir, co) * cone.cosa * cone.cosa); + float c = coAxisDot * coAxisDot - dot(co, co) * cone.cosa * cone.cosa; + + float det = b * b - 4. * a * c; + + if( det < 0 ) + { + if( baseT < 0 && tipT < 0 ) + { + return false; + } + return true; + } + + det = sqrt(abs(det)); + + // if t1 is < 0 then we are will never hit the cone i.e the ray will never intersect + t1 = ( -b - det ) / ( 2. * a ); + // if t2 is < 0 then we are looking down the axis of the cone (in either way) + t2 = ( -b + det ) / ( 2. * a ); + + return true; +} + +// Sorts a vector4 in ascending order (x, y, z, w) +float4 sort(float4 values) +{ + float minv, maxv; + + // move the maximum value to w + minv = min(values.x, values.y); + maxv = max(values.x, values.y); + values.x = minv; + values.y = maxv; + + minv = min(values.y, values.z); + maxv = max(values.y, values.z); + values.y = minv; + values.z = maxv; + + minv = min(values.z, values.w); + maxv = max(values.z, values.w); + values.z = minv; + values.w = maxv; + // now w has the highest value + + // now we can sort xyz easily + minv = min(values.x, min(values.y, values.z)); + maxv = max(values.x, max(values.y, values.z)); + float midv = values.x + values.y + values.z - minv - maxv; + values.x = minv; + values.y = midv; + values.z = maxv; + + // now values are sorted + return values; +} + +ConeHitInfo ConeFlatBaseHitTest( Cone cone, Ray ray ) +{ + ConeHitInfo hitInfo; + hitInfo.occurred = false; + hitInfo.firstIntersection = float4(0, 0, 0, 0); + hitInfo.secondIntersection = float4(0, 0, 0, 0); + hitInfo.hits = float4(0, 0, 0, 0); + hitInfo.tmp = float4(0, 0, 0, 0); + hitInfo.shadowConeHit = 0; + + float coneT1, coneT2, baseT, tipT = -1; + if( !GetConeIntersectionDistances(cone, ray, coneT1, coneT2, baseT, tipT) ) + { + return hitInfo; + } + + bool frontConeHit = PointInCone( ray, coneT2, cone ); + bool backConeHit = PointInCone( ray, coneT1, cone ); + bool rayOriginConeHit = PointInCone( ray, 0, cone ); + bool baseConeHit = baseT > -1; + bool tipConeHit = tipT > -1; + + hitInfo.hits = float4(frontConeHit, backConeHit, baseConeHit, tipConeHit); + hitInfo.shadowConeHit = 1; + + if( !any( hitInfo.hits.xyzw ) ) + { + return hitInfo; + } + + // for the "distances" that don't create a hit, put in invalid values + float4 modifiedT = float4(frontConeHit ? coneT2 : -1, + backConeHit ? coneT1 : -1, + tipConeHit ? tipT : -1, + baseConeHit ? baseT : -1); + + float4 sortedModifiedT = sort(modifiedT); + float2 tToUse; + + if( rayOriginConeHit ) + { + tToUse.x = 0; + tToUse.y = sortedModifiedT.w; + } + else + { + tToUse.x = sortedModifiedT.z >= 0 ? sortedModifiedT.z: sortedModifiedT.w; + tToUse.y = sortedModifiedT.w; + } + + hitInfo.occurred = true; + hitInfo.firstIntersection = float4(ray.origin + ray.dir * tToUse.x - cone.tip, tToUse.x); + hitInfo.secondIntersection = float4(ray.origin + ray.dir * tToUse.y - cone.tip, tToUse.y); + + return hitInfo; +} + +ConeHitInfo ConeRoundBaseHitTest( Cone cone, Ray ray ) +{ + ConeHitInfo hitInfo; + hitInfo.occurred = false; + hitInfo.firstIntersection = float4(0, 0, 0, 0); + hitInfo.secondIntersection = float4(0, 0, 0, 0); + hitInfo.hits = float4(0, 0, 0, 0); + hitInfo.shadowConeHit = false; + hitInfo.tmp = false; + + float coneT1, coneT2, tmp, tipT = -1; + // are we intersecting the cone (endless and in both directions...) + if( !GetConeIntersectionDistances(cone, ray, coneT1, coneT2, tmp, tipT ) ) + { + return hitInfo; + } + + hitInfo.shadowConeHit = true; + + // first do the sphereintersection since that is cheaper + Sphere s; + s.radius = cone.height; + s.center = cone.tip; + + SphereHitInfo si = SphereRayHitTest(s, ray); + + // Early exit, if no spherical intersection occurred + // either of the intersection points are not within the cone radius + if( !si.occurred ) + { + return hitInfo; + } + + float firstIntersectionDot = dot(normalize(si.firstIntersection.xyz), cone.axis); + float secondIntersectionDot = dot(normalize(si.secondIntersection.xyz), cone.axis); + + bool firstBaseHit = firstIntersectionDot - cone.cosa >= 0; + bool secondBaseHit = secondIntersectionDot - cone.cosa >= 0; + + float baseT1 = si.firstIntersection.w; + float baseT2 = si.secondIntersection.w; + + // modify the cone so it fits nicely to the sphere + cone.height *= cone.cosa; + bool frontConeHit = PointInCone( ray, coneT1, cone ); + bool backConeHit = PointInCone( ray, coneT2, cone ); + bool rayOriginConeHit = PointInCone( ray, 0, cone ); + + float tipOffsetRadius = cone.tipOffset / cone.cosa; + tipOffsetRadius = sqrt(tipOffsetRadius * tipOffsetRadius - cone.tipOffset - cone.tipOffset); + bool tipConeHit = PointOnPlane( ray, tipT, cone.tip + cone.axis * cone.tipOffset, tipOffsetRadius); + + float4 coneIntersections = float4(frontConeHit, backConeHit, rayOriginConeHit, tipConeHit); + float2 sphereIntersections = float2(firstBaseHit, secondBaseHit); + hitInfo.hits = float4(frontConeHit, backConeHit, (any(coneIntersections) && any(sphereIntersections)) || all(sphereIntersections), tipConeHit ); + + // if we don't hit the cone or have any cone and sphere intersections or don't hit the sphere, we can return + if( !any(hitInfo.hits.xyzw) ) + { + return hitInfo; + } + + float2 tToUse; + // figure out the t-s to use + // we have 6 ts to pick from: + // - front and back cone intersection + // - front and back sphere + // - tip + // - 0 (the camera) + + // there are 2 scenarios though + // if the camera is intersecting with the cone, then we need the next t (or min(coneT1, coneT2, sphereT1, sphereT2)) + // otherwise we need the middle values of (coneT1, coneT2, sphereT1, sphereT2) + float4 ts = sort(float4( + hitInfo.hits.x ? coneT1 : -1, + hitInfo.hits.y ? coneT2 : -1, + (any(coneIntersections) && sphereIntersections.x) || all(sphereIntersections)? baseT1 : -1, + (any(coneIntersections) && sphereIntersections.y) || all(sphereIntersections)? baseT2 : -1 + ) + ); + + if( rayOriginConeHit ) + { + tToUse.x = 0; + tToUse.y = max(tipT, ts.w); + } + else + { + tToUse.x = ts.z >= 0 ? ts.z: ts.w; + tToUse.y = ts.w; + } + + hitInfo.occurred = true; + hitInfo.firstIntersection = float4(ray.origin + ray.dir * tToUse.x - cone.tip, tToUse.x); + hitInfo.secondIntersection = float4(ray.origin + ray.dir * tToUse.y - cone.tip, tToUse.y); + + return hitInfo; +} + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/Math.fxh b/shaders/include/carbon/Math.fxh new file mode 100644 index 000000000..b90ce7cf4 --- /dev/null +++ b/shaders/include/carbon/Math.fxh @@ -0,0 +1,331 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_MATH_FXH +#define CARBON_MATH_FXH + +static float PI = 3.1415926535897932384626433832795; +static float _2PI = 6.283185307179586476925286766559; +static const float4x4 IDENTITY_MATRIX = float4x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + +// ---------------------------------------------------------------------------------------------- +// extract the eye-pos in world-space from the view matrix +// ---------------------------------------------------------------------------------------------- +float3 ExtractEyePosFromViewMatrix(float4x4 mat) +{ + return float3(mat[0].w, mat[1].w, mat[2].w); +} + +// ---------------------------------------------------------------------------------------------- +// extract the eye-dir in world-space from the view matrix +// ---------------------------------------------------------------------------------------------- +float3 ExtractEyeDirFromViewMatrix(float4x4 mat) +{ + return float3(mat[0].z, mat[1].z, mat[2].z); +} + +// ---------------------------------------------------------------------------------------------- +// extract z_near from projection matrix +// ---------------------------------------------------------------------------------------------- +float ExtractZnearFromProjectionMatrix(float4x4 mat) +{ + return mat[3][2] / mat[2][2]; +} + +// ---------------------------------------------------------------------------------------------- +// extract z_far from projection matrix +// ---------------------------------------------------------------------------------------------- +float ExtractZfarFromProjectionMatrix(float4x4 mat) +{ + return mat[3][2] / (mat[2][2] + 1.0); +} + +// ---------------------------------------------------------------------------------------------- +// extract FovY from projection matrix +// ---------------------------------------------------------------------------------------------- +float ExtractFovYFromProjectionMatrix(float4x4 mat) +{ + return 2.0 * atan(1.0 / mat[1][1]); +} + +// ---------------------------------------------------------------------------------------------- +// compute a simple rotation matrix from a given vector and angle +// ---------------------------------------------------------------------------------------------- +float3x3 GetRotationMatrixAxisAngle(float3 axis, float angle) +{ + float3x3 m; + + // pre + float oneMinusCosA = 1.0 - cos(angle); + float sinA = sin(angle); + + // matrix + m[0][0] = 1.0 + oneMinusCosA * (axis.x * axis.x - 1.0); + m[1][0] = -axis.z * sinA + oneMinusCosA * axis.x * axis.y; + m[2][0] = axis.y * sinA + oneMinusCosA * axis.x * axis.z; + + m[0][1] = axis.z * sinA + oneMinusCosA * axis.x * axis.y; + m[1][1] = 1.0 + oneMinusCosA * (axis.y * axis.y - 1.0); + m[2][1] = -axis.x * sinA + oneMinusCosA * axis.y * axis.z; + + m[0][2] = -axis.y * sinA + oneMinusCosA * axis.x * axis.z; + m[1][2] = axis.x * sinA + oneMinusCosA * axis.y * axis.z; + m[2][2] = 1.0 + oneMinusCosA * (axis.z * axis.z - 1.0); + + return m; +} + +// ---------------------------------------------------------------------------------------------- +// compute a rotation matrix which rotates axis1 into axis2 +// ---------------------------------------------------------------------------------------------- +float3x3 GetRotationMatrixNrmToNrm(float3 normal1, float3 normal2) +{ + float3 rotAxis = normalize(cross(normal1, normal2)); + float rotAngle = acos(dot(normal1, normal2)); + return GetRotationMatrixAxisAngle(rotAxis, rotAngle); +} + +// ---------------------------------------------------------------------------------------------- +// Create a transformation matrix from a quaternion of the form x, y, z, w +// ---------------------------------------------------------------------------------------------- +float4x4 CreateRotationMatrixFromQuaterion(float4 q) +{ + float tx2 = 2 * q.x * q.x; + float ty2 = 2 * q.y * q.y; + float tz2 = 2 * q.z * q.z; + + float txy = 2 * q.x * q.y; + float txz = 2 * q.x * q.z; + float txw = 2 * q.x * q.w; + float tyz = 2 * q.y * q.z; + float tyw = 2 * q.y * q.w; + float tzw = 2 * q.z * q.w; + + float4x4 m3 = + { + { 1 - ty2 - tz2, txy + tzw, txz - tyw, 0 }, + { txy - tzw, 1 - tx2 - tz2, tyz + txw, 0 }, + { txz + tyw, tyz - txw, 1 - tx2 - ty2, 0 }, + { 0, 0, 0, 1 } + }; + return m3; +} + +// ---------------------------------------------------------------------------------------------- +// combine a 3x3 rotation matrix and a float3 position to a 4x4 transform +// ---------------------------------------------------------------------------------------------- +float4x4 CreateTransformMatrix(float3x3 rotationMatrix, float3 translation) +{ + float4x4 m; + + m[0] = float4(rotationMatrix[0], 0.0); + m[1] = float4(rotationMatrix[1], 0.0); + m[2] = float4(rotationMatrix[2], 0.0); + m[3] = float4(translation, 1.0); + + return m; +} + +// ---------------------------------------------------------------------------------------------- +// combine a rotation quaternion and a float4 position to a 4x4 transform +// ---------------------------------------------------------------------------------------------- +float4x4 CreateTransformMatrix(float4 rotationQuaternion, float4 translation) +{ + float4x4 m = CreateRotationMatrixFromQuaterion(rotationQuaternion); + m[3] = translation; + + return m; +} + +// ---------------------------------------------------------------------------------------------- +// extract translation from transform matrix +// ---------------------------------------------------------------------------------------------- +float3 ExtractTranslationFromTransformMatrix(float4x4 mat) +{ + return mat[3].xyz; +} + +// ---------------------------------------------------------------------------------------------- +// extract rotation from transform matrix +// ---------------------------------------------------------------------------------------------- +float3x3 ExtractRotationFromTransformMatrix(float4x4 mat) +{ + float3x3 m; + + m[0] = mat[0].xyz; + m[1] = mat[1].xyz; + m[2] = mat[2].xyz; + return m; +} + +// ---------------------------------------------------------------------------------------------- +// remove translation from a transform matrix +// ---------------------------------------------------------------------------------------------- +float4x4 RemoveTranslationFromMatrix(float4x4 transformMatrix) +{ + float4x4 m = transformMatrix; + m[3] = float4(0.0, 0.0, 0.0, 1.0); + + return m; +} + +// ---------------------------------------------------------------------------------------------- +// create an identity matrix +// ---------------------------------------------------------------------------------------------- +float4x4 CreateIdentityMatrix() +{ + float4x4 m; + + m[0] = float4(1.0, 0.0, 0.0, 0.0); + m[1] = float4(0.0, 1.0, 0.0, 0.0); + m[2] = float4(0.0, 0.0, 1.0, 0.0); + m[3] = float4(0.0, 0.0, 0.0, 1.0); + + return m; +} + +// ---------------------------------------------------------------------------------------------- +// create a non-uniform scaling matrix +// ---------------------------------------------------------------------------------------------- +float4x4 CreateScalingMatrix(float3 s) +{ + float4x4 m; + + m[0] = float4(s.x, 0.0, 0.0, 0.0); + m[1] = float4(0.0, s.y, 0.0, 0.0); + m[2] = float4(0.0, 0.0, s.z, 0.0); + m[3] = float4(0.0, 0.0, 0.0, 1.0); + + return m; +} + +// ---------------------------------------------------------------------------------------------- +// compute a perpendicular vector to a given base vector: is any vector, only perpendicular +// ---------------------------------------------------------------------------------------------- +float3 GetVectorPerpendicular(float3 basis) +{ + // somehow this simple problem of constructing ANY perpendicular to a given vector + // is unsolvable.... at least in a nice, non-hacky way + float3 v = basis.yzx; + return normalize(cross(v, basis)); +} + +// ---------------------------------------------------------------------------------------------- +// "re-linearize" v from min to max +// ---------------------------------------------------------------------------------------------- +float LinStep(float min, float max, float v) +{ + return clamp((v - min) / (max - min), 0.0, 1.0); +} + +// ---------------------------------------------------------------------------------------------- +// remap a value from input range to an output range +// ---------------------------------------------------------------------------------------------- +float RemapFloatRange(float x, float inMin, float inMax, float outMin = 0.0f, float outMax = 1.0f) +{ + return outMin + ((x - inMin) / (inMax - inMin)) * (outMax - outMin); +} + +// ---------------------------------------------------------------------------------------------- +// Hermite spline position +// ---------------------------------------------------------------------------------------------- +float3 HermiteSplinePos(float3 v1, float3 t1, float3 v2, float3 t2, float s) +{ + // spline parameters + float3 a = 2.0 * v1 - 2.0 * v2 + t2 + t1; + float3 b = 3.0 * v2 - 3.0 * v1 - 2.0 * t1 - t2; + float3 c = t1; + float3 d = v1; + // cubic equation + return a * s * s * s + b * s * s + c * s + d; +} + +// ---------------------------------------------------------------------------------------------- +// Hermite spline direction (derive!) +// ---------------------------------------------------------------------------------------------- +float3 HermiteSplineDir(float3 v1, float3 t1, float3 v2, float3 t2, float s) +{ + // spline parameters + float3 a = 2.0 * v1 - 2.0 * v2 + t2 + t1; + float3 b = 3.0 * v2 - 3.0 * v1 - 2.0 * t1 - t2; + float3 c = t1; + // cubic equation becomes 2-dim cause of derive + return 3.0 * a * s * s + 2.0 * b * s + c; +} + +// ---------------------------------------------------------------------------------------------- +// Convert cartesian direction vector to spherical +// ---------------------------------------------------------------------------------------------- +float2 CartesianToSpherical(float3 dir) +{ + // x = sin( theta ) * sin( phi ) + // y = cos( phi ) + // z = cos( theta ) * sin( phi ) + float phi = acos(dir.y); + float theta = PI + atan2(dir.z, dir.x); + return float2(theta, phi); +} + +// ---------------------------------------------------------------------------------------------- +// Convert spherical coords into cartesian vector +// ---------------------------------------------------------------------------------------------- +float3 SphericalToCartesian(float2 spherical) +{ + float z = -sin(spherical.x) * sin(spherical.y); + float y = cos(spherical.y); + float x = -cos(spherical.x) * sin(spherical.y); + return float3(x, y, z); +} + + +float4 Vec4Cross(float4 v1, float4 v2, float4 v3) +{ + float4 result; + result.x = v1.y * (v2.z * v3.w - v3.z * v2.w) - v1.z * (v2.y * v3.w - v3.y * v2.w) + v1.w * (v2.y * v3.z - v2.z * v3.y); + result.y = -(v1.x * (v2.z * v3.w - v3.z * v2.w) - v1.z * (v2.x * v3.w - v3.x * v2.w) + v1.w * (v2.x * v3.z - v3.x * v2.z)); + result.z = v1.x * (v2.y * v3.w - v3.y * v2.w) - v1.y * (v2.x * v3.w - v3.x * v2.w) + v1.w * (v2.x * v3.y - v3.x * v2.y); + result.w = -(v1.x * (v2.y * v3.z - v3.y * v2.z) - v1.y * (v2.x * v3.z - v3.x * v2.z) + v1.z * (v2.x * v3.y - v3.x * v2.y)); + return result; +} + +float4x4 MatrixInverse(float4x4 m) +{ + float4 v, vec[3]; + float d; + + d = determinant(m); + if (!d) + { + return m; + } + float4x4 result; + [unroll] + for (int i = 0; i < 4; i++) + { + float signedDet = (i % 2 == 1) ? -1.f : 1.f; + signedDet /= d; + for (int j = 0; j < 4; j++) + { + if (j != i) + { + int a = j; + if (j > i) + { + a = a - 1; + } + vec[a].x = m[j][0]; + vec[a].y = m[j][1]; + vec[a].z = m[j][2]; + vec[a].w = m[j][3]; + } + } + v = Vec4Cross(vec[0], vec[1], vec[2]); + result[0][i] = signedDet * v.x; + result[1][i] = signedDet * v.y; + result[2][i] = signedDet * v.z; + result[3][i] = signedDet * v.w; + } + return result; +} + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh b/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh new file mode 100644 index 000000000..0a97167f8 --- /dev/null +++ b/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh @@ -0,0 +1,73 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_ENVIRONMENTMAP_FXH +#define CARBON_ENVIRONMENTMAP_FXH + +#include "../System.fxh" + + +// -------------------------------------------------------------------------------------------------- +// texture +// -------------------------------------------------------------------------------------------------- +// Environment map (refleciton) texture set by EveSpaceScene +TextureCube EveSpaceSceneEnvMap +< + bool AutoRegister = true; + bool Tr2sRGB = true; +>; +SamplerState EveSpaceSceneEnvMapSampler +{ + MinFilter = Anisotropic; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Wrap; + AddressV = Wrap; +}; + +// Helper function to convert PBR roughness to gloss value used for environment map lookup +float RoughnessToGloss( float roughness ) +{ + const float GGX_MAX_SPEC_POWER = 28; + const float EPSILON = 0.00052556; + float gloss = 1.0; + if( roughness >= EPSILON ) + { + gloss = roughness * roughness; + gloss *= gloss; + gloss = ( 2.0f / gloss ) - 1.0f; + gloss = log2( gloss ) / GGX_MAX_SPEC_POWER; + } + + return gloss; +} + +// Helper function to convert PBR roughness to mip level used for environment map lookup +float RoughnessToMip( TextureCube envMap, float roughness ) +{ + uint width; + uint height; + uint mipLevels; + envMap.GetDimensions( width, height, mipLevels ); + + return ( 1.0f - RoughnessToGloss( roughness ) ) * float( mipLevels - 1 ); +} + +// Helper function to convert PBR roughness to mip level used for environment map lookup for EveSpaceSceneEnvMap +float RoughnessToMip( float roughness ) +{ + return RoughnessToMip( EveSpaceSceneEnvMap, roughness ); +} + +// Sample an environment map with given direction and surface roughness +float3 SampleEnvironmentMap( TextureCube envMap, float3 dir, float roughness ) +{ + return envMap.SampleLevel( EveSpaceSceneEnvMapSampler, dir, RoughnessToMip( envMap, roughness ) ).rgb; +} + +// Sample EveSpaceSceneEnvMap with given direction and surface roughness +float3 SampleEnvironmentMap( float3 dir, float roughness ) +{ + return SampleEnvironmentMap( EveSpaceSceneEnvMap, dir, roughness ); +} + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/SpaceScene/PerSceneData.fxh b/shaders/include/carbon/SpaceScene/PerSceneData.fxh new file mode 100644 index 000000000..ae3282747 --- /dev/null +++ b/shaders/include/carbon/SpaceScene/PerSceneData.fxh @@ -0,0 +1,86 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_SPACESCENE_PERSCENEDATA_FXH +#define CARBON_SPACESCENE_PERSCENEDATA_FXH + +#include "../System.fxh" + + +struct FroxelPerFrameData +{ + float3 FogColor; + float BackgroundVisibility; + + float BaseDensity; + float MaxDistance; + float MaxDistanceVisibility; + float EnvironmentIntensity; + + float EnvironmentG; + float _pad0; + float _pad1; + float _pad2; + + float4 Planets[2]; +}; + +// Per-scene (per-frame) constant buffer data for the vertex shader. +struct EveSpaceSceneDataVS +{ + // matrices + float4x4 ViewInverseTransposeMat; + float4x4 ViewProjectionMat; + float4x4 ViewMat; + float4x4 ProjectionMat; + float4x4 ShadowViewMat; + float4x4 ShadowViewProjectionMat; + float4x4 EnvMapRotationMat; + float4x4 ViewProjectionLast; + float4x4 ViewLast; + float4x4 ProjLast; + // lighting info + float4 SunDirection; + float4 SunDiffuseColor; + float3 FogFactors; // Depth multiplier in x, constant in y and max fog in z + // rendertarget resolution and fovXY (rt pixelsize in .xy, fovXY in .zw) + float4 TargetResolution; + float4 ViewportAdjustment; + float4 MiscParams; // x - time, y - upscaling amount, zw - viewport size +}; + + +// Per-scene (per-frame) constant buffer data for the pixel shader. +struct EveSpaceSceneDataPS +{ + // some pixel-shaders do need these... + float4x4 ViewInverseTransposeMat; + float4x4 ViewMat; + float4x4 EnvMapRotationMat; + + // scene info + float4 SunDirection; + float4 SunDiffuseColor; // .rgb - sun diffuse color, .a - environment map diffuse "roughness" + float4 AmbientColor; // .rgb - ambient color, .a - nebula intensity + float4 FogColor; + + // various info + float4 ViewportOffsetSize; // .xy - viewport offset, .zw - viewport size + float4 RenderTargetData; // .xy - RT size in pixel, z - MSAA sample count (legacy, always 1 nowadays), w - debug + float4 ShadowMapSettings; // .xyzw - various shadow filter parameters + float4 ShadowMapSettings2; // .xy - shadow camera range, .z - shadow lightness, .w - shadow quality + float4 ProjectionData; // x - projection[3][2], y - projection[2][2], .zw = FoV + float4 MiscData; // x - time, y - scenemiplodbias, z - upscaling amount, w - gamma brightness + uint4 MiscData2; // x - frame counter, y - Jittering (bool), z - InverseShadowMapAtlasSize (float), w - ShadowMapAtlasEntryMinSizeLog2 (uint) + float4 VolumetricSlices; + float4 ShadowMapValues[4]; // x = zFar value[0], y = zFar value[1], z = zFar value[2], w = zFar value[3]..etc + float4x4 ShadowMatrix[16]; // Matrix that takes a coordinate from view space all the way to the packed cascades + float4 SplitInfo; // x = NrOfSplits, y = , z = , w = + float4x4 ProjectionInverseMat; // + float4 CascadeRanges[16]; + + //Froxel fog related global variables + FroxelPerFrameData FroxelFogData; +}; + + +#endif // CARBON_SPACESCENE_PERSCENEDATA_FXH \ No newline at end of file diff --git a/shaders/include/carbon/SpaceScene/Volumetrics.fxh b/shaders/include/carbon/SpaceScene/Volumetrics.fxh new file mode 100644 index 000000000..2e4a7d476 --- /dev/null +++ b/shaders/include/carbon/SpaceScene/Volumetrics.fxh @@ -0,0 +1,223 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_SPACESCENE_VOLUMETRICS_FXH +#define CARBON_SPACESCENE_VOLUMETRICS_FXH + +#include "../System.fxh" +#include "../Intersections.fxh" +#include "PerSceneData.fxh" +#include "../Math.fxh" + +// Depth slices for the rendered cloud volume (see EveChildCloud2) +Texture2DArray EveSceneFogVolumeMap ; + +// 3D froxel fog map and Mie environment map for volumetric effects +Texture3D EveSceneFroxelFogMap ; +TextureCube EveSceneMieEnvironmentMap ; + + +SamplerState EveSceneFogSampler = sampler_state +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; +}; + +SamplerState EveSceneFogVolumeMapSampler = sampler_state +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; +}; + + +float4 _CubicWeights( float x ) +{ + float x2 = x * x; + float x3 = x2 * x; + + const float4x4 m = float4x4( + +2, -3, -3, +5, + -2, +3, +3, +1, + +3, -6, +0, +4, + +1, +0, +0, +0 + ) * (1.0 / 6.0); + + return mul( m, float4( x3, x2, x, 1 ) ); +} + + +// Sample the 3D froxel fog map with bicubic filtering in the XY plane and bilinear filtering in the Z direction. +float3 SampleEveSceneFroxelFogRaw( float2 tc, float z ) +{ + + //Uncomment to disable bicubic filtering + //return EveSceneFroxelFogMap.SampleLevel(EveSceneFogSampler, float3(tc, z), 0.0f); + + + //The following code does 4x4 bicubic filtering on the froxel texture, using only bilinear for Z. + + //float2 size = PerFramePS.FroxelFogData.FroxelResolution.xy; + //float2 invSize = PerFramePS.FroxelFogData.FroxelResolution.zw; + + float width, height, dummy; + EveSceneFroxelFogMap.GetDimensions(width, height, dummy); + float2 size = float2(width, height); + float2 invSize = rcp(size); + + tc = tc * size - 0.5; + + float2 floored = floor(tc); + float2 frac = tc - floored; + + float2 baseTC = floored * invSize; + + float4 weightsX = _CubicWeights(frac.x); + float4 weightsY = _CubicWeights(frac.y); + + + //Since the specific spline used for the cubic weights means that all 4 weights will be over 1.0, + //we can sample a 2x2 area with specific weights for each of the 4 samples by carefully choosing + //the point we sample to achieve the correct ratio of weight between them, and then multiplying + //that ratio by the total of all 4 samples. + + //The problem is simplified due to the fact that we can calculate the weights along X and Y separately. + + //These are the offsets we need to use to get the correct ratio of the texels we want to sample. + float2 offsets0 = float2(weightsX.z / weightsX.x - 0.5, weightsY.z / weightsY.x - 0.5) * invSize + baseTC; //Top left + float2 offsets1 = float2(weightsX.w / weightsX.y + 1.5, weightsY.w / weightsY.y + 1.5) * invSize + baseTC; //Bot right + + //This is the total weight for each of the four samples. + float2 w = float2(weightsX.x, weightsY.x) / float2(weightsX.x + weightsX.y, weightsY.x + weightsY.y); //Top left weight + float2 iw = 1.0 - w; //Bot right weight + + //Do the 4 samples at the correct locations and apply the correct weights. + return + EveSceneFroxelFogMap.SampleLevel(EveSceneFogSampler, float3(offsets0.x, offsets0.y, z), 0.0f) * (( w.x) * ( w.y)) + + EveSceneFroxelFogMap.SampleLevel(EveSceneFogSampler, float3(offsets1.x, offsets0.y, z), 0.0f) * ((iw.x) * ( w.y)) + + EveSceneFroxelFogMap.SampleLevel(EveSceneFogSampler, float3(offsets0.x, offsets1.y, z), 0.0f) * (( w.x) * (iw.y)) + + EveSceneFroxelFogMap.SampleLevel(EveSceneFogSampler, float3(offsets1.x, offsets1.y, z), 0.0f) * ((iw.x) * (iw.y)); +} + + +// Get the froxel fog color for the given screen-space texture coordinates, scene depth. +float4 SampleEveSceneFroxelFog( float2 texCoords, float sceneDepth, EveSpaceSceneDataPS sceneData, bool sampleEnvironmentLighting ) +{ + float4 viewPositionProj = mul(float4(texCoords.x * 2.0 - 1.0, texCoords.y * -2.0 + 1.0, sceneDepth, 1.0), sceneData.ProjectionInverseMat); + float3 viewPosition = viewPositionProj.xyz / viewPositionProj.w; + + + + float dist = min(sceneData.FroxelFogData.MaxDistance, length(viewPosition)); + if(sceneDepth <= 0.0) + { + //If we're at the far plane, override the distance to match the game's expected back clip. + //This makes sure that the fog is the same even if the back clip is adjusted in Graphite. + dist = sceneData.FroxelFogData.MaxDistance; + } + + float4x4 inverseViewMatrix = transpose(sceneData.ViewInverseTransposeMat); + + float3 cameraWorldPosition = mul(float4(0.0, 0.0, 0.0, 1.0), inverseViewMatrix).xyz; + + float3 viewDirection = normalize(viewPosition); + float3 worldDirection = mul(float4(viewDirection, 0.0), inverseViewMatrix).xyz; + + [unroll] + for( int index = 0; index < 2; ++index) + { + float4 sphereData = sceneData.FroxelFogData.Planets[index]; + SphereHitInfo hitInfo = SphereRayHitTest( InitSphere( sphereData.xyz, sphereData.w ), InitRay( cameraWorldPosition, worldDirection ) ); + if( hitInfo.occurred ) + { + dist = min( dist, hitInfo.firstIntersection.w ); + } + } + + float normalizedZ = saturate((exp(-dist * sceneData.FroxelFogData.BaseDensity) - 1.0) / (sceneData.FroxelFogData.MaxDistanceVisibility - 1.0)); + + float3 froxel = SampleEveSceneFroxelFogRaw(texCoords, normalizedZ); + + float extinction = lerp(sceneData.FroxelFogData.BackgroundVisibility, 1.0, exp(-dist * sceneData.FroxelFogData.BaseDensity)); + + + + if( sampleEnvironmentLighting ) + { + float3 environmentLighting = EveSceneMieEnvironmentMap.SampleLevel(EveSceneFogSampler, worldDirection, 0.0).rgb; + + //float shadowing = sceneDepth != 0.0 ? pow(saturate(1.0 - extinction), -sceneData.FroxelFogData.EnvironmentG * 4.0) : 1.0; + float shadowing = 1.0; //Shadowing the environment lighting causes a mismatch between clouds and opaque objects. + + froxel += ((1.0 - extinction) * shadowing * sceneData.FroxelFogData.EnvironmentIntensity) * (environmentLighting * sceneData.FroxelFogData.FogColor); + } + + + return float4( froxel, extinction ); +} + + +float4 SampleEveSceneFog( float4 pos, EveSpaceSceneDataPS sceneData ) // pos is SV_Position +{ + float t0 = sceneData.VolumetricSlices.x; + float t1 = sceneData.VolumetricSlices.y; + float t2 = sceneData.VolumetricSlices.z; + float t3 = sceneData.VolumetricSlices.w; + + float i0, i1; + float z; + float depth = sceneData.ProjectionData.x / ( pos.z + sceneData.ProjectionData.y ); + float weight = 1; + if( depth > t2 ) + { + i0 = 2; + i1 = 3; + z = saturate( LinStep( t2, t3, depth ) ); + } + else if( depth > t1 ) + { + i0 = 1; + i1 = 2; + z = LinStep(t1, t2, depth); + } + else if( depth > t0 ) + { + i0 = 0; + i1 = 1; + z = LinStep(t0, t1, depth); + } + else + { + i0 = 0; + i1 = 0; + z = LinStep(0, t0, depth); + weight = depth / t0; + } + + float2 texCoords = pos.xy / sceneData.RenderTargetData.xy; + + float4 color0 = EveSceneFogVolumeMap.SampleLevel( EveSceneFogVolumeMapSampler, float3( texCoords, i0 ), 0 ); + float4 color1 = EveSceneFogVolumeMap.SampleLevel( EveSceneFogVolumeMapSampler, float3( texCoords, i1 ), 0 ); + float4 color = lerp( color0, color1, z ); + color *= weight; + return color; +} + +float4 SampleEveSceneVolumetrics( float4 pos, EveSpaceSceneDataPS sceneData ) // pos is SV_Position +{ + float4 result = SampleEveSceneFog( pos, sceneData ); + float2 texCoords = pos.xy / sceneData.RenderTargetData.xy; + float4 froxels = SampleEveSceneFroxelFog( texCoords, pos.z, sceneData, sceneData.FroxelFogData.EnvironmentIntensity > 0.0 ); + froxels.a = 1.0 - froxels.a; + result += (1.0 - result.a) * froxels; + + return result; +} + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/System.fxh b/shaders/include/carbon/System.fxh index 75b1f4eda..7706d9c66 100644 --- a/shaders/include/carbon/System.fxh +++ b/shaders/include/carbon/System.fxh @@ -78,4 +78,14 @@ #define SHADER_QUALITY SHADERMODEL #endif + +// Hits for the shader compiler signifying per-object and per-frame constant buffers. +// Used in global variable declarations. The actual register numbers specified in macros are +// just hints to the compiler, and have nothing to do with the actual binding. Declaration example: +// PerFrameStructType PerFrameVS : register( PERFRAME_VS_STARTREGISTER ); +#define PERFRAME_VS_STARTREGISTER vs, c220 +#define PERFRAME_PS_STARTREGISTER ps, c200 +#define PEROBJECT_VS_STARTREGISTER vs, c16 +#define PEROBJECT_PS_STARTREGISTER ps, c40 + #endif \ No newline at end of file From 6e17b0b9f98dc4c6bf003bd2c791508ca9964ce3 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 2 Oct 2026 12:58:18 +0000 Subject: [PATCH 45/83] Add support for TextureCube.GetDimensions override for Metal --- shadercompiler/MSLInclude.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/shadercompiler/MSLInclude.h b/shadercompiler/MSLInclude.h index 100ceabfd..8916757f1 100644 --- a/shadercompiler/MSLInclude.h +++ b/shadercompiler/MSLInclude.h @@ -332,6 +332,14 @@ void GetDimensions( texturecube tex, thread W& w, thread H& h ) h = H( tex.get_height() ); } +template +void GetDimensions( texturecube tex, uint mip, thread W& w, thread H& h, thread M& m ) +{ + w = W( tex.get_width() ); + h = H( tex.get_height() ); + m = M( tex.get_num_mip_levels() ); +} + template void GetDimensions( texture3d tex, thread W& w, thread H& h, thread D& d ) { From 4dd5e0e99a489a529b1acc692c437c3989fbe0ff Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 2 Oct 2026 13:02:36 +0000 Subject: [PATCH 46/83] More shaders --- CMakeLists.txt | 3 + shaders/include/carbon/BoneTransforms.fxh | 19 + shaders/include/carbon/Math.fxh | 4 +- .../include/carbon/SpaceScene/DepthMap.fxh | 9 + .../carbon/SpaceScene/DynamicLighting.fxh | 401 ++++++++++++++++++ .../carbon/SpaceScene/EnvironmentMap.fxh | 10 +- .../carbon/SpaceScene/PerSceneData.fxh | 6 +- shaders/include/carbon/System.fxh | 16 + 8 files changed, 457 insertions(+), 11 deletions(-) create mode 100644 shaders/include/carbon/BoneTransforms.fxh create mode 100644 shaders/include/carbon/SpaceScene/DepthMap.fxh create mode 100644 shaders/include/carbon/SpaceScene/DynamicLighting.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 6599d02d2..3102f76b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,10 +141,13 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() set(_SHADER_SOURCES + shaders/include/carbon/SpaceScene/DepthMap.fxh + shaders/include/carbon/SpaceScene/DynamicLighting.fxh shaders/include/carbon/SpaceScene/EnvironmentMap.fxh shaders/include/carbon/SpaceScene/PerSceneData.fxh shaders/include/carbon/SpaceScene/Volumetrics.fxh shaders/include/carbon/Bindless.fxh + shaders/include/carbon/BoneTransforms.fxh shaders/include/carbon/Intersections.fxh shaders/include/carbon/Math.fxh shaders/include/carbon/PackedTangents.fxh diff --git a/shaders/include/carbon/BoneTransforms.fxh b/shaders/include/carbon/BoneTransforms.fxh new file mode 100644 index 000000000..f2b6feae0 --- /dev/null +++ b/shaders/include/carbon/BoneTransforms.fxh @@ -0,0 +1,19 @@ +#ifndef CARBON_BONETRANSFORMS_FXH_ +#define CARBON_BONETRANSFORMS_FXH_ + +// Contains bone transforms for skeletal animation for all objects in the render pass. Each bone transform is a +// 4x3 matrix (3 rows of 4 floats) that represents the transformation of a bone in the skeleton. +StructuredBuffer BoneTransforms ; + +float4x4 GetBoneTransform( int boneIndex ) +{ + float4x3 bone = BoneTransforms[boneIndex]; + + float4x4 boneMatrix = float4x4( float4( bone[0], 0.0 ), + float4( bone[1], 0.0 ), + float4( bone[2], 0.0 ), + float4( bone[3], 1.0 ) ); + return boneMatrix; +} + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/Math.fxh b/shaders/include/carbon/Math.fxh index b90ce7cf4..bb96c3247 100644 --- a/shaders/include/carbon/Math.fxh +++ b/shaders/include/carbon/Math.fxh @@ -3,8 +3,8 @@ #ifndef CARBON_MATH_FXH #define CARBON_MATH_FXH -static float PI = 3.1415926535897932384626433832795; -static float _2PI = 6.283185307179586476925286766559; +static const float PI = 3.1415926535897932384626433832795; +static const float _2PI = 6.283185307179586476925286766559; static const float4x4 IDENTITY_MATRIX = float4x4(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); diff --git a/shaders/include/carbon/SpaceScene/DepthMap.fxh b/shaders/include/carbon/SpaceScene/DepthMap.fxh new file mode 100644 index 000000000..c802c914b --- /dev/null +++ b/shaders/include/carbon/SpaceScene/DepthMap.fxh @@ -0,0 +1,9 @@ +#ifndef CARBON_DEPTHMAP_FXH +#define CARBON_DEPTHMAP_FXH + +// Contains SRV representation of the depth buffer for the current render pass. Note that not all render passes may use a depth buffer, +// so this may be unbound in some cases. For example, opaque forward rendering passes may not use a depth buffer, while transparent +// forward rendering passes may use the depth buffer from the opaque pass. +Texture2D DepthMap ; + +#endif // CARBON_DEPTHMAP_FXH \ No newline at end of file diff --git a/shaders/include/carbon/SpaceScene/DynamicLighting.fxh b/shaders/include/carbon/SpaceScene/DynamicLighting.fxh new file mode 100644 index 000000000..faf217c0b --- /dev/null +++ b/shaders/include/carbon/SpaceScene/DynamicLighting.fxh @@ -0,0 +1,401 @@ +#ifndef CARBON_DYNAMICLIGHTING_FXH +#define CARBON_DYNAMICLIGHTING_FXH + +#include "../System.fxh" +#include "PerSceneData.fxh" +#include "../Math.fxh" + +// Packed light data for a single light source. See LightBuffer variable. +struct PerLightData +{ + float4 position; // xyz - world position, w - radius + float4 color; // xyz - color, w - bits 0..15 - innerRadius (float 16), bits 16..31 - flags + float4 direction; // see next few lines: + // x bits 0..15 - direction.x (float 16), x bits 16..31 - direction.y (float 16) + // y bits 0..15 - direction.z (float 16), y bits 16..31 - projectionPlaneDistance (float 16) + // z bits 0..15 - outerAngle (float 16), z bits 16..31 - innerAngle (float 16) + // w bits 0..1 - padding, w bits 2..11 - shadowMapScale, w bits 12..21 - shadowMapOffsetX, w bits 22..31 - shadowMapOffsetY +}; + +// Light flags stored in PerLightData.color.w + +// Light affects surfaces (opaque and transparent) +static const uint LIGHT_FLAG_AFFECTS_SURFACE = 1 << 16; +// Light affects particles (opaque and transparent) +static const uint LIGHT_FLAG_AFFECTS_PARTICLES = 1 << 17; +// Light casts shadows +static const uint LIGHT_FLAG_CASTS_SHADOWS = 1 << 18; +// Light affects volumetric fog (if enabled) +static const uint LIGHT_FLAG_IS_VOLUMETRIC = 1 << 19; + +// Stores linked lists of indices into LightBuffer for each tile in the screen. The buffer is partitioned into two sections: +// 3 arrays of per-tile list heads (opaque, transparent and particle arrays) and per-light next indices. The first section contains one uint per tile, +// which is the index (into LightIndexBuffer) of the first light in the linked list for that tile. The second section contains one uint per light, which is the index of the +// next light in the linked list for that tile. A value of for the index 0 indicates the end of the list. +StructuredBuffer LightIndexBuffer ; +// Stores the actual light data for each potentially visible light in the scene. The index into this buffer is stored in LightIndexBuffer. +StructuredBuffer LightBuffer ; + +// Global array of light profiles (IES profiles) for lights that use them. The index into this array is stored in PerLightData.color.w. +Texture2DArray LightProfileArray ; +SamplerState LightProfileSampler +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = None; + AddressU = Clamp; + AddressV = Clamp; +}; + +// Global shadow map atlas for all lights that cast shadows. The window of this atlas is stored in PerLightData.direction.w. +// This atlas is used when rendering rastrized shadows. Raytraced shadows are stored in EveSpaceSceneDynamicShadowMap. +DepthTexture2D ShadowMapAtlas < bool AutoRegister = true; >; + +SamplerComparisonState ShadowMapAtlasSampler +{ + AddressU = Clamp; + AddressV = Clamp; + ComparisonFunc = Greater; + Filter = COMPARISON_MIN_MAG_LINEAR_MIP_POINT; +}; + +Texture2D EveSpaceSceneDynamicShadowMap ; + +// The size of a tile in pixels. This is used to determine which tile a pixel belongs to when looking up the light list for that tile. +#define TILE_SIZE 16 + + +// ------------------------------------------------------------ PCF ------------------------------------------------------------- + +float2x2 _PCFTransform( float2 vpos, bool hasJitter, int frameIndex, float inverseShadowMapAtlasSize ) +{ + float angle = 0.0; + + //Randomize the angle if jittering is enabled (= we have some form of temporal filtering) + //Otherwise, we do no rotating at all to make sure the image isn't noisy or unstable when no AA or upscaling is enabled. + + if( hasJitter ) + { + int2 pixelPos = int2( vpos ); + //We use 9 evenly distributed rotations, which change both per pixel and over time + //This gives us effectively NUM_SAMPLES * 9 samples over time. + uint dither = ( pixelPos.x * 3u + pixelPos.y * 4u + frameIndex * 5u ) % 9u; + angle += float( dither ) * ( PI * 2.0 / 9.0 ); + } + + //Build a rotation matrix so that we can apply the quickly to each sample. + float s; + float c; + sincos( angle, s, c ); + float2x2 rotation = float2x2( + c, -s, + s, c + ); + + return rotation * inverseShadowMapAtlasSize; +} + +float2x2 _PCFTransform( float2 vpos, EveSpaceSceneDataPS perFramePS ) +{ + bool hasJitter = perFramePS.MiscData2.y != 0; + int frameIndex = perFramePS.MiscData2.x; + float inverseShadowMapAtlasSize = asfloat( perFramePS.MiscData2.z ); + return _PCFTransform( vpos, hasJitter, frameIndex, inverseShadowMapAtlasSize ); +} + +// based on: https://www.shadertoy.com/view/4djSRW +float3 _Random( float2 p, uint timer ) +{ + timer &= 2047; + float3 p3 = float3( p, float( timer ) ); + p3 = frac( p3 * float3( .1031, .1030, .0973 ) ); + p3 += dot( p3, p3.yxz + 33.33 ); + return frac( ( p3.xxy + p3.yxx ) * p3.zyx ); +} + +float3 _PCFOffset( float2 vpos, EveSpaceSceneDataPS perFramePS ) +{ + bool hasJitter = perFramePS.MiscData2.y != 0; + return hasJitter ? _Random( vpos, perFramePS.MiscData2.x ).xyz * .004 : 0.0.xxx; +} + +struct _PCFJitter +{ + float2x2 transform; + float3 offset; +}; + +_PCFJitter _GetPCFJitter( float2 vpos, EveSpaceSceneDataPS perFramePS ) +{ + _PCFJitter jitter; + jitter.transform = _PCFTransform( vpos, perFramePS ); + jitter.offset = _PCFOffset( vpos, perFramePS ); + return jitter; +} + +float _PCF( _PCFJitter pcfJitter, DepthTexture2D ShadowMapAtlas, SamplerComparisonState ShadowMapAtlasSampler, float centerDepth, float2 uv ) +{ + const int NUM_SAMPLES = 16; //higher count reduces flickering, but is slower + const float RADIUS = 4.5; //higher increases filter radius, making the transition softer and reducing flickering + + //Here we do a golden angle spiral sample pattern ("optimal" even distribution over a circle) over a larger area + float pcf = 0.0; + [unroll] + for( int i = 0; i < NUM_SAMPLES; i++ ) + { + //The following values are all constant in an unrolled loop + //That's why we don't include the extra "random" rotation here! + const float GOLDEN_ANGLE = PI * ( 3.0 - sqrt( 5.0 ) ); + float angle = float( i ) * GOLDEN_ANGLE; + float f = ( float( i ) + 0.5 ) / float( NUM_SAMPLES ); + float2 sampleOffset = float2( cos( angle ), sin( angle ) ) * ( sqrt( f ) * RADIUS ); + float weight = 1.0 / float( NUM_SAMPLES ); + + //These are actually calculated per sample, so we apply the per-pixel rotation here + float2 sampleUV = uv + mul( pcfJitter.transform, sampleOffset ); + + float comparisonResult = ShadowMapAtlas.SampleCmpLevelZero( ShadowMapAtlasSampler, sampleUV, centerDepth ); + pcf += comparisonResult * weight; + } + + float visibility = pcf; + return visibility; +} + +// ------------------------------------------------------------------------------------------------------------------------------ + +struct ShadowData +{ + _PCFJitter pcfJitter; + uint raytracedMask; +}; + +ShadowData GetShadowData( float2 vpos, EveSpaceSceneDataPS perFramePS ) +{ + ShadowData shadowData; + shadowData.pcfJitter.transform = float2x2( 0., 0., 0., 0. ); + shadowData.pcfJitter.offset = 0.0.xxx; + shadowData.raytracedMask = 0; + + uint shadowQuality = asuint( perFramePS.ShadowMapSettings2.w ); + if( ( shadowQuality & ( SHADOW_QUALITY_FLAG_LOW | SHADOW_QUALITY_FLAG_HIGH ) ) != 0 ) + { + shadowData.pcfJitter = _GetPCFJitter( vpos, perFramePS ); + } + if( ( shadowQuality & SHADOW_QUALITY_FLAG_RAYTRACED ) != 0 ) + { + shadowData.raytracedMask = EveSpaceSceneDynamicShadowMap.Load( int3( int2( vpos.xy ), 0 ) ).x; + } + return shadowData; +} + +// Light list types for GetDynamicLightingListHead function +static const uint LIGHT_LIST_TYPE_OPAQUE = 0; +static const uint LIGHT_LIST_TYPE_TRANSPARENT = 1; +static const uint LIGHT_LIST_TYPE_PARTICLES = 2; + +// Returns the index of the first light record in the linked list for the tile that contains the pixel at vpos. +// The lightListType parameter specifies which list to return (opaque, transparent or particle). +uint GetDynamicLightingListHead( uint2 vpos, uint targetWidth, uint lightListType ) +{ + uint2 pixelPos = vpos.xy / TILE_SIZE; + uint tilesPerRow = ( targetWidth + TILE_SIZE - 1 ) / TILE_SIZE; + uint index = pixelPos.x + pixelPos.y * tilesPerRow; + return LightIndexBuffer[index * 3 + lightListType]; +} + + +struct ComputedDynamicLight +{ + // Direction from the lit position to the light source, normalized. + float3 lightDirection; + // Distance from the lit position to the light source. + float distance; + // Color of the light source, after shadowing. Does not take distance-based attenuation into account. + float3 lightColor; + // Increase in roughness due to the light. + float roughnessIncrease; + // Light radius + float radius; + // Light inner radius + float innerRadius; +}; + +// Computes the lighting contribution of a single light source at a given position in world space. +// Returns true if the light contributes to the lighting at the given position (based on distance and filters), false otherwise. +// The lighting data is returned in the computedDynamicLight parameter. +// Parameters: +// shadowData - Shadow data for the current pixel, including PCF jitter and raytraced mask. Normally GetDynamicLight is called in a loop over all lights, +// and this data is computed once per pixel and passed to each call to GetDynamicLight. +// inverseShadowMapAtlasSize - Inverse size of the shadow map atlas (from EveSpaceSceneDataPS). +// shadowMapAtlasEntryMinSizeLog2 - Minimum size of a shadow map atlas entry, in log2 (from EveSpaceSceneDataPS). +// shadowQuality - Current shadow quality setting in the application (from EveSpaceSceneDataPS, see SHADOW_QUALITY_FLAG_*). +// lightData - Data for the light source, obtained from LightBuffer. +// litPosition - Position in world space being lit. +// flags - Flags for filtering which lights to consider (LIGHT_FLAG_*). +bool GetDynamicLight( + ShadowData shadowData, + float inverseShadowMapAtlasSize, + uint shadowMapAtlasEntryMinSizeLog2, + uint shadowQuality, + PerLightData lightData, + float3 litPosition, + uint flags, + out ComputedDynamicLight computedDynamicLight ) +{ + computedDynamicLight.lightDirection = 0; + computedDynamicLight.distance = 0; + computedDynamicLight.lightColor = 0; + computedDynamicLight.roughnessIncrease = 0; + computedDynamicLight.radius = 0; + computedDynamicLight.innerRadius = 0; + + computedDynamicLight.lightDirection = lightData.position.xyz - litPosition; + float3 unnormalizedLightDirection = computedDynamicLight.lightDirection; + computedDynamicLight.distance = length( computedDynamicLight.lightDirection ); + computedDynamicLight.lightDirection /= computedDynamicLight.distance; + + float radius = lightData.position.w; + computedDynamicLight.radius = radius; + float innerRadius = f16tof32( asuint( lightData.color.w ) & 0xffff ); + computedDynamicLight.innerRadius = innerRadius; + uint lightFlags = asuint( lightData.color.w ); + uint profile = lightFlags >> 20; + bool gotShadowMap = ( lightFlags & LIGHT_FLAG_CASTS_SHADOWS ) != 0; + + float3 lightDir = float3( + f16tof32( asuint( lightData.direction.x ) & 0xffff ), + f16tof32( asuint( lightData.direction.x ) >> 16 ), + f16tof32( asuint( lightData.direction.y ) & 0xffff ) + ); + float outerCosAngle = f16tof32( asuint( lightData.direction.z ) & 0xffff ); + float innerCosAngle = f16tof32( asuint( lightData.direction.z ) >> 16 ); + float cosAngle = dot( lightDir, computedDynamicLight.lightDirection ); + + bool result = false; + [branch] + if( computedDynamicLight.distance < radius && ( lightFlags & flags ) != 0 ) + { + float pointLightFuzzyness = clamp( innerRadius / computedDynamicLight.distance, 0.0, 0.8 ); + + // fuzzFactor needs to be in the 4th power (or 2 powers stronger than roughness) + // so the fuzz doesn't overshadow the roughness of the material (if that makes sense) + float fuzzFactor = pow( pointLightFuzzyness, 4 ); + + float attenuation = 1; + + if( outerCosAngle > 0.0f ) + { + attenuation *= pow( LinStep( outerCosAngle, innerCosAngle, cosAngle ), 2 ); + } + if( profile > 0 ) + { + attenuation *= LightProfileArray.SampleLevel( LightProfileSampler, float3( cosAngle * -0.5 + 0.5, 0, profile - 1 ), 0 ); + } + + if( ( shadowQuality & ( SHADOW_QUALITY_FLAG_LOW | SHADOW_QUALITY_FLAG_HIGH ) ) != 0 && inverseShadowMapAtlasSize > 0. && gotShadowMap && attenuation > 0. ) + { + uint shadowMapScale = ( ( asuint( lightData.direction.w ) >> 2 ) & ( ( 1 << 10 ) - 1 ) ) << shadowMapAtlasEntryMinSizeLog2; + uint shadowMapOffsetX = ( ( asuint( lightData.direction.w ) >> 12 ) & ( ( 1 << 10 ) - 1 ) ) << shadowMapAtlasEntryMinSizeLog2; + uint shadowMapOffsetY = ( ( asuint( lightData.direction.w ) >> 22 ) & ( ( 1 << 10 ) - 1 ) ) << shadowMapAtlasEntryMinSizeLog2; + float projectionPlaneDistance = f16tof32( asuint( lightData.direction.y ) >> 16 ); + + float depth = 0.; + if( outerCosAngle > 0.0f ) + { + // spotlight + lightDir = -lightDir; + float3 up = abs( lightDir.y ) < .7 ? float3( 0., 1., 0. ) : float3( 1., 0., 0. ); + float3 side = normalize( cross( lightDir, up ) ); + up = cross( side, lightDir ); + float3x3 lightRotation = float3x3( side, up, lightDir ); + unnormalizedLightDirection = mul( lightRotation, -unnormalizedLightDirection ); + depth = unnormalizedLightDirection.z; + } + else + { + // pointlight + float3 absLightDir = abs( computedDynamicLight.lightDirection ); + absLightDir += shadowData.pcfJitter.offset; + float maxDir = max( max( absLightDir.x, absLightDir.y ), absLightDir.z ); + if( absLightDir.x == maxDir ) + { + depth = unnormalizedLightDirection.x; + unnormalizedLightDirection.xy = unnormalizedLightDirection.zy; + shadowMapOffsetX += 0; + } + else if( absLightDir.y == maxDir ) + { + depth = unnormalizedLightDirection.y; + unnormalizedLightDirection.xy = unnormalizedLightDirection.xz; + shadowMapOffsetX += shadowMapScale; + } + else + { + depth = unnormalizedLightDirection.z; + unnormalizedLightDirection.xy = unnormalizedLightDirection.yx; + shadowMapOffsetX += 2 * shadowMapScale; + } + unnormalizedLightDirection.y *= depth > 0. ? -1. : 1.; + shadowMapOffsetY += depth < 0. ? shadowMapScale : 0; + depth = abs( depth ); + } + + // perspective projection of z, assuming reverse z and far clip being the same as near clip divided by 1000 + const float b = 1. / 999.; + float m = radius * b; + unnormalizedLightDirection.z = -b + m / depth; + + // perspective projection of xy and flipping image + unnormalizedLightDirection.xy *= ( projectionPlaneDistance / depth ); + unnormalizedLightDirection.y *= -1.; + + // margin scale and changing value range from [-1, 1] to [0, 1] + const float margin = 8.; + float marginScale = .5 - ( margin / shadowMapScale ); + unnormalizedLightDirection.xy = unnormalizedLightDirection.xy * marginScale + .5.xx; + + // coordinate on atlas + unnormalizedLightDirection.xy = unnormalizedLightDirection.xy * float( shadowMapScale ) + float2( shadowMapOffsetX, shadowMapOffsetY ); + unnormalizedLightDirection.xy *= inverseShadowMapAtlasSize; + + float visibility = _PCF( shadowData.pcfJitter, ShadowMapAtlas, ShadowMapAtlasSampler, unnormalizedLightDirection.z, unnormalizedLightDirection.xy ); + + attenuation *= visibility; + } + + if( ( shadowQuality & SHADOW_QUALITY_FLAG_RAYTRACED ) != 0 && gotShadowMap && attenuation > 0. ) + { + uint shadowMask = ( ( asuint( lightData.direction.w ) ) & ( ( 1 << 16 ) - 1 ) ); + int shadow = shadowData.raytracedMask & shadowMask; + attenuation *= shadow != 0 ? 0. : 1.; + } + + computedDynamicLight.lightColor = lightData.color.rgb * attenuation; // innerRadius now softens the core in GetBoundedAttenuation; (1-fuzz) dimming dropped to avoid double-counting source size (fuzz still drives roughnessIncrease) + computedDynamicLight.roughnessIncrease = fuzzFactor; + result = true; + } + return result; +} + +// Computes the lighting contribution of a single light source at a given position in world space. +// Returns true if the light contributes to the lighting at the given position (based on distance and filters), false otherwise. +// The lighting data is returned in the computedDynamicLight parameter. +// Parameters: +// shadowData - Shadow data for the current pixel, including PCF jitter and raytraced mask. Normally GetDynamicLight is called in a loop over all lights, +// and this data is computed once per pixel and passed to each call to GetDynamicLight. +// index - Index of the light in LightBuffer to compute lighting for. +// litPosition - Position in world space being lit. +// perFramePS - Per-scene pixel shader data (from EveSpaceSceneDataPS). +// flags - Flags for filtering which lights to consider (LIGHT_FLAG_*). +bool GetDynamicLight( ShadowData shadowData, uint index, float3 litPosition, EveSpaceSceneDataPS perFramePS, uint flags, out ComputedDynamicLight computedDynamicLight ) +{ + PerLightData lightData = LightBuffer[index]; + float inverseShadowMapAtlasSize = asfloat( perFramePS.MiscData2.z ); + uint shadowMapAtlasEntryMinSizeLog2 = asuint( perFramePS.MiscData2.w ); + uint shadowQuality = asuint( perFramePS.ShadowMapSettings2.w ); + return GetDynamicLight( shadowData, inverseShadowMapAtlasSize, shadowMapAtlasEntryMinSizeLog2, shadowQuality, lightData, litPosition, flags, computedDynamicLight ); +} + + +#endif \ No newline at end of file diff --git a/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh b/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh index 0a97167f8..c68b4130b 100644 --- a/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh +++ b/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh @@ -46,8 +46,8 @@ float RoughnessToMip( TextureCube envMap, float roughness ) { uint width; uint height; - uint mipLevels; - envMap.GetDimensions( width, height, mipLevels ); + uint mipLevels; + envMap.GetDimensions( 0, width, height, mipLevels ); return ( 1.0f - RoughnessToGloss( roughness ) ) * float( mipLevels - 1 ); } @@ -64,10 +64,4 @@ float3 SampleEnvironmentMap( TextureCube envMap, float3 dir, float roughness ) return envMap.SampleLevel( EveSpaceSceneEnvMapSampler, dir, RoughnessToMip( envMap, roughness ) ).rgb; } -// Sample EveSpaceSceneEnvMap with given direction and surface roughness -float3 SampleEnvironmentMap( float3 dir, float roughness ) -{ - return SampleEnvironmentMap( EveSpaceSceneEnvMap, dir, roughness ); -} - #endif \ No newline at end of file diff --git a/shaders/include/carbon/SpaceScene/PerSceneData.fxh b/shaders/include/carbon/SpaceScene/PerSceneData.fxh index ae3282747..3b022e8b1 100644 --- a/shaders/include/carbon/SpaceScene/PerSceneData.fxh +++ b/shaders/include/carbon/SpaceScene/PerSceneData.fxh @@ -48,6 +48,10 @@ struct EveSpaceSceneDataVS float4 MiscParams; // x - time, y - upscaling amount, zw - viewport size }; +static const uint SHADOW_QUALITY_FLAG_DISABLED = 1; +static const uint SHADOW_QUALITY_FLAG_LOW = 1 << 1; +static const uint SHADOW_QUALITY_FLAG_HIGH = 1 << 2; +static const uint SHADOW_QUALITY_FLAG_RAYTRACED = 1 << 3; // Per-scene (per-frame) constant buffer data for the pixel shader. struct EveSpaceSceneDataPS @@ -67,7 +71,7 @@ struct EveSpaceSceneDataPS float4 ViewportOffsetSize; // .xy - viewport offset, .zw - viewport size float4 RenderTargetData; // .xy - RT size in pixel, z - MSAA sample count (legacy, always 1 nowadays), w - debug float4 ShadowMapSettings; // .xyzw - various shadow filter parameters - float4 ShadowMapSettings2; // .xy - shadow camera range, .z - shadow lightness, .w - shadow quality + float4 ShadowMapSettings2; // .xy - shadow camera range, .z - shadow lightness, .w - shadow quality, uint (SHADOW_QUALITY_FLAG_*) float4 ProjectionData; // x - projection[3][2], y - projection[2][2], .zw = FoV float4 MiscData; // x - time, y - scenemiplodbias, z - upscaling amount, w - gamma brightness uint4 MiscData2; // x - frame counter, y - Jittering (bool), z - InverseShadowMapAtlasSize (float), w - ShadowMapAtlasEntryMinSizeLog2 (uint) diff --git a/shaders/include/carbon/System.fxh b/shaders/include/carbon/System.fxh index 7706d9c66..624090fcc 100644 --- a/shaders/include/carbon/System.fxh +++ b/shaders/include/carbon/System.fxh @@ -88,4 +88,20 @@ #define PEROBJECT_VS_STARTREGISTER vs, c16 #define PEROBJECT_PS_STARTREGISTER ps, c40 + +#if __INTELLISENSE__ + +// Intellisense stub definions for custom types used by the shader compiler. + +// DepthTexture2D is a custom type recognized by the shader compiler. It is used to declare depth textures in a platform-independent way. +#define DepthTexture2D Texture2D + +// Bindless handles are essentially uint values on all supported platforms, but the shader compiler recognizes them as custom types for additional semantics. +#define BindlessHandleTexture2D uint +#define BindlessHandleTexture3D uint +#define BindlessHandleTextureCube uint +#define BindlessHandleSampler uint + +#endif + #endif \ No newline at end of file From feb984855b1ae9a9929b02f789da2565f0a5d068 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 2 Oct 2026 13:17:02 +0000 Subject: [PATCH 47/83] Rename carbon shader include directory --- shaders/include/{carbon => Carbon}/Bindless.fxh | 0 shaders/include/{carbon => Carbon}/BoneTransforms.fxh | 0 shaders/include/{carbon => Carbon}/Intersections.fxh | 0 shaders/include/{carbon => Carbon}/Math.fxh | 0 shaders/include/{carbon => Carbon}/PackedTangents.fxh | 0 shaders/include/{carbon => Carbon}/ParticleAnnotations.fxh | 0 shaders/include/{carbon => Carbon}/SpaceScene/DepthMap.fxh | 0 shaders/include/{carbon => Carbon}/SpaceScene/DynamicLighting.fxh | 0 shaders/include/{carbon => Carbon}/SpaceScene/EnvironmentMap.fxh | 0 shaders/include/{carbon => Carbon}/SpaceScene/PerSceneData.fxh | 0 shaders/include/{carbon => Carbon}/SpaceScene/Volumetrics.fxh | 0 shaders/include/{carbon => Carbon}/System.fxh | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename shaders/include/{carbon => Carbon}/Bindless.fxh (100%) rename shaders/include/{carbon => Carbon}/BoneTransforms.fxh (100%) rename shaders/include/{carbon => Carbon}/Intersections.fxh (100%) rename shaders/include/{carbon => Carbon}/Math.fxh (100%) rename shaders/include/{carbon => Carbon}/PackedTangents.fxh (100%) rename shaders/include/{carbon => Carbon}/ParticleAnnotations.fxh (100%) rename shaders/include/{carbon => Carbon}/SpaceScene/DepthMap.fxh (100%) rename shaders/include/{carbon => Carbon}/SpaceScene/DynamicLighting.fxh (100%) rename shaders/include/{carbon => Carbon}/SpaceScene/EnvironmentMap.fxh (100%) rename shaders/include/{carbon => Carbon}/SpaceScene/PerSceneData.fxh (100%) rename shaders/include/{carbon => Carbon}/SpaceScene/Volumetrics.fxh (100%) rename shaders/include/{carbon => Carbon}/System.fxh (100%) diff --git a/shaders/include/carbon/Bindless.fxh b/shaders/include/Carbon/Bindless.fxh similarity index 100% rename from shaders/include/carbon/Bindless.fxh rename to shaders/include/Carbon/Bindless.fxh diff --git a/shaders/include/carbon/BoneTransforms.fxh b/shaders/include/Carbon/BoneTransforms.fxh similarity index 100% rename from shaders/include/carbon/BoneTransforms.fxh rename to shaders/include/Carbon/BoneTransforms.fxh diff --git a/shaders/include/carbon/Intersections.fxh b/shaders/include/Carbon/Intersections.fxh similarity index 100% rename from shaders/include/carbon/Intersections.fxh rename to shaders/include/Carbon/Intersections.fxh diff --git a/shaders/include/carbon/Math.fxh b/shaders/include/Carbon/Math.fxh similarity index 100% rename from shaders/include/carbon/Math.fxh rename to shaders/include/Carbon/Math.fxh diff --git a/shaders/include/carbon/PackedTangents.fxh b/shaders/include/Carbon/PackedTangents.fxh similarity index 100% rename from shaders/include/carbon/PackedTangents.fxh rename to shaders/include/Carbon/PackedTangents.fxh diff --git a/shaders/include/carbon/ParticleAnnotations.fxh b/shaders/include/Carbon/ParticleAnnotations.fxh similarity index 100% rename from shaders/include/carbon/ParticleAnnotations.fxh rename to shaders/include/Carbon/ParticleAnnotations.fxh diff --git a/shaders/include/carbon/SpaceScene/DepthMap.fxh b/shaders/include/Carbon/SpaceScene/DepthMap.fxh similarity index 100% rename from shaders/include/carbon/SpaceScene/DepthMap.fxh rename to shaders/include/Carbon/SpaceScene/DepthMap.fxh diff --git a/shaders/include/carbon/SpaceScene/DynamicLighting.fxh b/shaders/include/Carbon/SpaceScene/DynamicLighting.fxh similarity index 100% rename from shaders/include/carbon/SpaceScene/DynamicLighting.fxh rename to shaders/include/Carbon/SpaceScene/DynamicLighting.fxh diff --git a/shaders/include/carbon/SpaceScene/EnvironmentMap.fxh b/shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh similarity index 100% rename from shaders/include/carbon/SpaceScene/EnvironmentMap.fxh rename to shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh diff --git a/shaders/include/carbon/SpaceScene/PerSceneData.fxh b/shaders/include/Carbon/SpaceScene/PerSceneData.fxh similarity index 100% rename from shaders/include/carbon/SpaceScene/PerSceneData.fxh rename to shaders/include/Carbon/SpaceScene/PerSceneData.fxh diff --git a/shaders/include/carbon/SpaceScene/Volumetrics.fxh b/shaders/include/Carbon/SpaceScene/Volumetrics.fxh similarity index 100% rename from shaders/include/carbon/SpaceScene/Volumetrics.fxh rename to shaders/include/Carbon/SpaceScene/Volumetrics.fxh diff --git a/shaders/include/carbon/System.fxh b/shaders/include/Carbon/System.fxh similarity index 100% rename from shaders/include/carbon/System.fxh rename to shaders/include/Carbon/System.fxh From 87cdc0c12fb94725bf2593871e23eeaa0b6058d1 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 2 Oct 2026 13:22:55 +0000 Subject: [PATCH 48/83] Update path --- CMakeLists.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3102f76b7..8897db678 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,18 +141,18 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() set(_SHADER_SOURCES - shaders/include/carbon/SpaceScene/DepthMap.fxh - shaders/include/carbon/SpaceScene/DynamicLighting.fxh - shaders/include/carbon/SpaceScene/EnvironmentMap.fxh - shaders/include/carbon/SpaceScene/PerSceneData.fxh - shaders/include/carbon/SpaceScene/Volumetrics.fxh - shaders/include/carbon/Bindless.fxh - shaders/include/carbon/BoneTransforms.fxh - shaders/include/carbon/Intersections.fxh - shaders/include/carbon/Math.fxh - shaders/include/carbon/PackedTangents.fxh - shaders/include/carbon/ParticleAnnotations.fxh - shaders/include/carbon/System.fxh + shaders/include/Carbon/SpaceScene/DepthMap.fxh + shaders/include/Carbon/SpaceScene/DynamicLighting.fxh + shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh + shaders/include/Carbon/SpaceScene/PerSceneData.fxh + shaders/include/Carbon/SpaceScene/Volumetrics.fxh + shaders/include/Carbon/Bindless.fxh + shaders/include/Carbon/BoneTransforms.fxh + shaders/include/Carbon/Intersections.fxh + shaders/include/Carbon/Math.fxh + shaders/include/Carbon/PackedTangents.fxh + shaders/include/Carbon/ParticleAnnotations.fxh + shaders/include/Carbon/System.fxh ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) From c6b2e308ac1da60913243547a97e46e55f59072a Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 2 Oct 2026 15:00:33 +0000 Subject: [PATCH 49/83] More shaders --- CMakeLists.txt | 1 + shaders/include/Carbon/BoneTransforms.fxh | 2 + .../include/Carbon/SpaceScene/DepthMap.fxh | 2 + .../Carbon/SpaceScene/DynamicLighting.fxh | 2 + .../Carbon/SpaceScene/PerObjectData.fxh | 194 ++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/PerObjectData.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 8897db678..3d67b6182 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/DepthMap.fxh shaders/include/Carbon/SpaceScene/DynamicLighting.fxh shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh + shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh shaders/include/Carbon/Bindless.fxh diff --git a/shaders/include/Carbon/BoneTransforms.fxh b/shaders/include/Carbon/BoneTransforms.fxh index f2b6feae0..7a948441f 100644 --- a/shaders/include/Carbon/BoneTransforms.fxh +++ b/shaders/include/Carbon/BoneTransforms.fxh @@ -1,3 +1,5 @@ +// Copyright © 2026 CCP ehf. + #ifndef CARBON_BONETRANSFORMS_FXH_ #define CARBON_BONETRANSFORMS_FXH_ diff --git a/shaders/include/Carbon/SpaceScene/DepthMap.fxh b/shaders/include/Carbon/SpaceScene/DepthMap.fxh index c802c914b..b2bcc1d95 100644 --- a/shaders/include/Carbon/SpaceScene/DepthMap.fxh +++ b/shaders/include/Carbon/SpaceScene/DepthMap.fxh @@ -1,3 +1,5 @@ +// Copyright © 2026 CCP ehf. + #ifndef CARBON_DEPTHMAP_FXH #define CARBON_DEPTHMAP_FXH diff --git a/shaders/include/Carbon/SpaceScene/DynamicLighting.fxh b/shaders/include/Carbon/SpaceScene/DynamicLighting.fxh index faf217c0b..3df0ea43f 100644 --- a/shaders/include/Carbon/SpaceScene/DynamicLighting.fxh +++ b/shaders/include/Carbon/SpaceScene/DynamicLighting.fxh @@ -1,3 +1,5 @@ +// Copyright © 2026 CCP ehf. + #ifndef CARBON_DYNAMICLIGHTING_FXH #define CARBON_DYNAMICLIGHTING_FXH diff --git a/shaders/include/Carbon/SpaceScene/PerObjectData.fxh b/shaders/include/Carbon/SpaceScene/PerObjectData.fxh new file mode 100644 index 000000000..f36d9bdde --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/PerObjectData.fxh @@ -0,0 +1,194 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_PEROBJECTDATA_FXH +#define CARBON_PEROBJECTDATA_FXH + +#include "../BoneTransforms.fxh" + +// Constant buffer format for per-object data for space scene objects. This data is provided by the engine to the vertex shader stage. +struct EveSpaceObjectDataVS +{ + // world transform of this object + float4x4 WorldMat; + // world transform of this object in the previous frame + float4x4 WorldMatLast; + // inverse world transform of this object + float4x4 InvWorldMat; + // additional ship-data ( components: .x = boosterGain, .y = activation, .z = unused, .w = boundingsphere radius ) + float4 Shipdata; + // clip data for disolve fx ( components: .xyz = center, .w = signed squared size ) + float4 Clipdata1; + // bounding ellipsoid data + float4 EllipsoidRadii; + float4 EllipsoidCenter; + // custom mask data for pattern projection + float4x4 CustomMaskMatrix[2]; + // additional custommap-data ( components: .x = layerCount, components: .y = isMirrored, ) + float4 CustomMaskData[2]; + + uint4 BoneOffsets; // .x = current frame offset, .y = previous frame offset + uint4 MorphTarget; // .x = VertexDataOffset, .y = AnimationDataOffset, .z = MorphTargetsCount, .w = BakedVertexDataOffset + + float4 CustomData; +}; + +// Constant buffer format for per-object data for space scene objects. This data is provided by the engine to the pixel shader stage. +struct EveSpaceObjectDataPS +{ + // world transform of this object + float4x4 WorldMat; + // world transform of this object in the previous frame + float4x4 WorldMatLast; + // inverse world transform of this object + float4x4 InvWorldMat; + + // additional ship-data ( components: .x = boosterGain, .y = activation, .z = dirt level, .w = boundingsphere radius ) + float4 Shipdata; + // clip data for disolve fx ( components: .xyz = center, .w = signed squared size ) + float4 Clipdata1; + // misc data ( .x = signed squared clip sphere 2 radius, .y = impact data offset, .z = clip sphere 2 factor, .w = clip sphere factor) + float4 Miscdata; + // SH lighting coefficients + float4 ShLighting[7]; + // custom mask material ids ( components: .x = material1, .y = material2, .z = material3, .w = material4 ) + float4 CustomMaskMaterialIDs[2]; + // custom mask targets ( components: .x = isTargetMtl1, .y = isTargetMtl2, .z = isTargetMtl3, .w = isTargetMtl4 ) + float4 CustomMaskTargets[2]; + float4 CustomMaskClamps; + float4 ScreenSize; + float4 CustomData; +}; + +// Unified buffer per-object data for space scene objects. Used by shared instanced rendering and read from InstancedPerObjectBuffer. +// It is also possible to construct this data from the VS and PS per-object data structures, but some fields will be zeroed out. +// See CreateEveSpaceObjectData() functions below. +struct EveSpaceObjectData +{ + // world transform of this object + float4x4 WorldMat; + // world transform of this object in the previous frame + float4x4 WorldMatLast; + // inverse world transform of this object + float4x4 InvWorldMat; + // additional ship-data ( components: .x = boosterGain, .y = activation, .z = unused, .w = boundingsphere radius ) + float4 Shipdata; + // clip data for disolve fx ( components: .xyz = center, .w = signed squared size ) + float4 Clipdata1; + // misc data ( .x = signed squared clip sphere 2 radius, .y = impact data offset, .z = clip sphere 2 factor, .w = clip sphere factor) + float4 Miscdata; + + // bounding ellipsoid data + float4 EllipsoidRadii; + float4 EllipsoidCenter; + + // custom mask data + float4x4 CustomMaskMatrix[2]; + // additional custommap-data ( components: .x = layerCount, components: .y = isMirrored, ) + float4 CustomMaskData[2]; + // custom mask material ids ( components: .x = material1, .y = material2, .z = material3, .w = material4 ) + float4 CustomMaskMaterialIDs[2]; + // custom mask targets ( components: .x = isTargetMtl1, .y = isTargetMtl2, .z = isTargetMtl3, .w = isTargetMtl4 ) + float4 CustomMaskTargets[2]; + float4 CustomMaskClamps; + + // .x = current frame offset, .y = previous frame offset + uint4 BoneOffsets; + // .x - tactical camera object type, .y - tactical view transparency type + float4 CustomData; + // SH lighting coefficients + float4 ShLighting[7]; +}; + + +EveSpaceObjectData CreateEveSpaceObjectData( EveSpaceObjectDataVS vsData ) +{ + EveSpaceObjectData perObjectData; + perObjectData.WorldMat = vsData.WorldMat; + perObjectData.WorldMatLast = vsData.WorldMatLast; + perObjectData.InvWorldMat = vsData.InvWorldMat; + perObjectData.Shipdata = vsData.Shipdata; + perObjectData.Clipdata1 = vsData.Clipdata1; + perObjectData.Miscdata = 0; + perObjectData.EllipsoidRadii = vsData.EllipsoidRadii; + perObjectData.EllipsoidCenter = vsData.EllipsoidCenter; + perObjectData.CustomMaskMatrix[0] = vsData.CustomMaskMatrix[0]; + perObjectData.CustomMaskMatrix[1] = vsData.CustomMaskMatrix[1]; + perObjectData.CustomMaskData[0] = vsData.CustomMaskData[0]; + perObjectData.CustomMaskData[1] = vsData.CustomMaskData[1]; + perObjectData.CustomMaskMaterialIDs[0] = 0; + perObjectData.CustomMaskMaterialIDs[1] = 0; + perObjectData.CustomMaskTargets[0] = 0; + perObjectData.CustomMaskTargets[1] = 0; + perObjectData.CustomMaskClamps = 0; + perObjectData.BoneOffsets = vsData.BoneOffsets; + perObjectData.CustomData = vsData.CustomData; + perObjectData.ShLighting[0] = 0; + perObjectData.ShLighting[1] = 0; + perObjectData.ShLighting[2] = 0; + perObjectData.ShLighting[3] = 0; + perObjectData.ShLighting[4] = 0; + perObjectData.ShLighting[5] = 0; + perObjectData.ShLighting[6] = 0; + return perObjectData; +} + +EveSpaceObjectData CreateEveSpaceObjectData( EveSpaceObjectDataPS psData ) +{ + EveSpaceObjectData perObjectData; + perObjectData.WorldMat = psData.WorldMat; + perObjectData.WorldMatLast = psData.WorldMatLast; + perObjectData.InvWorldMat = psData.InvWorldMat; + perObjectData.Shipdata = psData.Shipdata; + perObjectData.Clipdata1 = psData.Clipdata1; + perObjectData.Miscdata = psData.Miscdata; + perObjectData.EllipsoidRadii = 0; + perObjectData.EllipsoidCenter = 0; + perObjectData.CustomMaskMatrix[0] = float4x4( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + perObjectData.CustomMaskMatrix[1] = float4x4( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + perObjectData.CustomMaskData[0] = 0; + perObjectData.CustomMaskData[1] = 0; + perObjectData.CustomMaskMaterialIDs[0] = psData.CustomMaskMaterialIDs[0]; + perObjectData.CustomMaskMaterialIDs[1] = psData.CustomMaskMaterialIDs[1]; + perObjectData.CustomMaskTargets[0] = psData.CustomMaskTargets[0]; + perObjectData.CustomMaskTargets[1] = psData.CustomMaskTargets[1]; + perObjectData.CustomMaskClamps = psData.CustomMaskClamps; + perObjectData.BoneOffsets = 0; + perObjectData.CustomData = psData.CustomData; + + perObjectData.ShLighting[0] = psData.ShLighting[0]; + perObjectData.ShLighting[1] = psData.ShLighting[1]; + perObjectData.ShLighting[2] = psData.ShLighting[2]; + perObjectData.ShLighting[3] = psData.ShLighting[3]; + perObjectData.ShLighting[4] = psData.ShLighting[4]; + perObjectData.ShLighting[5] = psData.ShLighting[5]; + perObjectData.ShLighting[6] = psData.ShLighting[6]; + // intentionally skipping ScreenSize as I don't think it's used + return perObjectData; +} + +// This buffer contains per-object data for shared instanced rendering. +StructuredBuffer InstancedPerObjectBuffer ; + + +float4x4 GetBoneMatrix( EveSpaceObjectData perObjectData, int boneIndex ) +{ + return GetBoneTransform( perObjectData.BoneOffsets.x + boneIndex ); +} + +float4x4 GetLastBoneMatrix( EveSpaceObjectData perObjectData, int boneIndex ) +{ + return GetBoneTransform( perObjectData.BoneOffsets.y + boneIndex ); +} + +float4x4 GetBoneMatrix( EveSpaceObjectDataVS perObjectData, int boneIndex ) +{ + return GetBoneTransform( perObjectData.BoneOffsets.x + boneIndex ); +} + +float4x4 GetLastBoneMatrix( EveSpaceObjectDataVS perObjectData, int boneIndex ) +{ + return GetBoneTransform( perObjectData.BoneOffsets.y + boneIndex ); +} + + +#endif \ No newline at end of file From 1820eb0b823215149a49730f562b5a44223165fc Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 5 Oct 2026 10:35:20 +0000 Subject: [PATCH 50/83] Booster shader headers --- CMakeLists.txt | 3 ++ .../SpaceScene/BehaviorGroupBooster.fxh | 23 ++++++++ .../Carbon/SpaceScene/EveBoosterSet.fxh | 49 +++++++++++++++++ .../Carbon/SpaceScene/EveChildBoosterSet.fxh | 54 +++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d67b6182..5806deb3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,9 +141,12 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() set(_SHADER_SOURCES + shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh shaders/include/Carbon/SpaceScene/DepthMap.fxh shaders/include/Carbon/SpaceScene/DynamicLighting.fxh shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh + shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh + shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh diff --git a/shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh b/shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh new file mode 100644 index 000000000..64e54e5c8 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh @@ -0,0 +1,23 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_BEHAVIORGROUPBOOSTER_FXH +#define CARBON_BEHAVIORGROUPBOOSTER_FXH + + +// Data passed from the engine to the vertex shader stage for BehaviourGroupBooster draw calls. +struct BehaviourGroupBoosterVertexInput +{ + // Vertex position in local instance space + float3 position : POSITION; + // UV coordinates + float2 texCoord : TEXCOORD0; + // Owner agent position (xyz) and scale (w) + float4 agentPos : TEXCOORD1; + // Owner agent rotation quaternion + float4 agentRot : TEXCOORD2; + // Booster data: x=intensity, y= per agent random number (0 to 1), z=atlasIndex0, w=atlasindex1 + float4 boosterData : TEXCOORD3; +}; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh b/shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh new file mode 100644 index 000000000..990832fa9 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh @@ -0,0 +1,49 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVEBOOSTERSET_FXH +#define CARBON_EVEBOOSTERSET_FXH + +// Data passed from the engine to the vertex shader stage for EveBoosterSet draw calls. +struct EveBoosterSetVertexInput +{ + // Vertex position in local instance space + float3 position : POSITION; + // UV coordinates; only filled when shader quality is set to low, for "star" shaped boosters + float2 texCoord : TEXCOORD0; + // 4x4 matrix that transforms the booster from local instance space to object space + float4 row1 : TEXCOORD1; + float4 row2 : TEXCOORD2; + float4 row3 : TEXCOORD3; + float4 row4 : TEXCOORD4; + // Custom values passed from SOF (no particular semantics, but can be used for various purposes in the shader) + float4 functionality : TEXCOORD5; + // Per booster instance random number from 0 to 1 used for offsetting booster animations + float wavePhase : TEXCOORD6; + // Texture atlas indices as floats, passed from SOF + float2 atlasIndex : TEXCOORD7; +}; + + +// Constant buffer format for per-object data for EveBoosterSet. This data is provided by the engine to the vertex shader stage. +struct EveBoosterSetDataVS +{ + // World matrix of the booster's owner ship + float4x4 WorldMat; + // Additional ship-data ( components: .x = boosterGain, .y = speed, .z = maxSize, .w = unused ) + float4 Shipdata; + // Trail spline data + float4 TrailsControlPositions[5]; + float4 TrailsControlNormals[5]; +}; + + +// Constant buffer format for per-object data for EveBoosterSet. This data is provided by the engine to the pixel shader stage. +struct EveBoosterSetDataPS +{ + // Additional ship-data ( components: .x = boosterGain, .y = trailIntensity, .z = warpStrength, .w = unused ) + float4 Shipdata; +}; + + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh b/shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh new file mode 100644 index 000000000..235bcd3dd --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh @@ -0,0 +1,54 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVECHILDBOOSTERSET_FXH +#define CARBON_EVECHILDBOOSTERSET_FXH + + +// Data passed from the engine to the vertex shader stage for EveChildBoosterSet draw calls. +struct EveChildBoosterSetVertexInput +{ + // Vertex position in local instance space + float3 position : POSITION; +}; + + +// Data passed from the engine to the vertex shader stage for EveChildBoosterSet draw calls. +struct EveChildBoosterSetInstanceData +{ + // 4x3 matrix that transforms the booster from local instance space to object space + float4x3 transform; + // Booster intensity + float intensity; + // Per booster instance random number from 0 to 1 used for offsetting booster animations + float wavePhase; + // Texture atlas indices, passed from SOF + uint atlasIndex0; + uint atlasIndex1; +}; + +StructuredBuffer ChildBoosterSetInstances ; + + +// Constant buffer format for per-object data for EveChildBoosterSet. This data is provided by the engine to the vertex shader stage. +struct EveChildBoosterSetDataVS +{ + // World matrix of the booster's owner ship + float4x4 WorldMat; + float _padding0; + float _padding1; + // Booster size at maximum intensity (used for scaling the booster in the shader) + float maxBoosterSize; + // Offset into the ChildBoosterSetInstances structured buffer for this booster set's instances + uint instanceOffset; +}; + + +// Constant buffer format for per-object data for EveChildBoosterSet. This data is provided by the engine to the pixel shader stage. +struct EveChildBoosterSetDataPS +{ + // Additional ship-data ( components: .x = unused, .y = unused, .z = warpStrength, .w = unused ) + float4 Shipdata; +}; + + +#endif \ No newline at end of file From 4716dfaaf8ef772d1a5561459f5823471b385d0d Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 5 Oct 2026 10:59:38 +0000 Subject: [PATCH 51/83] Decal header --- CMakeLists.txt | 1 + .../Carbon/SpaceScene/EveSpaceObjectDecal.fxh | 108 ++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 5806deb3b..2a1c7eb2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,6 +147,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh + shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh diff --git a/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh b/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh new file mode 100644 index 000000000..f856aa356 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh @@ -0,0 +1,108 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVESPACEOBJECTDECAL_FXH +#define CARBON_EVESPACEOBJECTDECAL_FXH + +#include "PerObjectData.fxh" +#include "../Math.fxh" + + +// Data passed from the engine to the vertex shader stage for EveSpaceObjectDecal draw calls. +struct EveSpaceObjectDecalDataVS +{ + // World transform of this decal's parent + float4x4 WorldMat; + // Inverse world transform of this decal's parent + float4x4 InvWorldMat; + // Decal projection to parent space (or to local bone) transform + float4x4 DecalMatrix; + // Inverse decal projection to parent space transform + float4x4 InvDecalMatrix; + // Transform from bone space to parent space + float4x4 ParentBoneMatrix; + // Inverse transform from parent space to bone space + float4x4 InvParentBoneMatrix; +}; + + +// Data passed from the engine to the pixel shader stage for EveSpaceObjectDecal draw calls. +struct EveSpaceObjectDecalDataPS +{ + // Parent ship's display data ( components: .x = killcounter, .yzw = unused ) + float4 DisplayData; + // Additional ship-data ( components: .x = boosterGain, .y = activation, .z = dirt, .w = boundingsphere radius ) + float4 Shipdata; + // Clip data for disolve fx ( components: .xyz = center, .w = signed size ) + float4 Clipdata1; + // Misc data ( components: .x = signed square of clip radius 2, .yzw = unused ) + float4 Miscdata; + // SH lighting coefficients + float4 ShLighting[7]; +}; + + + +EveSpaceObjectData CreateEveSpaceObjectData( EveSpaceObjectDecalDataVS perObjectData ) +{ + EveSpaceObjectData pod; + pod.WorldMat = perObjectData.WorldMat; + pod.WorldMatLast = (float4x4)0; + pod.BoneOffsets = (uint4)0; + + pod.Shipdata = (float4)0; + pod.Clipdata1 = (float4)0; + pod.Miscdata = (float4)0; + pod.EllipsoidRadii = (float4)0; + pod.EllipsoidCenter = (float4)0; + pod.CustomMaskMatrix[0] = IDENTITY_MATRIX; + pod.CustomMaskMatrix[1] = IDENTITY_MATRIX; + pod.CustomMaskData[0] = (float4)0; + pod.CustomMaskData[1] = (float4)0; + pod.CustomMaskMaterialIDs[0] = (float4)0; + pod.CustomMaskMaterialIDs[1] = (float4)0; + pod.CustomMaskTargets[0] = (float4)0; + pod.CustomMaskTargets[1] = (float4)0; + pod.CustomMaskClamps = (float4)0; + pod.CustomData = (float4)0; + // SH lighting coefficients + for( int i = 0; i < 7; ++i ) + { + pod.ShLighting[i] = 0; + } + return pod; +} + + +EveSpaceObjectData CreateEveSpaceObjectData( EveSpaceObjectDecalDataPS perObjectData ) +{ + EveSpaceObjectData pod; + pod.WorldMat = (float4x4)0; + pod.WorldMatLast = (float4x4)0; + pod.BoneOffsets = (uint4)0; + + pod.Shipdata = perObjectData.Shipdata; + pod.Clipdata1 = perObjectData.Clipdata1; + pod.Miscdata = perObjectData.Miscdata; + pod.EllipsoidRadii = (float4)0; + pod.EllipsoidCenter = (float4)0; + pod.CustomMaskMatrix[0] = IDENTITY_MATRIX; + pod.CustomMaskMatrix[1] = IDENTITY_MATRIX; + pod.CustomMaskData[0] = (float4)0; + pod.CustomMaskData[1] = (float4)0; + pod.CustomMaskMaterialIDs[0] = (float4)0; + pod.CustomMaskMaterialIDs[1] = (float4)0; + pod.CustomMaskTargets[0] = (float4)0; + pod.CustomMaskTargets[1] = (float4)0; + pod.CustomMaskClamps = (float4)0; + pod.CustomData = (float4)0; + // SH lighting coefficients + for( int i = 0; i < 7; ++i ) + { + pod.ShLighting[i] = perObjectData.ShLighting[i]; + } + return pod; +} + + + +#endif \ No newline at end of file From dddee0c4743fc352daaa553e76728aa505b980a9 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 5 Oct 2026 15:40:21 +0000 Subject: [PATCH 52/83] More shader includes --- CMakeLists.txt | 6 +++ shaders/include/Carbon/Intersections.fxh | 8 ++-- .../Carbon/SpaceScene/EveBannerSet.fxh | 22 ++++++++++ .../Carbon/SpaceScene/EveChildBulletStorm.fxh | 34 ++++++++++++++++ .../include/Carbon/SpaceScene/EveHazeSet.fxh | 28 +++++++++++++ .../include/Carbon/SpaceScene/EvePlaneSet.fxh | 32 +++++++++++++++ .../Carbon/SpaceScene/EveSpotlightSet.fxh | 40 +++++++++++++++++++ .../Carbon/SpaceScene/EveSpriteSet.fxh | 26 ++++++++++++ 8 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 shaders/include/Carbon/SpaceScene/EveBannerSet.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveHazeSet.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a1c7eb2c..8760175eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,9 +145,15 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/DepthMap.fxh shaders/include/Carbon/SpaceScene/DynamicLighting.fxh shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh + shaders/include/Carbon/SpaceScene/EveBannerSet.fxh shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh + shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh + shaders/include/Carbon/SpaceScene/EveHazeSet.fxh + shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh + shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh + shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh diff --git a/shaders/include/Carbon/Intersections.fxh b/shaders/include/Carbon/Intersections.fxh index 8b7c049dd..151d02196 100644 --- a/shaders/include/Carbon/Intersections.fxh +++ b/shaders/include/Carbon/Intersections.fxh @@ -44,8 +44,8 @@ float GetDistanceToPlane( Plane plane, Ray ray ) plane.normal = -plane.normal; } - const float FLT_EPSILON = 0.0000001; - if( d >= FLT_EPSILON ) + const float epsilon = 0.0000001; + if( d >= epsilon ) { float3 rayToPlanePoint = plane.planePoint - ray.origin; @@ -171,9 +171,9 @@ bool PointInCone( Ray ray, float t, Cone cone ) float3 pointInConeSpace = ray.origin + t * ray.dir - cone.tip; float cone_dist = dot( pointInConeSpace, cone.axis ); - const float FLT_EPSILON = 0.0000001; + const float epsilon = 0.0000001; - if( cone.tipOffset - cone_dist > 0 || cone_dist > cone.height + FLT_EPSILON ) + if( cone.tipOffset - cone_dist > 0 || cone_dist > cone.height + epsilon ) { return false; } diff --git a/shaders/include/Carbon/SpaceScene/EveBannerSet.fxh b/shaders/include/Carbon/SpaceScene/EveBannerSet.fxh new file mode 100644 index 000000000..7a7b1bd4f --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveBannerSet.fxh @@ -0,0 +1,22 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVEBANNERSET_FXH +#define CARBON_EVEBANNERSET_FXH + + +// Data passed from the engine to the vertex shader stage for EveBannerSet draw calls. +struct EveBannerSetVertexInput +{ + // Vertex position in local space + float3 position : POSITION; + // Vertex normal in local space + float3 normal : NORMAL; + // UV coordinates + float2 texCoord : TEXCOORD; + // W component contains bone index for skinning, XYZ components are unused + int4 indices : BLENDINDICES; +}; + +// EveBannerSet uses the same per-object data layout as other space objects. See PerObjectData.fxh + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh b/shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh new file mode 100644 index 000000000..dfccfa60a --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh @@ -0,0 +1,34 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVECHILDBULLETSTORM_FXH +#define CARBON_EVECHILDBULLETSTORM_FXH + + +// Data passed from the engine to the vertex shader stage for EveChildBulletStorm draw calls. +struct EveChildBulletStormVertexInput +{ + // Vertex index of the corner of the quad, from 0 to 3 + float cornerID : TEXCOORD0; + // Bullet position in object space + float3 positionOS : TEXCOORD1; + // Bullet direction in object space + float3 directionOS : TEXCOORD2; + // XYZ - three independent random values per bullet (from 0 to 1), W - part ID + float4 data : TEXCOORD3; +}; + + +// Data passed from the engine to the vertex shader stage for EveChildBulletStorm draw calls. +struct EveChildBulletStormDataVS +{ + // World transform matrix + float4x4 WorldMatrix; + // Target information: X - number of targets (for TargetPositionAndSize), Y - effect range, Z - clip sphere radius, W - bullet speed + float4 TargetPositionInfo; + // Up to 10 target positions and sizes (XYZ = position, W = size) + float4 TargetPositionAndSize[10]; +}; + + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveHazeSet.fxh b/shaders/include/Carbon/SpaceScene/EveHazeSet.fxh new file mode 100644 index 000000000..76136241a --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveHazeSet.fxh @@ -0,0 +1,28 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVEHAZESET_FXH +#define CARBON_EVEHAZESET_FXH + + +// Data passed from the engine to the vertex shader stage for EveHazeSet draw calls. +struct EveHazeSetVertexInput +{ + // 3x4 matrix that transforms the haze from local instance space to object space + float4 transform1 : TEXCOORD0; + float4 transform2 : TEXCOORD1; + float4 transform3 : TEXCOORD2; + // 3x4 matrix that transforms the haze from object space to local instance space + float4 invTransform1 : TEXCOORD3; + float4 invTransform2 : TEXCOORD4; + float4 invTransform3 : TEXCOORD5; + // X - haze falloff, Y - source size, Z - source brightness, W - saturation + float4 hazeData : TEXCOORD6; + // Color of the haze + float4 color : COLOR; + // X - vertex index (0-7), Y - skeleton bone index if the haze is attached to the bone + uint4 index : TEXCOORD7; +}; + +// EveHazeSet uses the same per-object data layout as other space objects. See PerObjectData.fxh + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh b/shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh new file mode 100644 index 000000000..d99d75cfe --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh @@ -0,0 +1,32 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVEPLANESET_FXH +#define CARBON_EVEPLANESET_FXH + + +// Data passed from the engine to the vertex shader stage for EvePlaneSet draw calls. +struct EvePlaneSetVertexInput +{ + // 3x4 matrix that transforms the plane from local instance space to world space + float4 transform1 : TEXCOORD0; + float4 transform2 : TEXCOORD1; + float4 transform3 : TEXCOORD2; + // Color of the plane + float4 color : COLOR; + // UV layer 1 transform and scroll data (XY - scale, ZW - offset) + float4 layer1Transform : TEXCOORD3; + // UV layer 2 transform and scroll data (XY - scale, ZW - offset) + float4 layer2Transform : TEXCOORD4; + // UV layer 1 scroll data (XY - scroll speed, ZW - scroll offset) + float4 layer1Scroll : TEXCOORD5; + // UV layer 2 scroll data (XY - scroll speed, ZW - scroll offset) + float4 layer2Scroll : TEXCOORD6; + // Z - texture atlas index + uint4 index : TEXCOORD7; + // Plane blink data coming from SOF (X - blink rate, Y - blink phase, Z - duty cycle, W - blink mode) + float4 blinkData : TEXCOORD8; +}; + +// EvePlaneSet uses the quad renderer for rendering sprites, so shaders do not have access to per-object data. + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh b/shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh new file mode 100644 index 000000000..a371df02d --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh @@ -0,0 +1,40 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVESPOTLIGHTSET_FXH +#define CARBON_EVESPOTLIGHTSET_FXH + +// Data passed from the engine to the vertex shader stage for EveSpotlightSet cone geometry draw calls. +struct EveSpotlightSetConeVertexInput +{ + // Spotlight color and activation state (w - ship activation) + float4 color : COLOR0; + // 3x4 matrix that transforms the spotlight from local instance space to world space + float4 transform1 : TEXCOORD0; + float4 transform2 : TEXCOORD1; + float4 transform3 : TEXCOORD2; + // X - booster gain, Y - unused + float2 boosterGain : TEXCOORD3; + // Vertex index of the spotlight cone (0-3) + float index : TEXCOORD4; +}; + + +// Data passed from the engine to the vertex shader stage for EveSpotlightSet glow sprite draw calls. +struct EveSpotlightSetGlowVertexInput +{ + // 3x4 matrix that transforms the spotlight from local instance space to world space + float4 transform1 : TEXCOORD0; + float4 transform2 : TEXCOORD1; + float4 transform3 : TEXCOORD2; + // Spotlight sprite color and activation state (w - ship activation) + float4 spriteColor : COLOR0; + // Spotlight flare color (w - unused) + float4 flareColor : COLOR1; + // Sprite scale (XYZ) and boosterGain influence (W) + float4 scale : TEXCOORD3; + // Vertex index of the spotlight cone (0-3) + float index : TEXCOORD4; +}; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh b/shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh new file mode 100644 index 000000000..c5f7147ab --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh @@ -0,0 +1,26 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVESPRITESET_FXH +#define CARBON_EVESPRITESET_FXH + +// Data passed from the engine to the vertex shader stage for EveSpriteSet draw calls. +struct EveSpriteSetVertexInput +{ + // Sprite center position in world space + float3 position : POSITION; + // Sprite color + float4 color : COLOR; + // X - owner ship's activation strength, Y - sprite blink phase, Z - sprite blink rate, W - sprite minimum size + float4 texcoord0 : TEXCOORD0; + // X - sprite maximum size, Y - sprite falloff, Z, W - unused + float2 texcoord1 : TEXCOORD1; + // Warp mode color + float4 warpColor : COLOR1; + // Vertex index for sprite quad (0-3) + float index : TEXCOORD5; +}; + +// EveSpriteSet uses the quad renderer for rendering sprites, so shaders do not have access to per-object data. + + +#endif \ No newline at end of file From 8a231fce59579d19cb36a558fbe0fed1128df62a Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Tue, 6 Oct 2026 10:37:08 +0000 Subject: [PATCH 53/83] Lensflare shaders --- CMakeLists.txt | 3 + .../Lensflares/OccluderManagement.fx | 58 +++++++++++++++++++ .../Carbon/SpaceScene/EveLensflare.fxh | 35 +++++++++++ .../include/Carbon/SpaceScene/EveOccluder.fxh | 44 ++++++++++++++ 4 files changed, 140 insertions(+) create mode 100644 shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx create mode 100644 shaders/include/Carbon/SpaceScene/EveLensflare.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveOccluder.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 8760175eb..fd96bf7e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,8 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh shaders/include/Carbon/SpaceScene/EveHazeSet.fxh + shaders/include/Carbon/SpaceScene/EveLensflare.fxh + shaders/include/Carbon/SpaceScene/EveOccluder.fxh shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh @@ -164,6 +166,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/PackedTangents.fxh shaders/include/Carbon/ParticleAnnotations.fxh shaders/include/Carbon/System.fxh + shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx b/shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx new file mode 100644 index 000000000..d0f90aecf --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx @@ -0,0 +1,58 @@ +float OcclusionBufferOffset ; +RWBuffer FlareOcclusionBuffer ; + +groupshared float occlusions[4]; + +[numthreads( 4, 1, 1 )] +void CopyCountersCS( uint3 groupIdx : SV_GroupID, uint3 threadIdx : SV_GroupThreadID ) +{ + uint flareOffset = groupIdx.x * 13; + uint occluderOffset = flareOffset + 5 + threadIdx.x * 2; + uint persistedOffset = flareOffset + 1 + threadIdx.x; + + uint total = FlareOcclusionBuffer[occluderOffset]; + if( total > 0 ) + { + uint unoccluded = FlareOcclusionBuffer[occluderOffset + 1]; + + float occlusion = float( unoccluded ) / float( total ) / 100.0; + FlareOcclusionBuffer[persistedOffset] = asuint( occlusion ); + + FlareOcclusionBuffer[occluderOffset] = 0; + FlareOcclusionBuffer[occluderOffset + 1] = 0; + occlusions[threadIdx.x] = occlusion; + } + else + { + occlusions[threadIdx.x] = asfloat( FlareOcclusionBuffer[persistedOffset] ); + } + + GroupMemoryBarrierWithGroupSync(); + + if( threadIdx.x == 0 ) + { + FlareOcclusionBuffer[flareOffset] = asuint( occlusions[0] * occlusions[1] * occlusions[2] * occlusions[3] ); + } +} + +[numthreads( 13, 1, 1 )] +void ClearCS( uint3 threadIdx : SV_GroupThreadID ) +{ + FlareOcclusionBuffer[asuint( OcclusionBufferOffset ) + threadIdx.x] = threadIdx.x < 5 ? asuint( 1.0 ) : 0; +} + +technique CopyCounters +{ + pass P0 + { + ComputeShader = compile cs_5_0 CopyCountersCS(); + } +} + +technique Clear +{ + pass P0 + { + ComputeShader = compile cs_5_0 ClearCS(); + } +} diff --git a/shaders/include/Carbon/SpaceScene/EveLensflare.fxh b/shaders/include/Carbon/SpaceScene/EveLensflare.fxh new file mode 100644 index 000000000..604b65dcb --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveLensflare.fxh @@ -0,0 +1,35 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVELENSFLARE_FXH +#define CARBON_EVELENSFLARE_FXH + + +struct EveLensflarePerObjectData +{ + // Direction towards the lens flare that owns the occluder; W - flare size scale + float4 LensflareFxDirectionScale; + // Offset into the occlusion buffer where the occlusion results for this lens flar are stored. + // X - foreground occlusion results, Y - background (planets, etc.) occlusion results, Z, W - unused + uint4 OcclusionIndices; +}; + +// The buffer containing occlusion results of occlusion queries for lens flares. Read values need to be cast to float using asfloat() to get the occlusion ratio in the range [0, 1]. +Buffer FlareOcclusionBuffer ; + +float GetLensFlareOcclusion( uint index ) +{ + return asfloat( FlareOcclusionBuffer[index] ); +} + +// Direction towards the lens flare that owns the occluder; W - flare size scale +// Can be used for querying lens flare position for shaders outside the lens flare system. +float4 LensflareFxDirectionScale ; + +// Stores offsets into the occlusion buffer where the occlusion results for a lens flare are stored. +// X - offset into the occlusion buffer for foreground occlusion results (cast to uint with asuint()) +// Y - offset into the occlusion buffer for background occlusion results (cast to uint with asuint()) +// Z, W - unused +float4 LensflareFxOccScale ; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveOccluder.fxh b/shaders/include/Carbon/SpaceScene/EveOccluder.fxh new file mode 100644 index 000000000..da7670992 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveOccluder.fxh @@ -0,0 +1,44 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVEOCCLUDER_FXH +#define CARBON_EVEOCCLUDER_FXH + +#include "DepthMap.fxh" +#include "Volumetrics.fxh" + +// Offset into the occlusion buffer where the occlusion results for this occluder are stored. +// Even though the variable is declared as a float, it is used as an integer value in the shader code (use asuint). +float OcclusionBufferOffset ; +// Scaling factor for fog occlusion to apply to the resulting occlusion value. +float OcclusionFogWeight ; +// Direction towards the lens flare that owns the occluder; W - flare size scale +float4 LensflareFxDirectionScale ; + + +// Destination buffer for writing occlusion results. Each occluder occupies two consecutive uint values in the buffer. +// The first value is the total occluder's shaded pixel count, and the second value is the unoccluded pixel count. +RWBuffer FlareOcclusionBuffer ; + +SamplerState _EveOccluderDepthMapSampler +{ + MinFilter = Point; + MagFilter = Point; + MipFilter = None; + AddressU = Mirror; + AddressV = Mirror; +}; + +// Records occlusion for a pixel with normalized screen space coordinates. +void EveOccluderRecordOcclusion( float2 pos ) +{ + uint bufferOffset = asuint( OcclusionBufferOffset ); + float depth = DepthMap.SampleLevel( _EveOccluderDepthMapSampler, pos, 0.0 ).r; + if( depth == 0 ) + { + float4 fog = EveSceneFogVolumeMap.SampleLevel( EveSceneFogVolumeMapSampler, float3( pos, 3 ), 0 ); + InterlockedAdd( FlareOcclusionBuffer[1 + bufferOffset], uint( 100 * ( 1 - min( fog.a * OcclusionFogWeight, 0.95 ) ) ) ); + } + InterlockedAdd( FlareOcclusionBuffer[bufferOffset], 1 ); +} + +#endif \ No newline at end of file From 27bc24830ce082176f3f6dcda37559102739525f Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Tue, 6 Oct 2026 14:27:48 +0000 Subject: [PATCH 54/83] More shaders --- CMakeLists.txt | 2 ++ .../Carbon/SpaceScene/EveTransform.fxh | 19 +++++++++++ shaders/include/Carbon/Tr2CurveLineSet.fxh | 33 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/EveTransform.fxh create mode 100644 shaders/include/Carbon/Tr2CurveLineSet.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index fd96bf7e6..f67550182 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,6 +156,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh + shaders/include/Carbon/SpaceScene/EveTransform.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh @@ -166,6 +167,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/PackedTangents.fxh shaders/include/Carbon/ParticleAnnotations.fxh shaders/include/Carbon/System.fxh + shaders/include/Carbon/Tr2CurveLineSet.fxh shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx ) diff --git a/shaders/include/Carbon/SpaceScene/EveTransform.fxh b/shaders/include/Carbon/SpaceScene/EveTransform.fxh new file mode 100644 index 000000000..915ea3435 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveTransform.fxh @@ -0,0 +1,19 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVETRANSFORM_FXH +#define CARBON_EVETRANSFORM_FXH + + +// Data passed from the engine to the vertex shader stage for EveTransform draw calls. +struct EveTransformDataVS +{ + // World transform of this object + float4x4 WorldMat; + // World transform of this object in the previous frame + float4x4 WorldMatLast; + // Inverse world transform of this object + float4x4 InvWorldMat; +}; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/Tr2CurveLineSet.fxh b/shaders/include/Carbon/Tr2CurveLineSet.fxh new file mode 100644 index 000000000..b1b0793e2 --- /dev/null +++ b/shaders/include/Carbon/Tr2CurveLineSet.fxh @@ -0,0 +1,33 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_TR2CURVELINESET_FXH +#define CARBON_TR2CURVELINESET_FXH + +// Data passed from the engine to the vertex shader stage for Tr2CurveLineSet draw calls. +struct Tr2CurveLineSetVertexInput +{ + // Vertex position in local space + float3 position : POSITION; + // XYZ - offset to next/previous line segment, W - width (incl. -1.f to indicate direction) + float4 lineDir : TEXCOORD0; + // X - 0 or 1 for begin/end, Y - uniform scalar from 0 to 1 across length of line segment, Z - override color border, W - length of vert in uniform scalar + float4 beginEnd : TEXCOORD1; + // X - animation speed, Y - animation scale, Z - lineID + float3 animationData : TEXCOORD2; + // Offset to one after next/previous line segment + float3 nextLineDir : TEXCOORD3; + // Line color + float4 color : COLOR0; + // Override color + float4 overrideColor : COLOR1; + // Overlay color + float4 overlayColor : COLOR2; +}; + +// Data passed from the engine to any shader stage for Tr2CurveLineSet draw calls. +struct Tr2CurveLineSetData +{ + float4x4 WorldMat; +}; + +#endif \ No newline at end of file From ae9484d94d819d8be231e9ce8f5edfd63b04c0c3 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Wed, 7 Oct 2026 08:45:57 +0000 Subject: [PATCH 55/83] GPU particle shaders --- CMakeLists.txt | 10 + .../Space/SpecialFX/Particles/Gpu/Clear.fx | 64 +++++ .../Space/SpecialFX/Particles/Gpu/Emit.fx | 137 +++++++++++ .../Particles/Gpu/SetDrawParameters.fx | 24 ++ .../SpecialFX/Particles/Gpu/SetSortArgs.fx | 24 ++ .../Space/SpecialFX/Particles/Gpu/Sort.fx | 94 ++++++++ .../SpecialFX/Particles/Gpu/SortInner.fx | 90 ++++++++ .../Space/SpecialFX/Particles/Gpu/SortStep.fx | 52 +++++ .../Space/SpecialFX/Particles/Gpu/Update.fx | 218 ++++++++++++++++++ shaders/include/Carbon/Math.fxh | 28 +++ shaders/include/Carbon/RandomXOrShift.fxh | 38 +++ .../Carbon/SpaceScene/GpuParticles.fxh | 86 +++++++ 12 files changed, 865 insertions(+) create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx create mode 100644 shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx create mode 100644 shaders/include/Carbon/RandomXOrShift.fxh create mode 100644 shaders/include/Carbon/SpaceScene/GpuParticles.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index f67550182..7263138ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,6 +157,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh shaders/include/Carbon/SpaceScene/EveTransform.fxh + shaders/include/Carbon/SpaceScene/GpuParticles.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh @@ -166,8 +167,17 @@ set(_SHADER_SOURCES shaders/include/Carbon/Math.fxh shaders/include/Carbon/PackedTangents.fxh shaders/include/Carbon/ParticleAnnotations.fxh + shaders/include/Carbon/RandomXOrShift.fxh shaders/include/Carbon/System.fxh shaders/include/Carbon/Tr2CurveLineSet.fxh + shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx + shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx ) diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx new file mode 100644 index 000000000..18524e524 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx @@ -0,0 +1,64 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/SpaceScene/GpuParticles.fxh" + +struct PerObjectVSData +{ + uint bufferSize; +} PerObjectVS; + +RWStructuredBuffer DeadBuffer; +RWBuffer ParticleCounters; +RWStructuredBuffer ParticleBuffer; + + +[numthreads( 1, 1, 1 )] +void ClearCounter() +{ + ParticleCounters[0] = 0; +} + +#define POPULATE_DEAD_DIM 16 + +[numthreads( POPULATE_DEAD_DIM, POPULATE_DEAD_DIM, 1 )] +void PopulateDead( uint groupIndex : SV_GroupIndex ) +{ + uint iterations = PerObjectVS.bufferSize / POPULATE_DEAD_DIM / POPULATE_DEAD_DIM; + for( uint i = 0; i < iterations; ++i ) + { + GpuParticleData particle = (GpuParticleData)0; + particle.age = -1; + ParticleBuffer[groupIndex + POPULATE_DEAD_DIM * POPULATE_DEAD_DIM * i] = particle; + int index; + InterlockedAdd( ParticleCounters[0], 1, index ); + DeadBuffer[index] = groupIndex + POPULATE_DEAD_DIM * POPULATE_DEAD_DIM * i; + } + + GroupMemoryBarrierWithGroupSync(); + + if( groupIndex == 0 ) + { + for( uint i = iterations * POPULATE_DEAD_DIM * POPULATE_DEAD_DIM; i < PerObjectVS.bufferSize; ++i ) + { + GpuParticleData particle = (GpuParticleData)0; + particle.age = -1; + ParticleBuffer[i] = particle; + int index; + InterlockedAdd( ParticleCounters[0], 1, index ); + DeadBuffer[index] = i; + } + } +} + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 ClearCounter(); + } + pass p1 + { + ComputeShader = compile cs_5_0 PopulateDead(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx new file mode 100644 index 000000000..d7c94669d --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx @@ -0,0 +1,137 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/System.fxh" +#include "../../../../../include/Carbon/Math.fxh" +#include "../../../../../include/Carbon/RandomXOrShift.fxh" +#include "../../../../../include/Carbon/SpaceScene/GpuParticles.fxh" + + +float3 GetRandomDirection( float3 direction, float angle, float innerAngle, float3 rands ) +{ + if( angle >= PI / 2 ) + { + angle = PI; + } + float3 dir = normalize( direction ); + + float phi = lerp( innerAngle, angle, rands.x ); + float theta = rands.y * 4 * PI; + + float4 q = QuaternionRotationYawPitchRoll( 0, phi, theta ); + float4 qp = float4( -q.xyz, q.w ); + float4 v = float4( 0, 0, 1, 0 ); + v = QuaternionMultiply( QuaternionMultiply( q, v ), qp ); + + float3 x = abs( dir.x ) > abs( dir.y ) ? float3( 0, 1, 0 ) : float3( 1, 0, 0 ); + float3 y = normalize( cross( dir, x ) ); + x = cross( dir, y ); + + return dir * v.z + x * v.x + y * v.y; +} + + +#define GROUP_X 16 +#define GROUP_Y 16 + +struct EmitterData +{ + float3 position; + uint count; + + float3 positionPrevious; + float radius; + + float3 direction; + float angle; + + float3 directionPrevious; + uint emitterSeed; // LO: emitter, HI: seed + + float3 velocity; + float minSpeed; + + float3 velocityPrevious; + float maxSpeed; + + float innerAngle; + float3 unused; +}; + +struct PerObjectVSData +{ + uint count; + uint3 padding; + // should be EmitterData data[(PLATFORM_MAX_CONSTANT_BUFFER_SIZE - 16)/sizeof(EmitterData)], but ShaderCompiler can't handle that +#if PLATFORM_MAX_CONSTANT_BUFFER_SIZE == 4096 + EmitterData data[36]; +#elif PLATFORM_MAX_CONSTANT_BUFFER_SIZE == 65536 + EmitterData data[585]; +#else +#error "Need to define proper length for the emitter CB" +#endif + +} PerObjectVS; + +RWStructuredBuffer ParticleBuffer; +RWBuffer ParticleCounters; +RWStructuredBuffer DeadBuffer; + +groupshared EmitterData g_emitter; + +[numthreads( GROUP_X, GROUP_Y, 1 )] +void Emit( uint3 grid : SV_GroupID, uint groupIndex : SV_GroupIndex, uint3 threadID : SV_GroupThreadID ) +{ + if( groupIndex == 0 ) + { + uint emitIndex = grid.x; + g_emitter = PerObjectVS.data[emitIndex]; + } + + GroupMemoryBarrierWithGroupSync(); + + uint rng_state = RandInit( groupIndex + ( g_emitter.emitterSeed >> 16 ) ); + + uint start = threadID.x + threadID.y * GROUP_X; + for( uint i = start; i < g_emitter.count; i += GROUP_X * GROUP_Y ) + { + int deadIndex; + InterlockedAdd( ParticleCounters[0], -1, deadIndex ); + --deadIndex; + + if( deadIndex >= 0 ) + { + float birthTime = RandFloat( rng_state ); + float3 velocityDirection = GetRandomDirection( + normalize( lerp( g_emitter.directionPrevious, g_emitter.direction, birthTime ) ), + g_emitter.angle, + g_emitter.innerAngle, + float3( RandFloat( rng_state ), RandFloat( rng_state ), RandFloat( rng_state ) ) ); + + uint index = DeadBuffer[deadIndex]; + GpuParticleData particle; + particle.position = lerp( g_emitter.positionPrevious, g_emitter.position, birthTime ); + particle.position += velocityDirection * g_emitter.radius; + particle.velocity = velocityDirection * + lerp( g_emitter.minSpeed, g_emitter.maxSpeed, RandFloat( rng_state ) ) + lerp( g_emitter.velocityPrevious, g_emitter.velocity, birthTime ); + particle.age = 0; + particle.emitterSeed = ( g_emitter.emitterSeed & 0xffff ) | ( Rand( rng_state ) << 16 ); + + + ParticleBuffer[index] = particle; + } + else + { + break; + } + } +} + + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 Emit(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx new file mode 100644 index 000000000..6807ffdd1 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx @@ -0,0 +1,24 @@ +// Copyright © 2026 CCP ehf. + + +RWBuffer DrawParameters; +Buffer ParticleCounters; + +[numthreads( 1, 1, 1 )] +void SetParameters() +{ + uint count = ParticleCounters[1]; + DrawParameters[0] = count * 6; + DrawParameters[1] = 1; + DrawParameters[2] = 0; + DrawParameters[3] = 0; +} + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 SetParameters(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx new file mode 100644 index 000000000..29a8e019d --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx @@ -0,0 +1,24 @@ +// Copyright © 2026 CCP ehf. + + +RWBuffer SortParameters; +Buffer ParticleCounters; + +[numthreads( 1, 1, 1 )] +void SetParameters() +{ + uint count = ParticleCounters[1]; + SortParameters[0] = ( ( max( count, (uint)1 ) - 1 ) >> 9 ) + 1; + SortParameters[1] = 1; + SortParameters[2] = 1; + SortParameters[3] = count; +} + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 SetParameters(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx new file mode 100644 index 000000000..f5b9001a3 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx @@ -0,0 +1,94 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/SpaceScene/GpuParticles.fxh" + +// Code based on https://github.com/GPUOpen-LibrariesAndSDKs/GPUParticles11 + +#define SORT_SIZE 512 + +#define HALF_SIZE 256 // (SORT_SIZE/2) +#define ITERATIONS 1 // (HALF_SIZE > 1024 ? HALF_SIZE/1024 : 1) +#define NUM_THREADS 256 // (HALF_SIZE/ITERATIONS) +#define INVERSION (16*2 + 8*3) + + +RWStructuredBuffer VisibleBuffer; +Buffer SortParameters; + + +groupshared GpuParticleVisibleData g_LDS[SORT_SIZE]; + + +[numthreads( NUM_THREADS, 1, 1 )] +void BitonicSortLDS( uint3 Gid : SV_GroupID, + uint3 DTid : SV_DispatchThreadID, + uint3 GTid : SV_GroupThreadID, + uint GI : SV_GroupIndex ) +{ + int GlobalBaseIndex = ( Gid.x * SORT_SIZE ) + GTid.x; + int LocalBaseIndex = GI; + + int g_NumElements = int( SortParameters[3] ); + if( g_NumElements == 0 ) + { + return; + } + + uint numElementsInThreadGroup = max( 0, min( SORT_SIZE, g_NumElements - int( Gid.x * SORT_SIZE ) ) ); + + // Load shared data + int i; + [unroll] + for( i = 0; i < 2 * ITERATIONS; ++i ) + { + if( GI + i * NUM_THREADS < numElementsInThreadGroup ) + g_LDS[LocalBaseIndex + i * NUM_THREADS] = VisibleBuffer[GlobalBaseIndex + i * NUM_THREADS]; + } + GroupMemoryBarrierWithGroupSync(); + + // Bitonic sort + for( uint nMergeSize = 2; nMergeSize <= SORT_SIZE; nMergeSize = nMergeSize * 2 ) + { + for( int nMergeSubSize = nMergeSize >> 1; nMergeSubSize > 0; nMergeSubSize = nMergeSubSize >> 1 ) + { + [unroll] + for( i = 0; i < ITERATIONS; ++i ) + { + int tmp_index = GI + NUM_THREADS * i; + int index_low = tmp_index & ( nMergeSubSize - 1 ); + int index_high = 2 * ( tmp_index - index_low ); + int index = index_high + index_low; + + uint nSwapElem = uint( nMergeSubSize ) == nMergeSize >> 1 ? index_high + ( 2 * nMergeSubSize - 1 ) - index_low : index_high + nMergeSubSize + index_low; + if( nSwapElem < numElementsInThreadGroup ) + { + GpuParticleVisibleData a = g_LDS[index]; + GpuParticleVisibleData b = g_LDS[nSwapElem]; + + if( a.depth > b.depth ) + { + g_LDS[index] = b; + g_LDS[nSwapElem] = a; + } + } + GroupMemoryBarrierWithGroupSync(); + } + } + } + + // Store shared data + [unroll] + for( i = 0; i < 2 * ITERATIONS; ++i ) + { + if( GI + i * NUM_THREADS < numElementsInThreadGroup ) + VisibleBuffer[GlobalBaseIndex + i * NUM_THREADS] = g_LDS[LocalBaseIndex + i * NUM_THREADS]; + } +} + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 BitonicSortLDS(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx new file mode 100644 index 000000000..8b13149a0 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx @@ -0,0 +1,90 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/SpaceScene/GpuParticles.fxh" + +// Code based on https://github.com/GPUOpen-LibrariesAndSDKs/GPUParticles11 + +#define SORT_SIZE 512 + +#define NUM_THREADS 256 // (SORT_SIZE/2) +#define INVERSION (16*2 + 8*3) + +RWStructuredBuffer VisibleBuffer; +Buffer SortParameters; + +groupshared GpuParticleVisibleData g_LDS[SORT_SIZE]; + + +[numthreads( NUM_THREADS, 1, 1 )] +void BitonicInnerSort( + uint3 Gid : SV_GroupID, + uint3 DTid : SV_DispatchThreadID, + uint3 GTid : SV_GroupThreadID, + uint GI : SV_GroupIndex ) +{ + int4 tgp; + + tgp.x = Gid.x * 256; + tgp.y = 0; + tgp.z = SortParameters[3]; + tgp.w = min( 512, max( 0, tgp.z - int( Gid.x * 512 ) ) ); + + int GlobalBaseIndex = tgp.y + tgp.x * 2 + GTid.x; + int LocalBaseIndex = GI; + int i; + + // Load shared data + if( GlobalBaseIndex < tgp.z ) + { + [unroll] + for( i = 0; i < 2; ++i ) + { + if( (int)GI + i * NUM_THREADS < tgp.w ) + g_LDS[LocalBaseIndex + i * NUM_THREADS] = VisibleBuffer[GlobalBaseIndex + i * NUM_THREADS]; + } + } + GroupMemoryBarrierWithGroupSync(); + + // sort threadgroup shared memory + for( int nMergeSubSize = SORT_SIZE >> 1; nMergeSubSize > 0; nMergeSubSize = nMergeSubSize >> 1 ) + { + int tmp_index = GI; + int index_low = tmp_index & ( nMergeSubSize - 1 ); + int index_high = 2 * ( tmp_index - index_low ); + int index = index_high + index_low; + + uint nSwapElem = index_high + nMergeSubSize + index_low; + + if( (int)nSwapElem < tgp.w ) + { + GpuParticleVisibleData a = g_LDS[index]; + GpuParticleVisibleData b = g_LDS[nSwapElem]; + + if( a.depth > b.depth ) + { + g_LDS[index] = b; + g_LDS[nSwapElem] = a; + } + } + GroupMemoryBarrierWithGroupSync(); + } + + // Store shared data + if( GlobalBaseIndex < tgp.z ) + { + [unroll] + for( i = 0; i < 2; ++i ) + { + if( (int)GI + i * NUM_THREADS < tgp.w ) + VisibleBuffer[GlobalBaseIndex + i * NUM_THREADS] = g_LDS[LocalBaseIndex + i * NUM_THREADS]; + } + } +} + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 BitonicInnerSort(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx new file mode 100644 index 000000000..d6aa03839 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx @@ -0,0 +1,52 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/SpaceScene/GpuParticles.fxh" + +// Code based on https://github.com/GPUOpen-LibrariesAndSDKs/GPUParticles11 + +RWStructuredBuffer VisibleBuffer; +Buffer SortParameters; + +struct PerObjectVSData +{ + int4 JobParams; +} PerObjectVS; + +[numthreads( 256, 1, 1 )] +void BitonicSortStep( uint3 Gid : SV_GroupID, uint3 GTid : SV_GroupThreadID ) +{ + int4 tgp; + + tgp.x = Gid.x * 256; + tgp.y = 0; + tgp.z = SortParameters[3]; + tgp.w = min( 512, max( 0, tgp.z - (int)Gid.x * 512 ) ); + + uint localID = tgp.x + GTid.x; // calculate threadID within this sortable-array + + uint index_low = localID & ( PerObjectVS.JobParams.x - 1 ); + uint index_high = 2 * ( localID - index_low ); + + uint index = tgp.y + index_high + index_low; + uint nSwapElem = tgp.y + index_high + PerObjectVS.JobParams.y + PerObjectVS.JobParams.z * index_low; + + if( nSwapElem < uint( tgp.y + tgp.z ) ) + { + GpuParticleVisibleData a = VisibleBuffer[index]; + GpuParticleVisibleData b = VisibleBuffer[nSwapElem]; + + if( a.depth > b.depth ) + { + VisibleBuffer[index] = b; + VisibleBuffer[nSwapElem] = a; + } + } +} + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 BitonicSortStep(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx new file mode 100644 index 000000000..5ade62772 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx @@ -0,0 +1,218 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/Math.fxh" +#include "../../../../../include/Carbon/SpaceScene/GpuParticles.fxh" +#include "../../../../../include/Carbon/SpaceScene/PerSceneData.fxh" + + +#define GROUP_X 16 +#define GROUP_Y 16 + + +Texture3D NoiseMap +< + bool SasUiVisible = true; +>; + +SamplerState NoiseMapSampler +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Wrap; + AddressV = Wrap; + AddressW = Wrap; +}; + +float3 GetTurbulence( float3 position, float frequency, float3 offset, float3 animation ) +{ + position += offset; + position *= frequency; + position += NoiseMap.SampleLevel( NoiseMapSampler, animation / 32, 0.0 ).xyz; + float3 result = 0; + float amplitude = 1; + + [unroll] + for( int i = 0; i < 3; ++i ) + { + result += ( NoiseMap.SampleLevel( NoiseMapSampler, position, 0.0 ).xyz - 0.5 ) * amplitude; + amplitude *= 0.5; + position = 2.0 * position.zyx; + } + return result; +} + +bool UpdateParticle( inout GpuParticleData particle, GpuParticleEmitterParams emitter, float dt, float seedf, float3 originShift, float3 turbulenceOffset, float3 turbulenceAnimation ) +{ + if( particle.age >= 0 ) + { + particle.age += dt; + + if( particle.age >= lerp( emitter.minLifeTime, emitter.maxLifeTime, seedf ) ) + { + particle.age = -1; + return false; + } + else + { + // forces + particle.velocity += float3( 0, emitter.gravity * dt, 0 ); + particle.velocity += GetTurbulence( particle.position, emitter.turbulenceFrequency, turbulenceOffset, turbulenceAnimation ) * emitter.turbulenceAmplitude * dt; + if( emitter.attractor.w != 0 ) + { + float3 dir = normalize( emitter.attractor.xyz - particle.position ); + particle.velocity += dir * emitter.attractor.w * dt; + } + if( emitter.drag < 0 ) + { + float speed = length( particle.velocity ); + if( speed > 0 ) + { + particle.velocity += particle.velocity * speed * emitter.drag * dt; + } + } + else + { + particle.velocity -= particle.velocity * emitter.drag * dt; + } + + particle.position += particle.velocity * dt + originShift; + if( any( isnan( particle.position ) ) ) + { + return false; + } + return true; + } + } + else + { + return false; + } +} + + +struct PerObjectVSData +{ + uint groupCountX; + uint groupCountY; + uint groupCountZ; + float deltaTime; + + float3 originShift; + uint bufferSize; + float4 turbulenceOffset; + float4 turbulenceAnimation; + + float4 frustumPlanes[6]; +} PerObjectVS; + +RWStructuredBuffer ParticleBuffer; +RWStructuredBuffer DeadBuffer; +RWBuffer ParticleCounters; +RWStructuredBuffer VisibleBuffer; +StructuredBuffer Emitters; + +EveSpaceSceneDataVS PerFrameVS : register( PERFRAME_VS_STARTREGISTER ); + +bool SphereInFrustum( float4 xyzr, float4 frustumPlane[6] ) +{ + [unroll] + for( uint i = 0; i != 6; ++i ) + { + if( dot( float4( xyzr.xyz, 1 ), -frustumPlane[i] ) > xyzr.w ) + { + return false; + } + } + return true; +} + +[numthreads( GROUP_X, GROUP_Y, 1 )] +void Update( uint3 grid : SV_GroupID, uint groupIndex : SV_GroupIndex ) +{ + uint offset = ( grid.x + grid.y * PerObjectVS.groupCountX + grid.z * PerObjectVS.groupCountX * PerObjectVS.groupCountY ) * GROUP_X * GROUP_Y + groupIndex; + float3 eye = ExtractEyePosFromViewMatrix( PerFrameVS.ViewInverseTransposeMat ); + float3 dir = normalize( ExtractEyeDirFromViewMatrix( PerFrameVS.ViewMat ) ); + float widthProjection = PerFrameVS.ProjectionMat[0][0] * PerFrameVS.TargetResolution.x; + + uint bufferSize = PerObjectVS.bufferSize; + + for( uint i = offset; i < bufferSize; i += GROUP_X * GROUP_Y * PerObjectVS.groupCountX * PerObjectVS.groupCountY * PerObjectVS.groupCountZ ) + { + GpuParticleData particle = ParticleBuffer[i]; + GpuParticleEmitterParams emitter = Emitters[particle.emitterSeed & 0xffff]; + uint seed = particle.emitterSeed >> 16; + float seedf = float( seed ) / float( 0xffff ); + + if( particle.age >= 0 ) + { + if( UpdateParticle( particle, emitter, PerObjectVS.deltaTime, seedf, PerObjectVS.originShift.xyz, PerObjectVS.turbulenceOffset.xyz, PerObjectVS.turbulenceAnimation.xyz ) ) + { + float maxSize = max( emitter.sizes.x, max( emitter.sizes.y, emitter.sizes.z ) ) * ( 1 + abs( emitter.sizeVariance ) ); + float4 frustumPlanes[6] = + { + PerObjectVS.frustumPlanes[0], + PerObjectVS.frustumPlanes[1], + PerObjectVS.frustumPlanes[2], + PerObjectVS.frustumPlanes[3], + PerObjectVS.frustumPlanes[4], + PerObjectVS.frustumPlanes[5] + }; + if( SphereInFrustum( float4( particle.position, maxSize ), frustumPlanes ) ) + { + float depth = -dot( dir, particle.position - eye ); + float screenSize = maxSize / max( 1.0, depth ) * widthProjection; + if( screenSize > 2 ) + { + int index; + InterlockedAdd( ParticleCounters[1], 1, index ); + + GpuParticleVisibleData ad; + ad.index = i; + ad.depth = -depth; + VisibleBuffer[index] = ad; + } + } + } + else + { + int index; + InterlockedAdd( ParticleCounters[0], 1, index ); + + DeadBuffer[index] = i; + } + ParticleBuffer[i] = particle; + } + else + { + int index; + InterlockedAdd( ParticleCounters[0], 1, index ); + DeadBuffer[index] = i; + } + } +} + + +[numthreads( 1, 1, 1 )] +void ClearCountersCS() +{ + ParticleCounters[0] = 0; + ParticleCounters[1] = 0; +} + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 Update(); + } +} + +technique ClearCounters +{ + pass p0 + { + ComputeShader = compile cs_5_0 ClearCountersCS(); + } +} diff --git a/shaders/include/Carbon/Math.fxh b/shaders/include/Carbon/Math.fxh index bb96c3247..1f2cda8d4 100644 --- a/shaders/include/Carbon/Math.fxh +++ b/shaders/include/Carbon/Math.fxh @@ -328,4 +328,32 @@ float4x4 MatrixInverse(float4x4 m) return result; } + +float4 QuaternionRotationYawPitchRoll( float yaw, float pitch, float roll ) +{ + float sinYaw = sin( yaw / 2.0f ); + float cosYaw = cos( yaw / 2.0f ); + float sinPitch = sin( pitch / 2.0f ); + float cosPitch = cos( pitch / 2.0f ); + float sinRoll = sin( roll / 2.0f ); + float cosRoll = cos( roll / 2.0f ); + + float4 result; + result.x = sinYaw * cosPitch * sinRoll + cosYaw * sinPitch * cosRoll; + result.y = sinYaw * cosPitch * cosRoll - cosYaw * sinPitch * sinRoll; + result.z = cosYaw * cosPitch * sinRoll - sinYaw * sinPitch * cosRoll; + result.w = cosYaw * cosPitch * cosRoll + sinYaw * sinPitch * sinRoll; + return result; +} + +float4 QuaternionMultiply( float4 q1, float4 q2 ) +{ + float4 result; + result.x = q2.w * q1.x + q2.x * q1.w + q2.y * q1.z - q2.z * q1.y; + result.y = q2.w * q1.y - q2.x * q1.z + q2.y * q1.w + q2.z * q1.x; + result.z = q2.w * q1.z + q2.x * q1.y - q2.y * q1.x + q2.z * q1.w; + result.w = q2.w * q1.w - q2.x * q1.x - q2.y * q1.y - q2.z * q1.z; + return result; +} + #endif \ No newline at end of file diff --git a/shaders/include/Carbon/RandomXOrShift.fxh b/shaders/include/Carbon/RandomXOrShift.fxh new file mode 100644 index 000000000..7495c0efc --- /dev/null +++ b/shaders/include/Carbon/RandomXOrShift.fxh @@ -0,0 +1,38 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_RANDOM_FXH +#define CARBON_RANDOM_FXH + + +// Based on https://www.reedbeta.com/blog/quick-and-easy-gpu-random-numbers-in-d3d11/ + +// Initializes a random number generator state based on a seed +uint RandInit( uint seed ) +{ + seed = ( seed ^ 61 ) ^ ( seed >> 16 ); + seed *= 9; + seed = seed ^ ( seed >> 4 ); + seed *= 0x27d4eb2d; + seed = seed ^ ( seed >> 15 ); + return seed; +} + +// Returns a random uint in the range [0, 2^32 - 1] and updates the rngState +uint Rand( inout uint rngState ) +{ + // Xorshift algorithm from George Marsaglia's paper + rngState ^= ( rngState << 13 ); + rngState ^= ( rngState >> 17 ); + rngState ^= ( rngState << 5 ); + return rngState; +} + +// Returns a random float in the range [0, 1) and updates the rngState +float RandFloat( inout uint rngState ) +{ + return float( Rand( rngState ) ) * ( 1.0 / 4294967296.0 ); +} + + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/GpuParticles.fxh b/shaders/include/Carbon/SpaceScene/GpuParticles.fxh new file mode 100644 index 000000000..f40b9fae3 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/GpuParticles.fxh @@ -0,0 +1,86 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_GPUPARTICLES_FXH +#define CARBON_GPUPARTICLES_FXH + +// Per particle data stored in the particle buffer. The particle buffer is a structured buffer of GpuParticleData elements. +struct GpuParticleData +{ + // Position of the particle in world space + float3 position; + // Age of the particle in seconds + float age; + // Particle velocity in world space + float3 velocity; + // 16 low bits - emitter index, 16 high bits - random seed for this particle + uint emitterSeed; +}; + +// Per emitter data stored in the emitter buffer. The emitter buffer is a structured buffer of GpuParticleEmitterParams elements. +struct GpuParticleEmitterParams +{ + // Minimal particle lifetime in seconds + float minLifeTime; + // Maximal particle lifetime in seconds + float maxLifeTime; + // Index of the texture in the texture atlas + float textureIndex; + // Particle color over lifetime, defined by a piecewise linear curve of 4 colors + float4 colors[4]; + // Particle sizes over lifetime, defined by a spline of 3 sizes + float3 sizes; + // Variance of the particle size + float sizeVariance; + // Drag force coefficient applied to the particles + float drag; + // Amplitude of the turbulence force applied to the particles + float turbulenceAmplitude; + // Frequency of the turbulence force applied to the particles + float turbulenceFrequency; + // Gravity force applied to the particles + float gravity; + // Attractor force applied to the particle: XYZ - attractor position, W - attractor strength + float4 attractor; + // Velocity stretch factor or rotation speed + // If velocityStretchRotation is negative, it is used as a velocity stretch factor. If it is positive, it is used as a rotation speed in radians per second. + float velocityStretchRotation; +}; + +float GetGpuParticleSize( GpuParticleEmitterParams params, float age, float seed ) +{ + float v = 1.0 - age; + float spline = params.sizes.x * v * v + params.sizes.y * 2.0 * age * v + params.sizes.z * age * age; + return spline * ( 1 + params.sizeVariance * seed ); +} + +float4 GetGpuParticleColor( GpuParticleEmitterParams params, float age, float exponent ) +{ + age = pow( abs( age ), log( exponent ) / log( 0.5 ) ); + float4 color; + if( age <= 0.333 ) + { + color = lerp( params.colors[0], params.colors[1], age / 0.333 ); + } + else if( age <= 0.666 ) + { + color = lerp( params.colors[1], params.colors[2], age / 0.333 - 1 ); + } + else + { + color = lerp( params.colors[2], params.colors[3], age / ( 1 - 0.666 ) - 0.666 / ( 1 - 0.666 ) ); + } + return color; +} + + +// Per particle data stored in the visible buffer. The visible buffer is a structured buffer of GpuParticleVisibleData elements. +struct GpuParticleVisibleData +{ + // Particle index in the particle buffer + uint index; + // Particle depth in projection space + float depth; +}; + + +#endif \ No newline at end of file From a5d32f3ea26d5c9d048dd9ba64e360877042be44 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Wed, 7 Oct 2026 12:19:55 +0000 Subject: [PATCH 56/83] More shaders --- CMakeLists.txt | 9 +- .../SpecialFX/Volumetric/Fog/ApplyFroxels.fx | 53 +++++++ .../SpecialFX/Volumetric/Fog/FilterFroxels.fx | 113 +++++++++++++ .../Space/SpecialFX/Volumetric/Fog/Fog.fxh | 118 ++++++++++++++ .../Volumetric/Fog/RaymarchFroxels.fx | 66 ++++++++ .../Volumetric/Fog/UpdateMieEnvironmentMap.fx | 148 ++++++++++++++++++ .../include/Carbon/SpaceScene/EveStretch2.fxh | 29 ++++ .../Carbon/SpaceScene/EveTacticalOverlay.fxh | 47 ++++++ 8 files changed, 582 insertions(+), 1 deletion(-) create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx create mode 100644 shaders/include/Carbon/SpaceScene/EveStretch2.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 7263138ee..9f9d88432 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,6 +157,8 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh shaders/include/Carbon/SpaceScene/EveTransform.fxh + shaders/include/Carbon/SpaceScene/EveStretch2.fxh + shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh shaders/include/Carbon/SpaceScene/GpuParticles.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh @@ -170,6 +172,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/RandomXOrShift.fxh shaders/include/Carbon/System.fxh shaders/include/Carbon/Tr2CurveLineSet.fxh + shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx @@ -178,7 +181,11 @@ set(_SHADER_SOURCES shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx - shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx + shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx + shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx + shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh + shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx + shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx new file mode 100644 index 000000000..6602e0e5c --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx @@ -0,0 +1,53 @@ +// Copyright © 2026 CCP ehf. + +#pragma permutation(ENVIRONMENT_LIGHTING, values = ( ENVIRONMENT_LIGHTING_DISABLED, ENVIRONMENT_LIGHTING_ENABLED ) ) + +#include "../../../../../include/Carbon/System.fxh" +#include "../../../../../include/Carbon/SpaceScene/PerSceneData.fxh" +#include "../../../../../include/Carbon/SpaceScene/Volumetrics.fxh" +#include "../../../../../include/Carbon/SpaceScene/DepthMap.fxh" + +EveSpaceSceneDataPS PerFramePS : register( PERFRAME_PS_STARTREGISTER ); + + +SamplerState DepthMapSamplerClamp +{ + MinFilter = Point; + MagFilter = Point; + MipFilter = None; + AddressU = Clamp; + AddressV = Clamp; +}; + + +float4 vs( float4 pos : POSITION ) : SV_Position +{ + return pos; +}; + +float4 ps( float4 pos : SV_Position ) : SV_Target0 +{ + float2 texCoords = pos.xy / PerFramePS.RenderTargetData.xy; + float sceneDepth = DepthMap.SampleLevel( DepthMapSamplerClamp, texCoords, 0.0 ).r; + + float4 result; +#if ENVIRONMENT_LIGHTING == ENVIRONMENT_LIGHTING_ENABLED + result = SampleEveSceneFroxelFog( texCoords, sceneDepth, PerFramePS, true ); +#else + result = SampleEveSceneFroxelFog( texCoords, sceneDepth, PerFramePS, false ); +#endif + return result; +} + +technique Main +{ + pass P0 + { + SrcBlend = One; + DestBlend = SrcAlpha; + CullMode = None; + ZEnable = False; + VertexShader = compile vs_5_0 vs(); + PixelShader = compile ps_5_0 ps(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx new file mode 100644 index 000000000..7235a6ea2 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx @@ -0,0 +1,113 @@ +// Copyright © 2026 CCP ehf. + +#include "Fog.fxh" + +SamplerState NearestClampSampler = sampler_state +{ + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; +}; +SamplerState LinearClampSampler = sampler_state +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; +}; + +Texture3D InputTexture; +Texture3D PreviousTexture; + + +RWTexture3D OutputTexture; + + +void accumulate( inout float4 m1, inout float4 m2, float weight, float4 froxel ) +{ + m1 += froxel * weight; + m2 += ( froxel * froxel ) * weight; +} + +[numthreads( 4, 4, 4 )] +void Test( uint3 coords : SV_DispatchThreadID ) +{ + if( coords.x >= FroxelPerObject.Resolution.x || coords.y >= FroxelPerObject.Resolution.y || coords.z >= FroxelPerObject.Resolution.z ) + { + return; + } + + float3 texCoords = ( float3( coords ) + 0.5 ) / float3( FroxelPerObject.Resolution ); + + float4 current = InputTexture.SampleLevel( NearestClampSampler, texCoords, 0 ); + + float4 m1 = 0.0; + float4 m2 = 0.0; + + float weight = 1.0 / 7.0; + + accumulate( m1, m2, weight, current ); + accumulate( m1, m2, weight, InputTexture.SampleLevel( NearestClampSampler, texCoords, 0, int3( -1, 0, 0 ) ) ); + accumulate( m1, m2, weight, InputTexture.SampleLevel( NearestClampSampler, texCoords, 0, int3( +1, 0, 0 ) ) ); + accumulate( m1, m2, weight, InputTexture.SampleLevel( NearestClampSampler, texCoords, 0, int3( 0, -1, 0 ) ) ); + accumulate( m1, m2, weight, InputTexture.SampleLevel( NearestClampSampler, texCoords, 0, int3( 0, +1, 0 ) ) ); + accumulate( m1, m2, weight, InputTexture.SampleLevel( NearestClampSampler, texCoords, 0, int3( 0, 0, -1 ) ) ); + accumulate( m1, m2, weight, InputTexture.SampleLevel( NearestClampSampler, texCoords, 0, int3( 0, 0, +1 ) ) ); + + float4 mean = m1; + float4 std = sqrt( max( m2 - mean * mean, 0.0 ) ); + + float4 result = current; + + //if(true) //Could attempt an early out here to improve performance when std is small (i.e. tight clamping --> we basically ignore the previous frame anyway) + { + +#if 1 + float layerDistance = GetLayerDistance( texCoords.z ); + float3 viewDirection = float3( texCoords.xy * FroxelPerObject.UnprojectParams.xy + FroxelPerObject.UnprojectParams.zw, -1.0 ); + float3 viewPosition = viewDirection * ( layerDistance * rsqrt( dot( viewDirection, viewDirection ) ) ); + + float3 previousViewPosition = mul( float4( viewPosition, 1.0 ), FroxelPerObject.ReprojectionMatrix ).xyz; //no need to do perspective divide + float2 previousCoords = ( previousViewPosition.xy / -previousViewPosition.z ) * FroxelPerObject.PreviousProjectParams.xy + FroxelPerObject.PreviousProjectParams.zw; + float previousNormalizedZ = GetNormalizedZ( length( previousViewPosition ) ); + + float3 previousTexCoords = float3( previousCoords, previousNormalizedZ ); + float4 previous = PreviousTexture.SampleLevel( LinearClampSampler, previousTexCoords, 0 ); +#else + float4 previous = PreviousTexture.SampleLevel(NearestClampSampler, texCoords, 0); +#endif + + + float gamma = 2.0; + previous = clamp( previous, mean - std * gamma, mean + std * gamma ); + + result = lerp( previous, current, 0.05 ); + + //result = float4(abs(texCoords - previousTexCoords) * 100.0, 1.0); + + //result = float4(abs(previousTexCoords - texCoords.xy), 0, current.a); + } + + if( any( isnan( result ) ) || any( isinf( result ) ) ) + { + result = float4( 1, 0, 0, 1 ); + } + + OutputTexture[coords] = result; + +} + + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 Test(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh new file mode 100644 index 000000000..9a9b3b237 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh @@ -0,0 +1,118 @@ +// Copyright © 2026 CCP ehf. + +#ifndef FOG_FXH +#define FOG_FXH + +#include "../../../../../include/Carbon/System.fxh" + + +static const uint LIGHT_FLAG_AFFECTS_SURFACE = 1 << 16; +static const uint LIGHT_FLAG_AFFECTS_PARTICLES = 1 << 17; +static const uint LIGHT_FLAG_CASTS_SHADOWS = 1 << 18; +static const uint LIGHT_FLAG_IS_VOLUMETRIC = 1 << 19; + +struct PerLightData +{ + float4 position; // xyz - world position, w - radius + float4 color; // xyz - color, w - bits 0..15 - innerRadius (float 16), bits 16..31 - flags + float4 direction; // see next few lines: + // x bits 0..15 - direction.x (float 16), x bits 16..31 - direction.y (float 16) + // y bits 0..15 - direction.z (float 16), y bits 16..31 - projectionPlaneDistance (float 16) + // z bits 0..15 - outerAngle (float 16), z bits 16..31 - innerAngle (float 16) + // w bits 0..1 - padding, w bits 2..11 - shadowMapScale, w bits 12..21 - shadowMapOffsetX, w bits 22..31 - shadowMapOffsetY +}; + +struct HitInfo +{ + float visibility; +}; + +#ifndef RAYTRACING +Texture2D ShadowMapAtlas ; +#endif + +struct FroxelPerObjectData +{ + uint3 Resolution; + uint NumDynamicLights; + + float3 Jitter; + float Far; + + float3 Scattering; + float BaseDensity; + + float MaxDistanceVisibility; + float LightG; + float EnvironmentIntensity; + float InverseShadowMapAtlasSize; + + float3 Extinction; + uint ShadowMapAtlasEntryMinSizeLog2; + + float4x4 InverseViewMatrix; + + + float GodRayNoiseFrequency; + float GodRayNoiseLerp; + float GodRayNoiseAnimation; + float GodRayNoiseIntensity; + + float4x4 GodRayNoiseMatrix; + + + float3 FogNoiseOffset; + float FogNoiseFrequency; + + float FogNoiseLerp; + float FogNoiseIntensity; + float2 LinearizeDepthParams; + + + float4 UnprojectParams; + float4 PreviousProjectParams; + float4x4 ReprojectionMatrix; + + float3 SunViewDirection; + float SunAngle; + + float3 SunWorldDirection; + float pad0; + + float3 SunColor; + float LightProfileTextureWidth; + + //Directional light shadows + float4 ShadowMapValues[4]; // x = zFar value[0], y = zFar value[1], z = zFar value[2], w = zFar value[3]..etc + float4x4 ShadowMatrix[16]; // Matrix that takes a coordinate from view space all the way to the packed cascades + float4 SplitInfo; // x = NrOfSplits, y = , z = , w = + + PerLightData DynamicLights[16]; + + float4 Planets[2]; +}; + +cbuffer FroxelPerObjectCB : register(b3) +{ + FroxelPerObjectData FroxelPerObject; +} + +float Dither(uint2 xy, float jitter) +{ + float g = 1.32471795724474602596; + return frac(jitter + dot(float2(xy), 1.0 / float2(g, g*g))); +} + +float GetLayerDistance(float normalizedZ) +{ + float layerDistance = -log(lerp(1.0, FroxelPerObject.MaxDistanceVisibility, normalizedZ)) / FroxelPerObject.BaseDensity; + return layerDistance; +} + +float GetNormalizedZ(float layerDistance) +{ + float normalizedZ = saturate((exp(-layerDistance * FroxelPerObject.BaseDensity) - 1.0) / (FroxelPerObject.MaxDistanceVisibility - 1.0)); + return normalizedZ; +} + +#endif \ No newline at end of file diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx new file mode 100644 index 000000000..998353832 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx @@ -0,0 +1,66 @@ +// Copyright © 2026 CCP ehf. + +#pragma permutation(INPUT_SOURCE, values = ( INPUT_SOURCE_INPUT_TEXTURE, INPUT_SOURCE_OUTPUT_TEXTURE ) ) + +#include "Fog.fxh" + +Texture3D InputTexture; + +RWTexture3D OutputTexture; + +[numthreads( 8, 4, 1 )] +void Test( uint3 coords : SV_DispatchThreadID ) +{ + if( coords.x >= FroxelPerObject.Resolution.x || coords.y >= FroxelPerObject.Resolution.y || coords.z >= FroxelPerObject.Resolution.z ) + { + return; + } + + float inverseLayers = 1.0 / FroxelPerObject.Resolution.z; + + float4 total = 0.0; + + float previousDistance = 0.0; + + for( uint i = 0; i < FroxelPerObject.Resolution.z; i++ ) + { + + float normalizedZ = ( float( i ) + 1.0 ) * inverseLayers; + + float layerDistance = min( FroxelPerObject.Far, GetLayerDistance( normalizedZ ) ); + float stepSize = layerDistance - previousDistance; + previousDistance = layerDistance; + +#if INPUT_SOURCE == INPUT_SOURCE_INPUT_TEXTURE + float3 froxel = InputTexture[uint3( coords.xy, i )]; +#else + float3 froxel = OutputTexture[uint3(coords.xy, i)]; +#endif + float density = stepSize * FroxelPerObject.BaseDensity; + + //Naive integration explodes when density is large, greatly overestimating the scattering + //This is especially bad at high fog density with the last layer, as that one goes to the far plane + //float3 color = froxel * Scattering * density; + + //Physically correct integration makes sure we don't emit more light than is coming in. + float3 color = froxel * FroxelPerObject.Scattering * ( 1.0 - exp( -density ) ); + + float visibility = exp( -total.a ); + + total += float4( color * visibility, density ); + + OutputTexture[uint3( coords.xy, i )] = total.rgb; + } + + +} + + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 Test(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx new file mode 100644 index 000000000..d0be66964 --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx @@ -0,0 +1,148 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../../include/Carbon/System.fxh" + + +uint Resolution; +float2 Jitter; + +float EnvironmentG; + +float BlendWeight; + +float Random; + +TextureCube EveSpaceSceneStaticEnvMap; + +SamplerState LinearClampSampler = sampler_state +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; +}; + +RWTexture2DArray PrecomputedMieEnvironmentMap; + + +float dither( uint2 coords, float scale ) +{ + float g = 1.32471795724474602596; + return frac( Random + dot( float2( coords ), 1.0 / float2( g, g * g ) ) ) * ( 2.0 * scale ) - scale; +} + + +[numthreads( 8, 8, 1 )] +void Test( uint3 coords : SV_DispatchThreadID ) +{ + if( coords.x >= Resolution || coords.y >= Resolution ) + { + return; + } + + float u = ( coords.x + 0.5 ) / Resolution * +2.0 - 1.0; + float v = ( coords.y + 0.5 ) / Resolution * -2.0 + 1.0; + uint face = coords.z; + + + float3 direction; + + if( face == 0 ) + direction = float3( 1, v, -u ); + else if( face == 1 ) + direction = float3( -1, v, u ); + else if( face == 2 ) + direction = float3( u, 1, -v ); + else if( face == 3 ) + direction = float3( u, -1, v ); + else if( face == 4 ) + direction = float3( u, v, 1 ); + else + direction = float3( -u, v, -1 ); + + direction = normalize( direction ); + + float3 normal = -direction; + + float3 up = float3( 1, 0, 0 ); + if( abs( dot( normal, up ) ) > 0.9 ) + { + up = float3( 0, 1, 0 ); + } + float3 tangent = normalize( cross( normal, up ) ); + float3 bitangent = cross( normal, tangent ); + + float4x4 transform = float4x4( + float4( tangent, 0.0 ), + float4( bitangent, 0.0 ), + float4( normal, 0.0 ), + float4( 0.0, 0.0, 0.0, 1.0 ) + ); + + const int ENVIRONMENT_SAMPLES = 32; + + const float PI = 3.14159265359; + + float g = EnvironmentG; + float g2 = g * g; + + const float GRADIENT_STRENGTH = 32.0; + float gradient = GRADIENT_STRENGTH / -g - GRADIENT_STRENGTH; + + float mipmap = log2( gradient ); + + + float weight = rcp( float( ENVIRONMENT_SAMPLES ) ); + + float3 environmentLighting = 0.0; + for( int i = 0; i < ENVIRONMENT_SAMPLES; i++ ) + { + + float2 randomOffset = float2( ( i + 0.5 ) / ENVIRONMENT_SAMPLES, i * 0.61803398875 ); + + randomOffset = frac( randomOffset + Jitter ); + + + float a = ( 1.0 / ( 2.0 * g ) ) * ( 1.0 + g2 - pow( ( 1.0 - g2 ) / ( 1.0 - g + 2.0 * g * randomOffset.x ), 2.0 ) ); + float b = randomOffset.y * ( PI * 2.0 ); + + float2 vertical = float2( a, sqrt( 1.0 - a * a ) ); + + float2 horizontal = float2( cos( b ), sin( b ) ); + float3 direction = mul( float4( horizontal.x * vertical.y, horizontal.y * vertical.y, vertical.x, 0.0 ), transform ).xyz; + float3 environmentColor = EveSpaceSceneStaticEnvMap.SampleLevel( LinearClampSampler, direction, 0.0 ).rgb; + + environmentLighting += environmentColor * weight; + } + + float3 previous = PrecomputedMieEnvironmentMap[coords]; + + float3 result = lerp( previous, environmentLighting, BlendWeight ); + + + if( any( isnan( result ) ) || any( isinf( result ) ) ) + { + result = float3( 1, 0, 0 ); + } + + //None of this helps with the precision issues :( + + //result *= 1.0 + dither(coords.xy, 1.0 / 512.0); + + //float3 test = asfloat(int3(asint(result)) + int(dither(coords.xy, 512.0 * 160))); + //result = test; + + PrecomputedMieEnvironmentMap[coords] = result; +} + + + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 Test(); + } +} diff --git a/shaders/include/Carbon/SpaceScene/EveStretch2.fxh b/shaders/include/Carbon/SpaceScene/EveStretch2.fxh new file mode 100644 index 000000000..9b94d8d96 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveStretch2.fxh @@ -0,0 +1,29 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVESTRETCH2_FXH +#define CARBON_EVESTRETCH2_FXH + + +// Data passed from the engine to the all shader stage for EveStretch2 draw calls. +struct EveStretch2PerObjectData +{ + // XYZ - stretch source position in world space, W - scale factor for the destination point or 0 if the destination effect is hidden + float4 SourcePosition; + // XYZ - stretch destination position in world space, W - scale factor for the destination point + float4 DestPosition; + // X - time from the beginning of the "start" phase, Y - time from the beginning of the firing loop, Z - time from the beginning of the "end" phase, W - random value from 0 to 1 + float4 Timing; + // X - effect intensity, YZW - unused + float4 Misc; +}; + + +// Data passed from the engine to the vertex shader stage for EveStretch2 draw calls. +struct EveStretch2Vertex +{ + // X - index of the quad, Y - index of the vertex in the quad + float2 indices : POSITION; +}; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh b/shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh new file mode 100644 index 000000000..85b778385 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh @@ -0,0 +1,47 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVETACTICALOVERLAY_FXH +#define CARBON_EVETACTICALOVERLAY_FXH + + +// Data passed from the engine to the vertex shader stage for EveTacticalOverlay sphere connector draw calls. +struct EveTacticalOverlaySphereConnectorVertexInput +{ + // XYZ - connector position in world space, W - step count and step index + float4 instanceData : TEXCOORD0; + // Object radius in integer part, intensity in fractional part + float instanceData2 : TEXCOORD1; + // Quad vertex index (0-3) + float index : TEXCOORD5; +}; + + +// Data passed from the engine to the vertex shader stage for EveTacticalOverlay anchor draw calls. +struct EveTacticalOverlayAnchorVertexInput +{ + // XYZ - anchor position in world space, W - effect intensity + float4 instanceData : TEXCOORD0; + // Quad vertex index (0-3) + float index : TEXCOORD5; +}; + + +// Data passed from the engine to the vertex shader stage for EveTacticalOverlay velocity connector draw calls. +struct EveTacticalOverlayVelocityConnectorVertexInput +{ + // XYZ - connector position in world space, W - quad index (0 - velocity, 1 - approach amount, 2 - relative approach amount) + float4 instanceData : TEXCOORD0; + // XYZ - velocity in world space, W - radius in integer part, blink phase in fractional part + float4 instanceData2 : TEXCOORD1; + // Quad vertex index (0-3) + float index : TEXCOORD5; +}; + +// Tactical overlay plane position in world space, passed via a variable store +float3 PlanePosition = float3( 0, 0, 0 ); +// Player ship velocity in world space, passed via a variable store +float3 RootVelocity = float3( 0, 0, 0 ); +// X - active range; Y - fadeout length; Z - multiplier for range and fadeout; W - base/source/ship radius +float4 Fadeout = float4( 200000.0, 50000.0, 1.0, 50.0 ); + +#endif \ No newline at end of file From 19e825a2559fc173f6af5809e0fb21d3867b5185 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Wed, 7 Oct 2026 13:05:53 +0000 Subject: [PATCH 57/83] Fog shaders --- CMakeLists.txt | 2 +- .../SpecialFX/Volumetric/Fog/FilterFroxels.fx | 11 +++-- .../Volumetric/Fog/RaymarchFroxels.fx | 11 +++-- .../Carbon/SpaceScene/FroxelFog.fxh} | 48 ++++++------------- 4 files changed, 31 insertions(+), 41 deletions(-) rename shaders/{Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh => include/Carbon/SpaceScene/FroxelFog.fxh} (61%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f9d88432..7d87bd24b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,6 +159,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveTransform.fxh shaders/include/Carbon/SpaceScene/EveStretch2.fxh shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh + shaders/include/Carbon/SpaceScene/FroxelFog.fxh shaders/include/Carbon/SpaceScene/GpuParticles.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh @@ -183,7 +184,6 @@ set(_SHADER_SOURCES shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx - shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx ) diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx index 7235a6ea2..79d1ae614 100644 --- a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx @@ -1,6 +1,11 @@ // Copyright © 2026 CCP ehf. -#include "Fog.fxh" +#include "../../../../../include/Carbon/SpaceScene/FroxelFog.fxh" + +cbuffer FroxelPerObjectCB : register( b3 ) +{ + FroxelPerObjectData FroxelPerObject; +} SamplerState NearestClampSampler = sampler_state { @@ -68,13 +73,13 @@ void Test( uint3 coords : SV_DispatchThreadID ) { #if 1 - float layerDistance = GetLayerDistance( texCoords.z ); + float layerDistance = FroxelGetLayerDistance( texCoords.z, FroxelPerObject ); float3 viewDirection = float3( texCoords.xy * FroxelPerObject.UnprojectParams.xy + FroxelPerObject.UnprojectParams.zw, -1.0 ); float3 viewPosition = viewDirection * ( layerDistance * rsqrt( dot( viewDirection, viewDirection ) ) ); float3 previousViewPosition = mul( float4( viewPosition, 1.0 ), FroxelPerObject.ReprojectionMatrix ).xyz; //no need to do perspective divide float2 previousCoords = ( previousViewPosition.xy / -previousViewPosition.z ) * FroxelPerObject.PreviousProjectParams.xy + FroxelPerObject.PreviousProjectParams.zw; - float previousNormalizedZ = GetNormalizedZ( length( previousViewPosition ) ); + float previousNormalizedZ = FroxelGetNormalizedZ( length( previousViewPosition ), FroxelPerObject ); float3 previousTexCoords = float3( previousCoords, previousNormalizedZ ); float4 previous = PreviousTexture.SampleLevel( LinearClampSampler, previousTexCoords, 0 ); diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx index 998353832..e89c0b9c5 100644 --- a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx +++ b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx @@ -2,7 +2,12 @@ #pragma permutation(INPUT_SOURCE, values = ( INPUT_SOURCE_INPUT_TEXTURE, INPUT_SOURCE_OUTPUT_TEXTURE ) ) -#include "Fog.fxh" +#include "../../../../../include/Carbon/SpaceScene/FroxelFog.fxh" + +cbuffer FroxelPerObjectCB : register( b3 ) +{ + FroxelPerObjectData FroxelPerObject; +} Texture3D InputTexture; @@ -27,14 +32,14 @@ void Test( uint3 coords : SV_DispatchThreadID ) float normalizedZ = ( float( i ) + 1.0 ) * inverseLayers; - float layerDistance = min( FroxelPerObject.Far, GetLayerDistance( normalizedZ ) ); + float layerDistance = min( FroxelPerObject.Far, FroxelGetLayerDistance( normalizedZ, FroxelPerObject ) ); float stepSize = layerDistance - previousDistance; previousDistance = layerDistance; #if INPUT_SOURCE == INPUT_SOURCE_INPUT_TEXTURE float3 froxel = InputTexture[uint3( coords.xy, i )]; #else - float3 froxel = OutputTexture[uint3(coords.xy, i)]; + float3 froxel = OutputTexture[uint3( coords.xy, i )]; #endif float density = stepSize * FroxelPerObject.BaseDensity; diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh b/shaders/include/Carbon/SpaceScene/FroxelFog.fxh similarity index 61% rename from shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh rename to shaders/include/Carbon/SpaceScene/FroxelFog.fxh index 9a9b3b237..830c59b1a 100644 --- a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/Fog.fxh +++ b/shaders/include/Carbon/SpaceScene/FroxelFog.fxh @@ -1,17 +1,11 @@ // Copyright © 2026 CCP ehf. -#ifndef FOG_FXH -#define FOG_FXH +#ifndef CARBON_FOG_FXH +#define CARBON_FOG_FXH -#include "../../../../../include/Carbon/System.fxh" +#include "../System.fxh" - -static const uint LIGHT_FLAG_AFFECTS_SURFACE = 1 << 16; -static const uint LIGHT_FLAG_AFFECTS_PARTICLES = 1 << 17; -static const uint LIGHT_FLAG_CASTS_SHADOWS = 1 << 18; -static const uint LIGHT_FLAG_IS_VOLUMETRIC = 1 << 19; - -struct PerLightData +struct FroxelPerLightData { float4 position; // xyz - world position, w - radius float4 color; // xyz - color, w - bits 0..15 - innerRadius (float 16), bits 16..31 - flags @@ -22,15 +16,6 @@ struct PerLightData // w bits 0..1 - padding, w bits 2..11 - shadowMapScale, w bits 12..21 - shadowMapOffsetX, w bits 22..31 - shadowMapOffsetY }; -struct HitInfo -{ - float visibility; -}; - -#ifndef RAYTRACING -Texture2D ShadowMapAtlas ; -#endif - struct FroxelPerObjectData { uint3 Resolution; @@ -61,7 +46,7 @@ struct FroxelPerObjectData float4x4 GodRayNoiseMatrix; - float3 FogNoiseOffset; + float3 FogNoiseOffset; float FogNoiseFrequency; float FogNoiseLerp; @@ -83,35 +68,30 @@ struct FroxelPerObjectData float LightProfileTextureWidth; //Directional light shadows - float4 ShadowMapValues[4]; // x = zFar value[0], y = zFar value[1], z = zFar value[2], w = zFar value[3]..etc + float4 ShadowMapValues[4]; // x = zFar value[0], y = zFar value[1], z = zFar value[2], w = zFar value[3]..etc float4x4 ShadowMatrix[16]; // Matrix that takes a coordinate from view space all the way to the packed cascades float4 SplitInfo; // x = NrOfSplits, y = , z = , w = - PerLightData DynamicLights[16]; + FroxelPerLightData DynamicLights[16]; float4 Planets[2]; }; -cbuffer FroxelPerObjectCB : register(b3) -{ - FroxelPerObjectData FroxelPerObject; -} - -float Dither(uint2 xy, float jitter) +float FroxelDither( uint2 xy, float jitter ) { - float g = 1.32471795724474602596; - return frac(jitter + dot(float2(xy), 1.0 / float2(g, g*g))); + float g = 1.32471795724474602596; + return frac( jitter + dot( float2( xy ), 1.0 / float2( g, g * g ) ) ); } -float GetLayerDistance(float normalizedZ) +float FroxelGetLayerDistance( float normalizedZ, FroxelPerObjectData froxelPerObject ) { - float layerDistance = -log(lerp(1.0, FroxelPerObject.MaxDistanceVisibility, normalizedZ)) / FroxelPerObject.BaseDensity; + float layerDistance = -log( lerp( 1.0, froxelPerObject.MaxDistanceVisibility, normalizedZ ) ) / froxelPerObject.BaseDensity; return layerDistance; } -float GetNormalizedZ(float layerDistance) +float FroxelGetNormalizedZ( float layerDistance, FroxelPerObjectData froxelPerObject ) { - float normalizedZ = saturate((exp(-layerDistance * FroxelPerObject.BaseDensity) - 1.0) / (FroxelPerObject.MaxDistanceVisibility - 1.0)); + float normalizedZ = saturate( ( exp( -layerDistance * froxelPerObject.BaseDensity ) - 1.0 ) / ( froxelPerObject.MaxDistanceVisibility - 1.0 ) ); return normalizedZ; } From 2e98a8cf926c54ff356f2b08672a558fd971fd2e Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Wed, 7 Oct 2026 13:58:21 +0000 Subject: [PATCH 58/83] Cloud shaders --- CMakeLists.txt | 3 + .../SpecialFX/Volumetric/BlurVolumetric.fx | 79 +++++++++++++++++++ .../SpecialFX/Volumetric/DownsampleDepth.fx | 31 ++++++++ .../Carbon/SpaceScene/EnvironmentMap.fxh | 6 +- .../Carbon/SpaceScene/EveChildCloud2.fxh | 53 +++++++++++++ 5 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx create mode 100644 shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx create mode 100644 shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d87bd24b..df0d235a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh + shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh shaders/include/Carbon/SpaceScene/EveHazeSet.fxh shaders/include/Carbon/SpaceScene/EveLensflare.fxh shaders/include/Carbon/SpaceScene/EveOccluder.fxh @@ -186,6 +187,8 @@ set(_SHADER_SOURCES shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx + shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx + shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx b/shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx new file mode 100644 index 000000000..11f947d9c --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx @@ -0,0 +1,79 @@ +#pragma permutation(SOURCE_TYPE, values=(SOURCE_TYPE_ARRAY, SOURCE_TYPE_TEXTURE)) + +#include "../../../../include/Carbon/SpaceScene/PerSceneData.fxh" +#include "../../../../include/Carbon/SpaceScene/Volumetrics.fxh" + +EveSpaceSceneDataPS PerFramePS : register( PERFRAME_PS_STARTREGISTER ); + + +float4 vs( float4 pos : POSITION ) : SV_Position +{ + return pos; +}; + + +SamplerState EveSceneFogVolumeMapPSampler +{ + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; +}; + +float4 DepthSizes; +Texture2D VolumetricDepthMap; +Texture2D SourceMap; + +float GetLinearDepth( float d ) +{ + return PerFramePS.ProjectionData.x / ( d + PerFramePS.ProjectionData.y ); +} + +float4 ps( float4 pos : SV_Position ) : SV_Target +{ + float2 uv = pos.xy / DepthSizes.xy; + float2 invTexelSize = DepthSizes.zw; + + float centerDepth = GetLinearDepth( VolumetricDepthMap.SampleLevel( EveSceneFogVolumeMapPSampler, uv, 0 ) ); + + half4 color = 0; + half weight = 0; + +#define HALFTAP 2 + const half weights[HALFTAP * 2 + 1] = { 18, 46, 90, 46, 18 }; + + [unroll] + for( float i = -HALFTAP; i <= HALFTAP; ++i ) + { + float depth = GetLinearDepth( VolumetricDepthMap.SampleLevel( EveSceneFogVolumeMapPSampler, uv + i * invTexelSize, 0 ) ); + + half w = weights[i + HALFTAP]; + float denom = 1 + min( depth, centerDepth ); + w *= half( 1 - saturate( abs( depth - centerDepth ) / denom ) ); +#if SOURCE_TYPE == SOURCE_TYPE_TEXTURE + color += w * SourceMap.SampleLevel( EveSceneFogVolumeMapPSampler, uv + i * invTexelSize, 0 ); +#else + color += w * half4( EveSceneFogVolumeMap.SampleLevel( EveSceneFogVolumeMapPSampler, float3( uv + i * invTexelSize, 3 ), 0 ) ); +#endif + weight += w; + } + color /= weight; + + color.a = saturate( color.a ); //half precision math means we can get over 1.0 alpha, so saturate it. + + return float4( color ); +} + +technique Main +{ + pass P0 + { + AlphaBlendEnable = false; + CullMode = None; + ZEnable = False; + VertexShader = compile vs_5_0 vs(); + PixelShader = compile ps_5_0 ps(); + } +} diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx b/shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx new file mode 100644 index 000000000..757aa103f --- /dev/null +++ b/shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx @@ -0,0 +1,31 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../include/Carbon/System.fxh" +#include "../../../../include/Carbon/SpaceScene/DepthMap.fxh" + + +float4 vs( float4 pos : POSITION ) : SV_Position +{ + return pos; +} + + +float4 DepthSizes; + +float4 ps( float4 pos : SV_Position ) : SV_Target +{ + return DepthMap.Load( float3( pos.xy / DepthSizes.xy * DepthSizes.zw, 0 ) ); +} + + +technique Main +{ + pass P0 + { + AlphaBlendEnable = false; + CullMode = None; + ZEnable = False; + VertexShader = compile vs_5_0 vs(); + PixelShader = compile ps_5_0 ps(); + } +} diff --git a/shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh b/shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh index c68b4130b..2ab4cc415 100644 --- a/shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh +++ b/shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh @@ -42,7 +42,7 @@ float RoughnessToGloss( float roughness ) } // Helper function to convert PBR roughness to mip level used for environment map lookup -float RoughnessToMip( TextureCube envMap, float roughness ) +float RoughnessToMip( float roughness, TextureCube envMap ) { uint width; uint height; @@ -55,13 +55,13 @@ float RoughnessToMip( TextureCube envMap, float roughness ) // Helper function to convert PBR roughness to mip level used for environment map lookup for EveSpaceSceneEnvMap float RoughnessToMip( float roughness ) { - return RoughnessToMip( EveSpaceSceneEnvMap, roughness ); + return RoughnessToMip( roughness, EveSpaceSceneEnvMap ); } // Sample an environment map with given direction and surface roughness float3 SampleEnvironmentMap( TextureCube envMap, float3 dir, float roughness ) { - return envMap.SampleLevel( EveSpaceSceneEnvMapSampler, dir, RoughnessToMip( envMap, roughness ) ).rgb; + return envMap.SampleLevel( EveSpaceSceneEnvMapSampler, dir, RoughnessToMip( roughness, envMap ) ).rgb; } #endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh b/shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh new file mode 100644 index 000000000..1af046d7a --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh @@ -0,0 +1,53 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVECHILDCLOUD2_FXH +#define CARBON_EVECHILDCLOUD2_FXH + + +// Data passed from the engine to the vertex shader stage for EveChildCloud2 draw calls. +struct EveChildCloud2VertexInput +{ + // Vertex position in object space + float3 position : POSITION; +}; + + +struct EveChildCloud2LightInfo +{ + float4 position; // xyz - position, w - radius + float4 color; // xyz - color, w - normalized inner radius +}; + + +// Constant buffer format for per-object data for EveChildCloud2. This data is provided by the engine to all shader stages. +struct EveChildCloud2PerObjectData +{ + float4x4 WorldMat; + float4x4 ProjectionInvMat; + float4x4 WorldViewInvMat; + uint4 LightmapDimensions; // xyz - lightmap width/height/depth, w - current generation offset + uint4 NoiseConfig; // xy - random offset, zw - noise texture width/height + float4 SunDirection; // xyz - sun direction in model space, w - slice 0 w + float4 ViewPosition; // xyz - view position in model space, w - slice 1 w + float4 ViewDirection; // xyz - view direction in model space, w - slice 2 w + float4 RelativeScaling; // xyz - renormalizing factors for non-uniform scaling, w - lod factor + float4 TargetInvSize; // xy - render target inv size x2 + EveChildCloud2LightInfo Lights[4]; + float4 MapOffsets[3]; + float4x4 LightViewProj; +}; + + +// The expected pixel shader output from EveChildCloud2 materials. +// Each slice of the cloud is written to a separate render target. +// Slice depth is taken from EveChildCloud2PerObjectData +struct EveChildCloud2PSOutput +{ + float4 slice0 : SV_Target0; + float4 slice1 : SV_Target1; + float4 slice2 : SV_Target2; + float4 slice3 : SV_Target3; +}; + + +#endif \ No newline at end of file From 46059f146121281d869ed38d2de8fd6012d0ef8a Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Wed, 7 Oct 2026 14:58:16 +0000 Subject: [PATCH 59/83] More vfx shaders --- CMakeLists.txt | 3 ++ .../Carbon/SpaceScene/EveChildCloud.fxh | 30 +++++++++++++++++++ .../Carbon/SpaceScene/EveChildQuad.fxh | 29 ++++++++++++++++++ .../Carbon/SpaceScene/EveStarfield.fxh | 23 ++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/EveChildCloud.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveChildQuad.fxh create mode 100644 shaders/include/Carbon/SpaceScene/EveStarfield.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index df0d235a9..5f23be2ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,14 +149,17 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh + shaders/include/Carbon/SpaceScene/EveChildCloud.fxh shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh shaders/include/Carbon/SpaceScene/EveHazeSet.fxh shaders/include/Carbon/SpaceScene/EveLensflare.fxh shaders/include/Carbon/SpaceScene/EveOccluder.fxh shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh + shaders/include/Carbon/SpaceScene/EveChildQuad.fxh shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh + shaders/include/Carbon/SpaceScene/EveStarfield.fxh shaders/include/Carbon/SpaceScene/EveTransform.fxh shaders/include/Carbon/SpaceScene/EveStretch2.fxh shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh diff --git a/shaders/include/Carbon/SpaceScene/EveChildCloud.fxh b/shaders/include/Carbon/SpaceScene/EveChildCloud.fxh new file mode 100644 index 000000000..fee339ee6 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveChildCloud.fxh @@ -0,0 +1,30 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVECHILDCLOUD_FXH +#define CARBON_EVECHILDCLOUD_FXH + + +// Data passed from the engine to the vertex shader stage for EveChildCloud draw calls. +struct EveChildCloudVertexInput +{ + float2 position : POSITION; +}; + + +// Data passed from the engine to the vertex shader stage for EveChildCloud draw calls. +struct EveChildCloudPerObjectDataVS +{ + float4x4 WorldMat; + float4x4 WorldViewMat; + float4x4 WorldViewInv; + float4x4 ProjectionInv; + // Near plane in object space + float4 NearPlaneLocal; + // XYZ - camera position in object space, W - screen depth of the object (Z in clip space) + float4 EyePosLocal; + // Bounds of the cloud in projection space (XY - min, ZW - max) + float4 ScreenSize; +}; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveChildQuad.fxh b/shaders/include/Carbon/SpaceScene/EveChildQuad.fxh new file mode 100644 index 000000000..487ae2b80 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveChildQuad.fxh @@ -0,0 +1,29 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVECHILDQUAD_FXH +#define CARBON_EVECHILDQUAD_FXH + + +struct EveChildQuadVertexInput +{ + // Quad vertex index (0-3) + float index : TEXCOORD5; + + // Transform matrix (3x4) from owner local space to world space + float4 parentTransform0 : POSITION0; + float4 parentTransform1 : POSITION1; + float4 parentTransform2 : POSITION2; + + // Transform matrix (3x4) from quad local space to owner local space + float4 localTransform0 : POSITION3; + float4 localTransform1 : POSITION4; + float4 localTransform2 : POSITION5; + + // Quad color + float4 color : TEXCOORD0; + // X - quad brightness, Y - unused + float2 data : TEXCOORD1; +}; + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/EveStarfield.fxh b/shaders/include/Carbon/SpaceScene/EveStarfield.fxh new file mode 100644 index 000000000..8bce8f5a3 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveStarfield.fxh @@ -0,0 +1,23 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVESTARFIELD_FXH +#define CARBON_EVESTARFIELD_FXH + +struct EveStarfieldVertexInput +{ + // Start sprite position in local space + float3 position : POSITION; + // Random number from 0 to 1 for each star + float coloridx : TEXCOORD0; + // Maximum intensity of the star sprite + float flashIntensity : TEXCOORD1; + // Random phase for the star sprite's flashing effect (0 to 1) + float phase : TEXCOORD2; + // Random rate for the star sprite's flashing effect + float rate : TEXCOORD3; + // X - vertex corner index (0-3), Y - texture atlas element index, Z - unused, W - unused + uint4 index : TEXCOORD4; +}; + + +#endif \ No newline at end of file From 9a97bd47be52a798cd0b6fc2937d4157ca1f24c5 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 09:32:09 +0000 Subject: [PATCH 60/83] Raytracing helpers --- CMakeLists.txt | 2 + .../SpaceScene/Raytracing/GeometryData.fxh | 158 ++++++++ shaders/include/Carbon/VertexBufferUtil.fxh | 346 ++++++++++++++++++ 3 files changed, 506 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh create mode 100644 shaders/include/Carbon/VertexBufferUtil.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f23be2ac..a9695307c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,6 +141,7 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() set(_SHADER_SOURCES + shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh shaders/include/Carbon/SpaceScene/DepthMap.fxh shaders/include/Carbon/SpaceScene/DynamicLighting.fxh @@ -177,6 +178,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/RandomXOrShift.fxh shaders/include/Carbon/System.fxh shaders/include/Carbon/Tr2CurveLineSet.fxh + shaders/include/Carbon/VertexBufferUtil.fxh shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx diff --git a/shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh b/shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh new file mode 100644 index 000000000..674181bcf --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh @@ -0,0 +1,158 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_RAYTRACING_GEOMETRYDATA_FXH +#define CARBON_RAYTRACING_GEOMETRYDATA_FXH + +#include "../../PackedTangents.fxh" +#include "../../VertexBufferUtil.fxh" + +// Constant buffer layout for data describing the geometry of a mesh for ray tracing shaders. +// This is used to read vertex and index data from buffers in a shader. +// Normally the constant buffer for this data is declared as: +// cbuffer RtVertexBufferData : register( b5, space8 ) { RayTracingGeometryData geometryData; } +struct RayTracingGeometryData +{ + // Index into the buffer heap view array for the index buffer of the mesh. + uint indexBufferId; + // Index buffer stride in bytes (2 for 16-bit indices, 4 for 32-bit indices). + uint indexBufferStride; + + // Offset in bytes to the start of the index data in the index buffer. + uint indexOffset; + + // Index into the buffer heap view array for the vertex buffer of the mesh. + uint vertexBufferId; + // Vertex buffer stride in bytes. + uint vertexBufferStride; + + // Offset in bytes to the start of the position (POSITION0 semantics) data in the vertex buffer. + uint positionOffset; + // Data type of the position attribute. See constants in VertexBufferUtil.fxh for possible values. + uint positionType; + + // Offset in bytes to the start of the normal (NORMAL0 semantics) data in the vertex buffer. + uint normalOffset; + // Data type of the normal attribute. See constants in VertexBufferUtil.fxh for possible values. + uint normalType; + + // Offset in bytes to the start of the tangent (TANGENT0 semantics) data in the vertex buffer. + uint tangentOffset; + // Data type of the tangent attribute. See constants in VertexBufferUtil.fxh for possible values. + uint tangentType; + + // Offset in bytes to the start of the bitangent (BITANGENT0 semantics) data in the vertex buffer. + uint bitangentOffset; + // Data type of the bitangent attribute. See constants in VertexBufferUtil.fxh for possible values. + uint bitangentType; + + // Offset in bytes to the start of the first texture coordinate (TEXCOORD0 semantics) data in the vertex buffer. + uint texCoord0Offset; + // Data type of the first texture coordinate attribute. + uint texCoord0Type; + + // Offset in bytes to the start of the second texture coordinate (TEXCOORD1 semantics) data in the vertex buffer. + uint texCoord1Offset; + // Data type of the second texture coordinate attribute. + uint texCoord1Type; + + // Offset in bytes to the start of the third texture coordinate (TEXCOORD2 semantics) data in the vertex buffer. + uint texCoord2Offset; + // Data type of the third texture coordinate attribute. + uint texCoord2Type; + + uint padding; +}; + +// Reads trangle vertex indices from the index buffer for a given primitive index. Returns a uint3 containing the three vertex indices of the triangle. +// Handles both 16-bit and 32-bit index buffers based on the indexBufferStride in the RayTracingGeometryData. Assumes "triangle list" topology. +uint3 ReadIndices( Buffer indexBuffer, RayTracingGeometryData data, uint primitiveIndex ) +{ + uint indicesAddress = ( 3 * primitiveIndex ) * data.indexBufferStride + data.indexOffset; + if( data.indexBufferStride == 2 ) + { + return ReadUInt16_3( indexBuffer, indicesAddress ); + } + else + { + return ReadUInt32_3( indexBuffer, indicesAddress ); + } +} + +// Reads the position of a vertex (POSITION0 semantics) from the vertex buffer for a given vertex index. Returns a float3 containing the position. +// Assumes positions are stored as float32_3 in the vertex buffer. The position offset and stride are taken from the RayTracingGeometryData. +float3 ReadPosition( Buffer vertexBuffer, RayTracingGeometryData data, uint vertexIndex ) +{ + return ReadFloat32_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.positionOffset ); +} + +// Reads the normal, tangent, and bitangent of a vertex from the vertex buffer for a given vertex index. Returns a TangentSpace struct containing the three vectors. +// Supports both unpacked and packed tangent space representations based on the tangentType in the RayTracingGeometryData. +TangentSpace ReadNormalTangentBitangent( Buffer vertexBuffer, RayTracingGeometryData data, uint vertexIndex ) +{ + TangentSpace ts; + if( data.tangentType == FLOAT32_3 ) + { + ts.normal = ReadFloat32_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.normalOffset ); + ts.tangent = ReadFloat32_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.tangentOffset ); + ts.bitangent = ReadFloat32_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.bitangentOffset ); + } + else if( data.tangentType == FLOAT16_3 ) + { + ts.normal = ReadFloat16_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.normalOffset ); + ts.tangent = ReadFloat16_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.tangentOffset ); + ts.bitangent = ReadFloat16_3( vertexBuffer, vertexIndex * data.vertexBufferStride + data.bitangentOffset ); + } + else if( data.tangentType == UBYTE_4_NORM ) + { + // untested... + uint packed = vertexBuffer.Load( ( vertexIndex * data.vertexBufferStride + data.tangentOffset ) >> 2 ); + float4 tangents; + tangents.x = float( ( packed >> 0 ) & 0xFF ); + tangents.y = float( ( packed >> 8 ) & 0xFF ); + tangents.z = float( ( packed >> 16 ) & 0xFF ); + tangents.w = float( ( packed >> 24 ) & 0xFF ); + tangents *= ( 1. / 255. ); + ts = UnpackTangentSpace( tangents ); + } + else if( data.tangentType == USHORT_4_NORM ) + { + // untested... + uint packed0 = vertexBuffer.Load( ( vertexIndex * data.vertexBufferStride + data.tangentOffset + 0 ) >> 2 ); + uint packed1 = vertexBuffer.Load( ( vertexIndex * data.vertexBufferStride + data.tangentOffset + 4 ) >> 2 ); + float4 tangents; + tangents.x = float( ( packed0 >> 0 ) & 0xFFFF ); + tangents.y = float( ( packed0 >> 16 ) & 0xFFFF ); + tangents.z = float( ( packed1 >> 0 ) & 0xFFFF ); + tangents.w = float( ( packed1 >> 16 ) & 0xFFFF ); + tangents *= ( 1. / 65535. ); + ts = UnpackTangentSpace( tangents ); + } + else + { + ts.normal = 0; + ts.tangent = 0; + ts.bitangent = 0; + } + return ts; +} + +// Reads the texture coordinate (TEXCOORD0 semantics) of a vertex from the vertex buffer for a given vertex index. Returns a float2 containing the texture coordinate. +float2 ReadTexcoord0( Buffer vertexBuffer, RayTracingGeometryData data, uint vertexIndex ) +{ + return ReadFloat_2( vertexBuffer, vertexIndex * data.vertexBufferStride + data.texCoord0Offset, data.texCoord0Type ); +} + +// Reads the texture coordinate (TEXCOORD1 semantics) of a vertex from the vertex buffer for a given vertex index. Returns a float2 containing the texture coordinate. +float2 ReadTexcoord1( Buffer vertexBuffer, RayTracingGeometryData data, uint vertexIndex ) +{ + return ReadFloat_2( vertexBuffer, vertexIndex * data.vertexBufferStride + data.texCoord1Offset, data.texCoord1Type ); +} + +// Reads the texture coordinate (TEXCOORD2 semantics) of a vertex from the vertex buffer for a given vertex index. Returns a float2 containing the texture coordinate. +float2 ReadTexcoord2( Buffer vertexBuffer, RayTracingGeometryData data, uint vertexIndex ) +{ + return ReadFloat_2( vertexBuffer, vertexIndex * data.vertexBufferStride + data.texCoord2Offset, data.texCoord2Type ); +} + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/VertexBufferUtil.fxh b/shaders/include/Carbon/VertexBufferUtil.fxh new file mode 100644 index 000000000..6a1a25885 --- /dev/null +++ b/shaders/include/Carbon/VertexBufferUtil.fxh @@ -0,0 +1,346 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_VERTEX_BUFFER_UTIL_FXH +#define CARBON_VERTEX_BUFFER_UTIL_FXH + +// ------------------------------------------------------------------------ +// --- mirrors Tr2VertexDefinition::DataType, see Tr2VertexDefinition.h --- +// ------------------------------------------------------------------------ +static const uint DT_INT8 = 0u; +static const uint DT_INT16 = 1u; +static const uint DT_INT32 = 2u; +static const uint DT_FLOAT16 = 3u; +static const uint DT_FLOAT32 = 4u; +static const uint DT_TYPE_MASK = 7u; +static const uint DT_UNSIGNED_BIT = ( 1u << 3u ); +static const uint DT_NORMALIZED_BIT = ( 1u << 4u ); +static const uint DT_SIZE_OFFSET = 5u; +static const uint DT_SIZE_MASK = ( 3u << DT_SIZE_OFFSET ); +static const uint DT_SIZE_1 = ( 0u << DT_SIZE_OFFSET ); +static const uint DT_SIZE_2 = ( 1u << DT_SIZE_OFFSET ); +static const uint DT_SIZE_3 = ( 2u << DT_SIZE_OFFSET ); +static const uint DT_SIZE_4 = ( 3u << DT_SIZE_OFFSET ); +static const uint BYTE_1 = ( DT_INT8 | DT_SIZE_1 ); +static const uint BYTE_2 = ( DT_INT8 | DT_SIZE_2 ); +static const uint BYTE_3 = ( DT_INT8 | DT_SIZE_3 ); +static const uint BYTE_4 = ( DT_INT8 | DT_SIZE_4 ); +static const uint UBYTE_1 = ( DT_INT8 | DT_SIZE_1 | DT_UNSIGNED_BIT ); +static const uint UBYTE_2 = ( DT_INT8 | DT_SIZE_2 | DT_UNSIGNED_BIT ); +static const uint UBYTE_3 = ( DT_INT8 | DT_SIZE_3 | DT_UNSIGNED_BIT ); +static const uint UBYTE_4 = ( DT_INT8 | DT_SIZE_4 | DT_UNSIGNED_BIT ); +static const uint SHORT_1 = ( DT_INT16 | DT_SIZE_1 ); +static const uint SHORT_2 = ( DT_INT16 | DT_SIZE_2 ); +static const uint SHORT_3 = ( DT_INT16 | DT_SIZE_3 ); +static const uint SHORT_4 = ( DT_INT16 | DT_SIZE_4 ); +static const uint USHORT_1 = ( DT_INT16 | DT_SIZE_1 | DT_UNSIGNED_BIT ); +static const uint USHORT_2 = ( DT_INT16 | DT_SIZE_2 | DT_UNSIGNED_BIT ); +static const uint USHORT_3 = ( DT_INT16 | DT_SIZE_3 | DT_UNSIGNED_BIT ); +static const uint USHORT_4 = ( DT_INT16 | DT_SIZE_4 | DT_UNSIGNED_BIT ); +static const uint INT32_1 = ( DT_INT32 | DT_SIZE_1 ); +static const uint INT32_2 = ( DT_INT32 | DT_SIZE_2 ); +static const uint INT32_3 = ( DT_INT32 | DT_SIZE_3 ); +static const uint INT32_4 = ( DT_INT32 | DT_SIZE_4 ); +static const uint UINT32_1 = ( DT_INT32 | DT_SIZE_1 | DT_UNSIGNED_BIT ); +static const uint UINT32_2 = ( DT_INT32 | DT_SIZE_2 | DT_UNSIGNED_BIT ); +static const uint UINT32_3 = ( DT_INT32 | DT_SIZE_3 | DT_UNSIGNED_BIT ); +static const uint UINT32_4 = ( DT_INT32 | DT_SIZE_4 | DT_UNSIGNED_BIT ); +static const uint FLOAT16_1 = ( DT_FLOAT16 | DT_SIZE_1 ); +static const uint FLOAT16_2 = ( DT_FLOAT16 | DT_SIZE_2 ); +static const uint FLOAT16_3 = ( DT_FLOAT16 | DT_SIZE_3 ); +static const uint FLOAT16_4 = ( DT_FLOAT16 | DT_SIZE_4 ); +static const uint UFLOAT16_1 = ( DT_FLOAT16 | DT_SIZE_1 | DT_UNSIGNED_BIT ); +static const uint UFLOAT16_2 = ( DT_FLOAT16 | DT_SIZE_2 | DT_UNSIGNED_BIT ); +static const uint UFLOAT16_3 = ( DT_FLOAT16 | DT_SIZE_3 | DT_UNSIGNED_BIT ); +static const uint UFLOAT16_4 = ( DT_FLOAT16 | DT_SIZE_4 | DT_UNSIGNED_BIT ); +static const uint FLOAT32_1 = ( DT_FLOAT32 | DT_SIZE_1 ); +static const uint FLOAT32_2 = ( DT_FLOAT32 | DT_SIZE_2 ); +static const uint FLOAT32_3 = ( DT_FLOAT32 | DT_SIZE_3 ); +static const uint FLOAT32_4 = ( DT_FLOAT32 | DT_SIZE_4 ); +static const uint UFLOAT32_1 = ( DT_FLOAT32 | DT_SIZE_1 | DT_UNSIGNED_BIT ); +static const uint UFLOAT32_2 = ( DT_FLOAT32 | DT_SIZE_2 | DT_UNSIGNED_BIT ); +static const uint UFLOAT32_3 = ( DT_FLOAT32 | DT_SIZE_3 | DT_UNSIGNED_BIT ); +static const uint UFLOAT32_4 = ( DT_FLOAT32 | DT_SIZE_4 | DT_UNSIGNED_BIT ); +static const uint BYTE_1_NORM = ( BYTE_1 | DT_NORMALIZED_BIT ); +static const uint BYTE_2_NORM = ( BYTE_2 | DT_NORMALIZED_BIT ); +static const uint BYTE_3_NORM = ( BYTE_3 | DT_NORMALIZED_BIT ); +static const uint BYTE_4_NORM = ( BYTE_4 | DT_NORMALIZED_BIT ); +static const uint UBYTE_1_NORM = ( UBYTE_1 | DT_NORMALIZED_BIT ); +static const uint UBYTE_2_NORM = ( UBYTE_2 | DT_NORMALIZED_BIT ); +static const uint UBYTE_3_NORM = ( UBYTE_3 | DT_NORMALIZED_BIT ); +static const uint UBYTE_4_NORM = ( UBYTE_4 | DT_NORMALIZED_BIT ); +static const uint SHORT_1_NORM = ( SHORT_1 | DT_NORMALIZED_BIT ); +static const uint SHORT_2_NORM = ( SHORT_2 | DT_NORMALIZED_BIT ); +static const uint SHORT_3_NORM = ( SHORT_3 | DT_NORMALIZED_BIT ); +static const uint SHORT_4_NORM = ( SHORT_4 | DT_NORMALIZED_BIT ); +static const uint USHORT_1_NORM = ( USHORT_1 | DT_NORMALIZED_BIT ); +static const uint USHORT_2_NORM = ( USHORT_2 | DT_NORMALIZED_BIT ); +static const uint USHORT_3_NORM = ( USHORT_3 | DT_NORMALIZED_BIT ); +static const uint USHORT_4_NORM = ( USHORT_4 | DT_NORMALIZED_BIT ); +static const uint DT_UNKNOWN_TYPE = 0xffFFffFFu; + +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ + +// the following assumes addresses are aligned with size of the respective datatype +// I couldn't find vertex buffer alignment rules for dx12, so I'm basing this on vulkan... +// https://registry.khronos.org/vulkan/specs/latest/html/vkspec.html#fxvertex-input-extraction +// "attribAddress must be a multiple of the size in bytes of the size of the format" + + +// Read Write Buffers + +uint ReadUInt32( RWBuffer buffer, uint address ) +{ + return buffer[( address + 0 ) >> 2]; +} + +uint2 ReadUInt32_2( RWBuffer buffer, uint address ) +{ + uint2 result; + result.x = buffer[( address + 0 ) >> 2]; + result.y = buffer[( address + 4 ) >> 2]; + return result; +} + +uint3 ReadUInt32_3( RWBuffer buffer, uint address ) +{ + uint3 result; + result.x = buffer[( address + 0 ) >> 2]; + result.y = buffer[( address + 4 ) >> 2]; + result.z = buffer[( address + 8 ) >> 2]; + return result; +} + +float ReadFloat32( RWBuffer buffer, uint address ) +{ + return asfloat( ReadUInt32( buffer, address ) ); +} + +float2 ReadFloat32_2( RWBuffer buffer, uint address ) +{ + return asfloat( ReadUInt32_2( buffer, address ) ); +} + +float3 ReadFloat32_3( RWBuffer buffer, uint address ) +{ + return asfloat( ReadUInt32_3( buffer, address ) ); +} + +uint4 ReadUInt16_4( RWBuffer buffer, uint address ) +{ + uint4 result; + uint packed0 = buffer[( address + 0 ) >> 2]; + uint packed1 = buffer[( address + 4 ) >> 2]; + result.x = packed0 & 0xFFFF; + result.y = packed0 >> 16; + result.z = packed1 & 0xFFFF; + result.w = packed1 >> 16; + return result; +} + +int4 ReadInt16_4( RWBuffer buffer, uint address ) +{ + int4 result; + uint packed0 = buffer[( address + 0 ) >> 2]; + uint packed1 = buffer[( address + 4 ) >> 2]; + result.x = asint( ( packed0 & 0xFFFF ) << 16 ) >> 16; + result.y = asint( packed0 & 0xFFFF0000 ) >> 16; + result.z = asint( ( packed1 & 0xFFFF ) << 16 ) >> 16; + result.w = asint( packed1 & 0xFFFF0000 ) >> 16; + return result; +} + +// Read Only Buffers + +uint ReadUInt16( Buffer buffer, uint address ) +{ + uint result; + uint packed = buffer.Load( address >> 2 ); + if( ( address & 3 ) == 0 ) + { + result = packed & 0xFFFF; + } + else + { + result = packed >> 16; + } + return result; +} + +uint2 ReadUInt16_2( Buffer buffer, uint address ) +{ + uint2 result; + uint packed = buffer.Load( ( address + 0 ) >> 2 ); + result.x = packed & 0xFFFF; + result.y = packed >> 16; + return result; +} + +uint3 ReadUInt16_3( Buffer buffer, uint address ) +{ + uint3 result; + uint packed0 = buffer.Load( ( address + 0 ) >> 2 ); + uint packed1 = buffer.Load( ( address + 4 ) >> 2 ); + if( ( address & 3 ) == 0 ) + { + result.x = packed0 & 0xFFFF; + result.y = packed0 >> 16; + result.z = packed1 & 0xFFFF; + } + else + { + result.x = packed0 >> 16; + result.y = packed1 & 0xFFFF; + result.z = packed1 >> 16; + } + return result; +} + +uint4 ReadUInt16_4( Buffer buffer, uint address ) +{ + uint4 result; + uint packed0 = buffer.Load( ( address + 0 ) >> 2 ); + uint packed1 = buffer.Load( ( address + 4 ) >> 2 ); + result.x = packed0 & 0xFFFF; + result.y = packed0 >> 16; + result.z = packed1 & 0xFFFF; + result.w = packed1 >> 16; + return result; +} + +int4 ReadInt16_4( Buffer buffer, uint address ) +{ + int4 result; + uint packed0 = buffer.Load( ( address + 0 ) >> 2 ); + uint packed1 = buffer.Load( ( address + 4 ) >> 2 ); + result.x = asint( ( packed0 & 0xFFFF ) << 16 ) >> 16; + result.y = asint( packed0 & 0xFFFF0000 ) >> 16; + result.z = asint( ( packed1 & 0xFFFF ) << 16 ) >> 16; + result.w = asint( packed1 & 0xFFFF0000 ) >> 16; + return result; +} + + +uint ReadUInt32( Buffer buffer, uint address ) +{ + return buffer.Load( ( address + 0 ) >> 2 ); +} + +uint2 ReadUInt32_2( Buffer buffer, uint address ) +{ + uint2 result; + result.x = buffer.Load( ( address + 0 ) >> 2 ); + result.y = buffer.Load( ( address + 4 ) >> 2 ); + return result; +} + +uint3 ReadUInt32_3( Buffer buffer, uint address ) +{ + uint3 result; + result.x = buffer.Load( ( address + 0 ) >> 2 ); + result.y = buffer.Load( ( address + 4 ) >> 2 ); + result.z = buffer.Load( ( address + 8 ) >> 2 ); + return result; +} + +float ReadFloat16( Buffer buffer, uint address ) +{ + return f16tof32( ReadUInt16( buffer, address ) ); +} + +float2 ReadFloat16_2( Buffer buffer, uint address ) +{ + return f16tof32( ReadUInt16_2( buffer, address ) ); +} + +float3 ReadFloat16_3( Buffer buffer, uint address ) +{ + return f16tof32( ReadUInt16_3( buffer, address ) ); +} + +float ReadFloat32( Buffer buffer, uint address ) +{ + return asfloat( ReadUInt32( buffer, address ) ); +} + +float2 ReadFloat32_2( Buffer buffer, uint address ) +{ + return asfloat( ReadUInt32_2( buffer, address ) ); +} + +float3 ReadFloat32_3( Buffer buffer, uint address ) +{ + return asfloat( ReadUInt32_3( buffer, address ) ); +} + +float2 ReadFloat_2( Buffer buffer, uint address, uint dataType ) +{ + if( dataType == FLOAT16_2 ) + { + return ReadFloat16_2( buffer, address ); + } + else if( dataType == FLOAT32_2 ) + { + return ReadFloat32_2( buffer, address ); + } + else + { + return 0.0.xx; + } +} + +void WriteInt16_4( RWBuffer buffer, uint address, int4 data ) +{ + uint packed0 = ( ( asuint( data.x ) & 0xFFFF ) | ( asuint( data.y ) << 16 ) ); + uint packed1 = ( ( asuint( data.z ) & 0xFFFF ) | ( asuint( data.w ) << 16 ) ); + buffer[( address + 0 ) >> 2] = packed0; + buffer[( address + 4 ) >> 2] = packed1; +} + +void WriteUInt16_4( RWBuffer buffer, uint address, uint4 data ) +{ + uint packed0 = ( data.x & 0xFFFF ) | data.y << 16; + uint packed1 = ( data.z & 0xFFFF ) | data.w << 16; + + buffer[( address + 0 ) >> 2] = packed0; + buffer[( address + 4 ) >> 2] = packed1; +} + +void WriteUInt32_2( RWBuffer buffer, uint address, uint2 data ) +{ + buffer[( address + 0 ) >> 2] = data.x; + buffer[( address + 4 ) >> 2] = data.y; +} + +void WriteUInt32_3( RWBuffer buffer, uint address, uint3 data ) +{ + buffer[( address + 0 ) >> 2] = data.x; + buffer[( address + 4 ) >> 2] = data.y; + buffer[( address + 8 ) >> 2] = data.z; +} + +void WriteUInt32_4( RWBuffer buffer, uint address, uint4 data ) +{ + buffer[( address + 0 ) >> 2] = data.x; + buffer[( address + 4 ) >> 2] = data.y; + buffer[( address + 8 ) >> 2] = data.z; + buffer[( address + 12 ) >> 2] = data.w; +} + +void WriteFloat32_2( RWBuffer buffer, uint address, float2 data ) +{ + WriteUInt32_2( buffer, address, asuint( data ) ); +} + +void WriteFloat32_3( RWBuffer buffer, uint address, float3 data ) +{ + WriteUInt32_3( buffer, address, asuint( data ) ); +} + +void WriteFloat32_4( RWBuffer buffer, uint address, float4 data ) +{ + WriteUInt32_4( buffer, address, asuint( data ) ); +} + +#endif // VERTEX_BUFFER_UTIL_FXH From 53d432a5f35cb8746c54e5680a8c6b06841055e1 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 13:08:34 +0000 Subject: [PATCH 61/83] Fixed a crash in the shader compiler when failing to compile a RT shader --- shadercompiler/EffectCompilerDX11.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/shadercompiler/EffectCompilerDX11.cpp b/shadercompiler/EffectCompilerDX11.cpp index 9512daa97..1ad97abea 100644 --- a/shadercompiler/EffectCompilerDX11.cpp +++ b/shadercompiler/EffectCompilerDX11.cpp @@ -1789,6 +1789,13 @@ bool EffectCompilerDX11::CompileEffect( const char* source, size_t sourceLength, CComPtr pCompileResult; HRESULT hrCompilation = compiler->Compile( &sourceBuffer, arguments, argumentsSize, nullptr, IID_PPV_ARGS( &pCompileResult ) ); + if( SUCCEEDED( hrCompilation ) ) + { + if( FAILED( pCompileResult->GetStatus( &hrCompilation ) ) ) + { + hrCompilation = E_FAIL; + } + } if( FAILED( hrCompilation ) ) { From 49929724cffb441fcc43e3956922c63ab3082b45 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 13:08:54 +0000 Subject: [PATCH 62/83] Raytracing header --- CMakeLists.txt | 1 + .../SpaceScene/Raytracing/ShadowData.fxh | 64 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index a9695307c..7c7df102a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,6 +142,7 @@ endif() set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh + shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh shaders/include/Carbon/SpaceScene/DepthMap.fxh shaders/include/Carbon/SpaceScene/DynamicLighting.fxh diff --git a/shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh b/shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh new file mode 100644 index 000000000..c397f8f54 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh @@ -0,0 +1,64 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_RAYTRACING_SHADOWDATA_FXH +#define CARBON_RAYTRACING_SHADOWDATA_FXH + + +// Data passed to the shadow ray tracing shaders when rendering main sun light shadows in a "b2" constant buffer using Tr2RaytracingManager. +// Can be used by declaring a constant buffer as follows: +// cbuffer RtShadowsPerFrameBuffer: register( b2 ) { RtShadowsSunData RtShadowsPerFrame; } +struct RtShadowsSunData +{ + // The inverse projection transform of the camera for the current frame. + float4x4 ProjectionInv; + // The inverse view transform of the camera for the current frame. + float4x4 ViewInv; + // XYZ - sun direction in world space, W - sun angular size in radians. + float4 SunDirection; + + // Planet positions and radii in world space. X, Y, Z - position, W - radius. + float4 Planets[2]; + + // The resolution of the render target in pixels. + float2 Resolution; + // The current frame index, used for temporal accumulation of shadows. + uint FrameIndex; +}; + +struct RtShadowsPerLightData +{ + float4 position; // xyz - world position, w - radius + float4 color; // xyz - color, w - bits 0..15 - innerRadius (float 16), bits 16..31 - flags + float4 direction; // see next few lines: + // x bits 0..15 - direction.x (float 16), x bits 16..31 - direction.y (float 16) + // y bits 0..15 - direction.z (float 16), y bits 16..31 - projectionPlaneDistance (float 16) + // z bits 0..15 - outerAngle (float 16), z bits 16..31 - innerAngle (float 16) + // w bits 0..1 - padding, w bits 2..11 - shadowMapScale, w bits 12..21 - shadowMapOffsetX, w bits 22..31 - shadowMapOffsetY +}; + +// Data passed to the shadow ray tracing shaders when rendering main sun light shadows in a "b7" constant buffer using Tr2LightManager. +// Can be used by declaring a constant buffer as follows: +// cbuffer RtShadowsPerFrameBuffer: register( b7 ) { RtShadowsPointLightsData RtShadowsPerFrame; } +struct RtShadowsPointLightsData +{ + // The inverse projection transform of the camera for the current frame. + float4x4 ProjectionInv; + // The inverse view transform of the camera for the current frame. + float4x4 ViewInv; + + // Planet positions and radii in world space. X, Y, Z - position, W - radius. + float4 Planets[2]; + + // The resolution of the render target in pixels. + float2 Resolution; + // Number of dynamic lights in DynamicLights array. + uint NumDynamicLights; + float Padding; + + // Per-light data for dynamic lights in the scene. Up to 16 shadow casting lights are supported. + RtShadowsPerLightData DynamicLights[16]; +}; + + + +#endif \ No newline at end of file From 186a4e8edeaa81dbc14a3a5646290b75f39429d1 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 14:13:43 +0000 Subject: [PATCH 63/83] SkinVertices shader --- CMakeLists.txt | 1 + .../Space/System/Raytracing/SkinVertices.fx | 142 ++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 shaders/Managed/Space/System/Raytracing/SkinVertices.fx diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c7df102a..22a11c2e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,6 +195,7 @@ set(_SHADER_SOURCES shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx + shaders/Managed/Space/System/Raytracing/SkinVertices.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Managed/Space/System/Raytracing/SkinVertices.fx b/shaders/Managed/Space/System/Raytracing/SkinVertices.fx new file mode 100644 index 000000000..23a38f899 --- /dev/null +++ b/shaders/Managed/Space/System/Raytracing/SkinVertices.fx @@ -0,0 +1,142 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../../include/Carbon/System.fxh" +#include "../../../../include/Carbon/BoneTransforms.fxh" +#include "../../../../include/Carbon/VertexBufferUtil.fxh" + +StructuredBuffer InVB; +RWStructuredBuffer OutVB; + +struct AnimationData +{ + uint index; + float weight; +}; +StructuredBuffer MorphTargetAnimations ; +RWBuffer BakedMorphTargetBuffer ; + +cbuffer PerObjectVS : register( b3 ) +{ + uint VertexCount; + uint Stride; + uint PositionOffset; + uint BoneOffset; + uint BoneWeightOffset; + uint TransformOffset; + uint InVBIndex; + uint OutVBIndex; + uint OutVBOffset; + uint MorphAnimationDataOffset; + uint MorphAnimationDataCount; + uint MorphTargetPositionOffset; + uint MorphTargetStride; + uint MorphTargetSize; + uint BakedMorphTargetPositionOffset; + uint Padding2; +}; + +#if PLATFORM==PLATFORM_DX12 + +StructuredBuffer HeapView_StructuredBuffer[] +< + bool IsHeapView = true; +>; + +RWStructuredBuffer HeapView_RWStructuredBuffer[] +< + bool IsHeapView = true; +>; + +float LoadVB( uint offset ) +{ + return HeapView_StructuredBuffer[InVBIndex][offset]; +} + +void StoreVB( uint offset, float value ) +{ + HeapView_RWStructuredBuffer[OutVBIndex][offset + OutVBOffset] = value; +} + +#else + +float LoadVB( uint offset ) +{ + return InVB[offset]; +} + +void StoreVB( uint offset, float value ) +{ + OutVB[offset + OutVBOffset] = value; +} + +#endif + +uint4 FromUByte4( uint x ) +{ + return uint4( x & 0xff, ( x >> 8 ) & 0xff, ( x >> 16 ) & 0xff, x >> 24 ); +} + +[numthreads( 64, 1, 1 )] +void SkinVertices( uint3 offset : SV_DispatchThreadID ) +{ + uint vtx = offset.x; + + if( vtx < VertexCount ) + { + uint poffset = ( vtx * Stride + PositionOffset ); + float3 pos = float3( LoadVB( poffset ), LoadVB( poffset + 1 ), LoadVB( poffset + 2 ) ); + + int morphOffset = vtx * MorphTargetStride + MorphTargetPositionOffset; + float3 tmpPos = pos; + for( uint i = 0; i < MorphAnimationDataCount; i++ ) + { + AnimationData data = MorphTargetAnimations[MorphAnimationDataOffset + i]; + int offset = morphOffset + MorphTargetSize * data.index; + float3 morphPos = float3( LoadVB( offset ), LoadVB( offset + 1 ), LoadVB( offset + 2 ) ); + pos += data.weight * ( morphPos - tmpPos ); + } + + if( BakedMorphTargetPositionOffset != 0xFFFFFFFF ) + { + int bakedPosOffset = BakedMorphTargetPositionOffset; // offset in shared index/vertex buffer, but for baked morphs + bakedPosOffset += ( vtx * MorphTargetStride ) << 2; + + float3 morphPos = ReadFloat32_3( BakedMorphTargetBuffer, bakedPosOffset ); + + pos += morphPos - tmpPos; + } + + uint boffset = vtx * Stride + BoneOffset; + + float4x4 boneMatrix; + uint boneIndices = asuint( LoadVB( boffset ) ); + if( BoneWeightOffset != 0xffffffff ) + { + uint4 bones = FromUByte4( boneIndices ); + uint4 w = FromUByte4( asuint( LoadVB( vtx * Stride + BoneWeightOffset ) ) ); + float4 weights = float4( float4( w ) / 255.0 ); + + boneMatrix = + GetBoneTransform( TransformOffset + bones.x ) * weights.x + + GetBoneTransform( TransformOffset + bones.y ) * weights.y + + GetBoneTransform( TransformOffset + bones.z ) * weights.z + + GetBoneTransform( TransformOffset + bones.w ) * weights.w; + } + else + { + boneMatrix = GetBoneTransform( TransformOffset + ( boneIndices & 0xff ) ); + } + pos = mul( float4( pos, 1 ), boneMatrix ).xyz; + StoreVB( vtx * 3, pos.x ); + StoreVB( vtx * 3 + 1, pos.y ); + StoreVB( vtx * 3 + 2, pos.z ); + } +} + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 SkinVertices(); + } +} From 6b6cb0f5e4715db7ec1b8ad6ab5773082e31b8b3 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 15:03:54 +0000 Subject: [PATCH 64/83] System shaders --- CMakeLists.txt | 4 + .../Managed/Space/System/ComputeLightLists.fx | 355 ++++++++++++++++++ shaders/Managed/Space/System/Denoise1D.fx | 127 +++++++ .../Managed/Space/System/DenoiseEstimate.fx | 52 +++ shaders/Managed/Space/System/EstimateNoise.fx | 84 +++++ 5 files changed, 622 insertions(+) create mode 100644 shaders/Managed/Space/System/ComputeLightLists.fx create mode 100644 shaders/Managed/Space/System/Denoise1D.fx create mode 100644 shaders/Managed/Space/System/DenoiseEstimate.fx create mode 100644 shaders/Managed/Space/System/EstimateNoise.fx diff --git a/CMakeLists.txt b/CMakeLists.txt index 22a11c2e3..be1d1b645 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,6 +196,10 @@ set(_SHADER_SOURCES shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx shaders/Managed/Space/System/Raytracing/SkinVertices.fx + shaders/Managed/Space/System/ComputeLightLists.fx + shaders/Managed/Space/System/Denoise1D.fx + shaders/Managed/Space/System/DenoiseEstimate.fx + shaders/Managed/Space/System/EstimateNoise.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Managed/Space/System/ComputeLightLists.fx b/shaders/Managed/Space/System/ComputeLightLists.fx new file mode 100644 index 000000000..c4189c855 --- /dev/null +++ b/shaders/Managed/Space/System/ComputeLightLists.fx @@ -0,0 +1,355 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../include/Carbon/System.fxh" + +#define TILE_WIDTH 16 +#define TILE_HEIGHT 16 + +Texture2D DepthMap; + +struct PerLightData +{ + float4 position; // xyz - world position, w - radius + float4 color; // xyz - color, w - bits 0..15 - innerRadius (float 16), bits 16..31 - flags + float4 direction; // see next few lines: + // x bits 0..15 - direction.x (float 16), x bits 16..31 - direction.y (float 16) + // y bits 0..15 - direction.z (float 16), y bits 16..31 - projectionPlaneDistance (float 16) + // z bits 0..15 - outerAngle (float 16), z bits 16..31 - innerAngle (float 16) + // w bits 0..1 - padding, w bits 2..11 - shadowMapScale, w bits 12..21 - shadowMapOffsetX, w bits 22..31 - shadowMapOffsetY +}; +static const uint LIGHT_FLAG_AFFECTS_PARTICLES = 1 << 17; + + + +StructuredBuffer LightBuffer; +RWStructuredBuffer LightIndices : register( u1 ) < + // These annotations are used by Tr2LightManager + int TileWidth = TILE_WIDTH; + int TileHeight = TILE_HEIGHT; + >; +RWBuffer LightIndexCount; + +struct +{ + float4x4 ViewInverse; + float4x4 ProjInverse; + float4 CameraPosition; + uint4 FrameBufferSizes; // xy - frame buffer size; zw - tiles per width and height + uint LightCount; // number of lights in LightBuffer + uint IndexBufferSize; // number of elements in LightIndices +} PerFramePS : register( c200 ); + +float3 ComputeWorldPos( float2 pixel, float depth, float2 wh ) +{ + float2 uv = pixel / wh; + float2 clipPos = uv * 2 - 1; + clipPos.y = -clipPos.y; + + float4 pos = float4( clipPos, depth, 1 ); + pos = mul( pos, PerFramePS.ProjInverse ); + pos /= pos.w; + pos = mul( pos, PerFramePS.ViewInverse ); + return pos.xyz; +} + +float GetViewDepth( float depth ) +{ + float4 p = mul( float4( 0, 0, depth, 1 ), PerFramePS.ProjInverse ); + return p.z / p.w; +} + +float ConeSphereIntersect( float3 conePosition, float3 coneDirection, float sinAngle, float3 center, float radius ) +{ + float3 d = center - conePosition; + float c = length( d ); + d = normalize( d ); + float ca = dot( d, coneDirection ); + float a = c * ca; + float b = sqrt( c * c - a * a ); + + return saturate( radius + sinAngle * c - b ); +} + + +struct Frustum +{ + float3 coneDirection; + float coneAngleSine; + float3 cameraDirection; + // near/far planes constained to depth buffer contents (for opaque lists) + float nearDepth; + float farDepth; + // near/far planes from the camera (for transparent lists) + float nearPlane; + float farPlane; +}; + +void CreateFrustum( out Frustum frustum, float2 tile, float2 depths, float transparentDepth ) +{ + float2 screenSize = (float2)PerFramePS.FrameBufferSizes.xy; + float minD = depths.x; + float maxD = depths.y; + + // near, far + float minDV = GetViewDepth( minD ); + float maxDV = GetViewDepth( maxD ); + float3 viewDir = mul( float4( 0, 0, -1, 0 ), PerFramePS.ViewInverse ).xyz; + + frustum.cameraDirection = viewDir; + frustum.nearDepth = dot( PerFramePS.ViewInverse[3].xyz, -viewDir ) + minDV; + frustum.farDepth = dot( PerFramePS.ViewInverse[3].xyz, -viewDir ) + maxDV; + frustum.nearPlane = dot( PerFramePS.ViewInverse[3].xyz, -viewDir ) + GetViewDepth( 0 ); + frustum.farPlane = dot( PerFramePS.ViewInverse[3].xyz, -viewDir ) + GetViewDepth( transparentDepth ); + + float left = tile.x * TILE_WIDTH; + float top = tile.y * TILE_HEIGHT; + float right = min( screenSize.x, left + TILE_WIDTH ); + float bottom = min( screenSize.y, top + TILE_HEIGHT ); + + float3 ful = ComputeWorldPos( float2( left, top ), maxD, screenSize ); + float3 fbr = ComputeWorldPos( float2( right, bottom ), maxD, screenSize ); + + float3 c = PerFramePS.CameraPosition.xyz; + + float3 r0 = normalize( ful - c ); + float3 r1 = normalize( fbr - c ); + + float3 dir = normalize( r0 + r1 ); + frustum.coneDirection.xyz = dir; + frustum.coneAngleSine = sqrt( 1 - dot( dir, r0 ) * dot( dir, r0 ) ); +} + +bool SphereInFrustum( float3 center, float radius, Frustum frustum, out bool transparent ) +{ + // check depth: near/far planes + float inside = 1; + + inside *= ConeSphereIntersect( PerFramePS.CameraPosition.xyz, frustum.coneDirection, frustum.coneAngleSine, center, radius ); + + float transparentInside = inside; + + inside *= saturate( radius - dot( float4( center, 1 ), float4( -frustum.cameraDirection, -frustum.nearDepth ) ) ); + inside *= saturate( radius - dot( float4( center, 1 ), float4( frustum.cameraDirection, frustum.farDepth ) ) ); + + transparentInside *= saturate( radius - dot( float4( center, 1 ), float4( -frustum.cameraDirection, -frustum.nearPlane ) ) ); + transparentInside *= saturate( radius - dot( float4( center, 1 ), float4( frustum.cameraDirection, frustum.farPlane ) ) ); + + transparent = inside <= 0; + + return inside > 0 || transparentInside > 0; +} + +bool ConeInFrustum( float3 center, float radius, float3 spotlightDir, float spotlightAngleCos, Frustum frustum, out bool transparent ) +{ + // check first for a sphere that the cone is a subsection of. + float inside = ConeSphereIntersect( PerFramePS.CameraPosition.xyz, frustum.coneDirection, frustum.coneAngleSine, center, radius ); + + // this is a very gross approxomation of the spotlight occlusion... + float cosAngle = spotlightAngleCos; + float hypotenuse = radius / cosAngle; + float sphereRadius = 0.5f * hypotenuse / cosAngle; + float3 sphereCenter = clamp( 0.0, radius, sphereRadius ) * normalize( -spotlightDir ); + + inside *= ConeSphereIntersect( PerFramePS.CameraPosition.xyz, frustum.coneDirection, frustum.coneAngleSine, center + sphereCenter, sphereRadius ); + + float transparentInside = inside; + + inside *= saturate( radius - dot( float4( center, 1 ), float4( -frustum.cameraDirection, -frustum.nearDepth ) ) ); + inside *= saturate( radius - dot( float4( center, 1 ), float4( frustum.cameraDirection, frustum.farDepth ) ) ); + + transparentInside *= saturate( radius - dot( float4( center, 1 ), float4( -frustum.cameraDirection, -frustum.nearPlane ) ) ); + transparentInside *= saturate( radius - dot( float4( center, 1 ), float4( frustum.cameraDirection, frustum.farPlane ) ) ); + + transparent = inside <= 0; + + return inside > 0 || transparentInside > 0; +} + + +groupshared uint g_tileHeadIndex; +groupshared uint g_tileTransparentHeadIndex; +groupshared uint g_tileParticleHeadIndex; +groupshared uint g_tileTransparentTailIndex; + + +void AddLight( uint light, uint heapOffset, uint indexBufferSize, bool transparent ) +{ + int iHead; + InterlockedAdd( LightIndexCount[0], 1, iHead ); + uint head = iHead; + + head = head * 2 + heapOffset; + if( head < indexBufferSize ) + { + if( transparent ) + { + uint next; + InterlockedExchange( g_tileTransparentHeadIndex, head, next ); + + LightIndices[head] = light; + LightIndices[head + 1] = next; + + if( next == 0 ) + { + g_tileTransparentTailIndex = head + 1; + } + } + else + { + uint next; + InterlockedExchange( g_tileHeadIndex, head, next ); + + LightIndices[head] = light; + LightIndices[head + 1] = next; + } + } +} + +groupshared uint g_DepthMinShared; +groupshared uint g_DepthMaxShared; +groupshared uint g_DepthMaxTransparentShared; +groupshared Frustum g_frustum; + + +[numthreads( TILE_WIDTH, TILE_HEIGHT, 1 )] +void ComputeLightLists( uint3 nGid : SV_GroupID, uint groupIndex : SV_GroupIndex, uint3 offset : SV_DispatchThreadID ) +{ + if( groupIndex == 0 ) + { + g_DepthMinShared = asuint( 1.0 ); + g_DepthMaxShared = asuint( 0.0 ); + g_DepthMaxTransparentShared = asuint( 0.0 ); + } + + GroupMemoryBarrierWithGroupSync(); + + float minD = 1; + float minDD = 1; + float maxD = 0; + float d = DepthMap[offset.xy]; + minDD = min( d, minDD ); + if( d != 0 ) + { + minD = maxD = d; + } + if( maxD != 0 ) + { + // have to add epsilon values to depth range because of precision issues when depth buffer range is too large + minD = max( 0.0, minD - 1.19e-07 ); + minDD = max( 0.0, minDD - 1.19e-07 ); + maxD = min( 1.0, maxD + 1.19e-07 ); + } + InterlockedMin( g_DepthMinShared, asuint( 1 - maxD ) ); + InterlockedMax( g_DepthMaxShared, asuint( 1 - minD ) ); + InterlockedMax( g_DepthMaxTransparentShared, asuint( 1 - minDD ) ); + + GroupMemoryBarrierWithGroupSync(); + + if( groupIndex == 0 ) + { + float2 tileDepth = float2( asfloat( g_DepthMinShared ), asfloat( g_DepthMaxShared ) ); + float tileTransparentDepth = asfloat( g_DepthMaxTransparentShared ); + + Frustum frustum; + CreateFrustum( frustum, (float2)nGid.xy, tileDepth, tileTransparentDepth ); + g_frustum = frustum; + g_tileHeadIndex = 0; + g_tileTransparentHeadIndex = 0; + g_tileTransparentTailIndex = 0; + g_tileParticleHeadIndex = 0; + } + + GroupMemoryBarrierWithGroupSync(); + + uint numLights = PerFramePS.LightCount; + uint heapOffset = PerFramePS.FrameBufferSizes.z * PerFramePS.FrameBufferSizes.w * 3; + uint indexBufferSize = PerFramePS.IndexBufferSize; + + for( uint light = groupIndex; light < numLights; light += TILE_WIDTH * TILE_HEIGHT ) + { + PerLightData lightData = LightBuffer[light]; + float4 lightPos = lightData.position; + float3 lightDir = float3( + f16tof32( asuint( lightData.direction.x ) & 0xffff ), + f16tof32( asuint( lightData.direction.x ) >> 16 ), + f16tof32( asuint( lightData.direction.y ) & 0xffff ) + ); + float spotlightAngleCos = f16tof32( asuint( lightData.direction.z ) & 0xffff ); + + bool inside = false; + bool transparent = false; + + if( spotlightAngleCos <= 0 ) + { + if( SphereInFrustum( lightPos.xyz, lightPos.w, g_frustum, transparent ) ) + { + inside = true; + } + } + else + { + if( ConeInFrustum( lightPos.xyz, lightPos.w, lightDir.xyz, spotlightAngleCos, g_frustum, transparent ) ) + { + inside = true; + } + } + if( inside ) + { + AddLight( light, heapOffset, indexBufferSize, transparent ); + uint lightFlags = asuint( lightData.color.w ); + if( lightFlags & LIGHT_FLAG_AFFECTS_PARTICLES ) + { + int iHead; + InterlockedAdd( LightIndexCount[0], 1, iHead ); + uint head = iHead; + + head = head * 2 + heapOffset; + if( head < indexBufferSize ) + { + uint next; + InterlockedExchange( g_tileParticleHeadIndex, head, next ); + + LightIndices[head] = light; + LightIndices[head + 1] = next; + } + } + } + } + + GroupMemoryBarrierWithGroupSync(); + + if( groupIndex == 0 ) + { + uint linearTile = ( nGid.x + nGid.y * PerFramePS.FrameBufferSizes.z ) * 3; + LightIndices[linearTile] = g_tileHeadIndex; + LightIndices[linearTile + 1] = g_tileTransparentHeadIndex ? g_tileTransparentHeadIndex : g_tileHeadIndex; + LightIndices[linearTile + 2] = g_tileParticleHeadIndex; + if( g_tileTransparentTailIndex != 0 ) + { + LightIndices[g_tileTransparentTailIndex] = g_tileHeadIndex; + } + } +} + +[numthreads( 1, 1, 1 )] +void ClearLightListCounter() +{ + LightIndexCount[0] = 0; +} + +technique Main +{ + pass p0 + { + ComputeShader = compile cs_5_0 ComputeLightLists(); + } +} + + +technique Clear +{ + pass p0 + { + ComputeShader = compile cs_5_0 ClearLightListCounter(); + } +} diff --git a/shaders/Managed/Space/System/Denoise1D.fx b/shaders/Managed/Space/System/Denoise1D.fx new file mode 100644 index 000000000..10c45c413 --- /dev/null +++ b/shaders/Managed/Space/System/Denoise1D.fx @@ -0,0 +1,127 @@ +// Copyright © 2026 CCP ehf. + +#pragma permutation(NORMALS_INPUT, values=(NORMALS_INPUT_NONE, NORMALS_INPUT_NORMALS)) + +#include "../../../include/Carbon/System.fxh" + +Texture2D Source; +Texture2D NoiseEstimate; +Texture2D DepthBuffer; +Texture2D NormalBuffer; +#define LOAD_TEX( tex, coord ) ( tex[coord] ) + +float DepthWeight; +float NormalWeight; +float PlaneWeight; +float PassThrough; +int Radius; + +float2 Axis; + +float2 ClipInfo; // x - projection[3][2], y - projection[2][2] +float4x4 ProjectionInv; + +float GetLinearDepth( float d ) +{ + return ClipInfo.x / ( d + ClipInfo.y ); +} + +float3 GetViewSpacePos( float2 xy, float depth ) +{ + float2 dd = ( xy * 2.f - 1.f ); + dd.y = -dd.y; + float4 projPos = float4( dd, depth, 1 ); + float4 viewPos = mul( projPos, ProjectionInv ); + viewPos /= viewPos.w; + return viewPos.xyz; +} + +struct TapKey +{ + float csZ; + float3 csPosition; + float3 normal; +}; + +TapKey GetTapKey( int2 C, float2 fragCoord ) +{ + TapKey key = (TapKey)0; + + if( ( DepthWeight != 0.0 ) || ( PlaneWeight != 0.0 ) ) + { + key.csZ = GetLinearDepth( LOAD_TEX( DepthBuffer, C ) ); + } + + if( PlaneWeight != 0.0 ) + { + key.csPosition = GetViewSpacePos( fragCoord.xy, key.csZ ); + } + + return key; +} + +float CalculateBilateralWeight( TapKey center, TapKey tap ) +{ + float depthWeight = 1.0; + float normalWeight = 1.0; + float planeWeight = 1.0; + + if( DepthWeight != 0.0 ) + { + depthWeight = max( 0.0, 1.0 - abs( tap.csZ - center.csZ ) / max( abs( tap.csZ ), 0.01 ) * DepthWeight ); + } + + return depthWeight * normalWeight * planeWeight; +} + +float4 VS( float4 pos : POSITION ) : SV_Position +{ + return pos; +} + +float4 PS( float4 pixelPos: SV_Position ) : SV_Target +{ + int2 ssC = int2( pixelPos.xy ); + + // 3* is because the estimator produces larger values than we want to use, for visualization purposes + float gaussianRadius = saturate( NoiseEstimate[ssC] * 10.5 ) * Radius; + + float result = 0; + + // Detect sky and noiseless pixels and reject them + if( ( PassThrough != 1 ) && ( LOAD_TEX( DepthBuffer, ssC ) > 0 ) && ( gaussianRadius > 0.5 ) ) + { + float sum0 = 0; + float totalWeight = 0.0; + TapKey key = GetTapKey( ssC, pixelPos.xy ); + + for( int r = -Radius; r <= Radius; ++r ) + { + int2 tapOffset = int2( Axis * r ); + int2 tapLoc = ssC + tapOffset; + + float gaussian = exp( -pow( float( r ) / gaussianRadius, 2 ) ); + float weight = gaussian * ( ( r == 0 ) ? 1.0 : CalculateBilateralWeight( key, GetTapKey( tapLoc, pixelPos.xy + float2(tapOffset) ) ) ); + sum0 += Source[tapLoc].r * weight; + totalWeight += weight; + } + + // totalWeight >= gaussian[0], so no division by zero here + result = sum0 / totalWeight; + } + else + { + // No denoising needed + result = Source[ssC]; + } + return result; +} + +technique Main +{ + pass P0 + { + VertexShader = compile vs_5_0 VS(); + PixelShader = compile ps_5_0 PS(); + } +} diff --git a/shaders/Managed/Space/System/DenoiseEstimate.fx b/shaders/Managed/Space/System/DenoiseEstimate.fx new file mode 100644 index 000000000..1cffd6b9f --- /dev/null +++ b/shaders/Managed/Space/System/DenoiseEstimate.fx @@ -0,0 +1,52 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../include/Carbon/System.fxh" + +Texture2D Source; +SamplerState SourceSampler +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = None; + AddressU = Clamp; + AddressV = Clamp; +}; + +float4 SourceDimensions; + + +float4 VS( float4 pos : POSITION ) : SV_Position +{ + return pos; +} + + +float4 PS( float4 pixelPos: SV_Position ) : SV_Target +{ + float2 center = ( pixelPos.xy + 0.5 ) * SourceDimensions.zw; + + float dst = 0.0; + const int R = 3; + for( int2 delta = int2( -R, -R ); delta.y <= R; delta.y += 2 ) + { + for( delta.x = -R; delta.x <= R; delta.x += 2 ) + { + dst += Source.SampleLevel( SourceSampler, center + float2(delta) * SourceDimensions.zw, 0); + } + } + int samples = R + 1; + + dst *= ( 1.0 / float( samples * samples ) ); + return dst; +} + + + +technique Main +{ + pass P0 + { + VertexShader = compile vs_5_0 VS(); + PixelShader = compile ps_5_0 PS(); + } +} diff --git a/shaders/Managed/Space/System/EstimateNoise.fx b/shaders/Managed/Space/System/EstimateNoise.fx new file mode 100644 index 000000000..d97f2a25e --- /dev/null +++ b/shaders/Managed/Space/System/EstimateNoise.fx @@ -0,0 +1,84 @@ +// Copyright © 2026 CCP ehf. + +#include "../../../include/Carbon/System.fxh" + +Texture2D Source; + +// Pixel radius for noise search. It relates to dithering +static const int NOISE_ESTIMATION_RADIUS = 3; + + +/* Sample the signal used for the noise estimation at offset from ssC */ +float Tap( int2 ssC, int2 offset ) +{ + return Source[ssC + offset].r; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Estimate desired radius from the second derivative of the signal itself in source0 relative to baseline, +// which is the noisier image because it contains shadows +float EstimateNoise( int2 ssC, float2 axis ) +{ + float v2 = Tap( ssC, int2( -NOISE_ESTIMATION_RADIUS * axis ) ); + float v1 = Tap( ssC, int2( ( 1 - NOISE_ESTIMATION_RADIUS ) * axis ) ); + + float d2mag = 0.0; + // The first two points are accounted for above + for( int r = -NOISE_ESTIMATION_RADIUS + 2; r <= NOISE_ESTIMATION_RADIUS; ++r ) + { + float v0 = Tap( ssC, int2( axis * r ) ); + + // Second derivative + float d2 = v2 - v1 * 2.0 + v0; + + d2mag += abs( d2 ); + + // Shift weights in the window + v2 = v1; + v1 = v0; + } + + // Scaled value by 1.5 *before* clamping to visualize going out of range + // It is clamped again when applied. + return clamp( sqrt( d2mag * ( 1.0 / NOISE_ESTIMATION_RADIUS ) ) * ( 1.0 / 1.5 ), 0.0, 1.0 ); +} + + +float Hash( float n ) +{ + return frac( sin( n ) * 1e4 ); +} + + +float4 VS( float4 pos : POSITION ) : SV_Position +{ + return pos; +} + + +float4 PS( float4 pixelPos : SV_Position ) : SV_Target +{ + + float angle = Hash( pixelPos.x + pixelPos.y * 1920.0 ); + + float result = 0; + const int N = 3; + for( float t = 0; t < N; ++t, angle += 3.1428 / float( N ) ) + { + float c = cos( angle ), s = sin( angle ); + result = max( EstimateNoise( int2( pixelPos.xy ), float2( c, s ) ), result ); + } + return result; +} + + + +technique Main +{ + pass P0 + { + VertexShader = compile vs_5_0 VS(); + PixelShader = compile ps_5_0 PS(); + } +} From fee1f86f02e501ba5fcd402783cd7f5b2fd34a82 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 16:26:04 +0000 Subject: [PATCH 65/83] Fix "static const" variables getting into the "globals" constant buffer declaration and getting sorted incorrectly --- shadercompiler/ParserUtils.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/shadercompiler/ParserUtils.cpp b/shadercompiler/ParserUtils.cpp index d42566e00..2d0f33e76 100644 --- a/shadercompiler/ParserUtils.cpp +++ b/shadercompiler/ParserUtils.cpp @@ -905,23 +905,27 @@ int GetNodeOrder( ASTNode* t ) { if( child->GetNodeType() == NT_CBUFFER ) { - return 2; + return 3; } } if( auto child = t->GetChildOrNull( 1 ) ) { if( child->GetNodeType() == NT_CBUFFER ) { - return 2; + return 3; } } if( GetRegisterType( t->GetType() ) ) { - return 2; + return 3; } else { - return 1; + if ( t->GetType().modifier == OP_CONST && t->GetType().storageClass == OP_STATIC ) + { + return 1; + } + return 2; } case NT_TECHNIQUE: return 12; @@ -985,7 +989,7 @@ void CreateGlobalsCB( ParserState& state ) continue; } } - if( !GetRegisterType( child->GetType() ) ) + if( !GetRegisterType( child->GetType() ) && !( child->GetType().modifier == OP_CONST && child->GetType().storageClass == OP_STATIC ) ) { varStart = std::min( varStart, i ); varEnd = std::max( varEnd, i ); From bf3358dcaed147300ada646970e06d1ba7a38fd3 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 8 Oct 2026 16:26:24 +0000 Subject: [PATCH 66/83] Turret data --- CMakeLists.txt | 1 + .../Carbon/SpaceScene/EveTurretSet.fxh | 103 ++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/EveTurretSet.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index be1d1b645..eab0c27d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -165,6 +165,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveTransform.fxh shaders/include/Carbon/SpaceScene/EveStretch2.fxh shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh + shaders/include/Carbon/SpaceScene/EveTurretSet.fxh shaders/include/Carbon/SpaceScene/FroxelFog.fxh shaders/include/Carbon/SpaceScene/GpuParticles.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh diff --git a/shaders/include/Carbon/SpaceScene/EveTurretSet.fxh b/shaders/include/Carbon/SpaceScene/EveTurretSet.fxh new file mode 100644 index 000000000..88e51fac0 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveTurretSet.fxh @@ -0,0 +1,103 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVETURRETSET_FXH +#define CARBON_EVETURRETSET_FXH + +#include "PerObjectData.fxh" +#include "../Math.fxh" + +#define EVE_MAX_TURRETS_PER_SET 24 + +struct EveTurrentSetPerObjectDataVS +{ + // X - "height" of the clipping plane for the turret set, Y - unused, Z - unused, W - unused + float4 ClipData; + // X - number of bones in the turret skeleton, Y - unused, Z - unused, W - unused + float4 TurretData; + // World transform of this object + float4x4 WorldMat; + // World transform of this object in the previous frame + float4x4 WorldMatLast; + // X - current frame offset, Y - previous frame offset + uint4 BoneOffsets; + // Turret instances translation data (XYZ - position, W - 1.0) + float4 TurretTrans[EVE_MAX_TURRETS_PER_SET]; + // Turret instances rotation quaternions + float4 TurretRot[EVE_MAX_TURRETS_PER_SET]; +}; + +struct EveTurrentSetPerObjectDataPS +{ + // Additional ship-data ( components: .x = boosterGain, .y = activation, .z = dirt level, .w = boundingsphere radius ) + float4 Shipdata; + // Clip data for disolve fx ( components: .xyz = center, .w = signed size ) + float4 Clipdata1; + // Misc data ( components: .x = signed square of clip radius 2, .yzw = unused ) + float4 Miscdata; + // SH lighting coefficients + float4 ShLighting[7]; +}; + + +EveSpaceObjectData CreateEveSpaceObjectData( EveTurrentSetPerObjectDataVS PerObjectVS ) +{ + EveSpaceObjectData pod; + pod.WorldMat = PerObjectVS.WorldMat; + pod.WorldMatLast = PerObjectVS.WorldMatLast; + pod.BoneOffsets = PerObjectVS.BoneOffsets; + + pod.Shipdata = (float4)0; + pod.Clipdata1 = (float4)0; + pod.Miscdata = (float4)0; + pod.EllipsoidRadii = (float4)0; + pod.EllipsoidCenter = (float4)0; + pod.CustomMaskMatrix[0] = IDENTITY_MATRIX; + pod.CustomMaskMatrix[1] = IDENTITY_MATRIX; + pod.CustomMaskData[0] = (float4)0; + pod.CustomMaskData[1] = (float4)0; + pod.CustomMaskMaterialIDs[0] = (float4)0; + pod.CustomMaskMaterialIDs[1] = (float4)0; + pod.CustomMaskTargets[0] = (float4)0; + pod.CustomMaskTargets[1] = (float4)0; + pod.CustomMaskClamps = (float4)0; + pod.CustomData = (float4)0; + // SH lighting coefficients + for( int i = 0; i < 7; ++i ) + { + pod.ShLighting[i] = (float4)0; + } + return pod; +} + + +EveSpaceObjectData CreateEveSpaceObjectData( EveTurrentSetPerObjectDataPS PerObjectPS ) +{ + EveSpaceObjectData pod; + pod.WorldMat = (float4x4)0; + pod.WorldMatLast = (float4x4)0; + pod.BoneOffsets = (uint4)0; + + pod.Shipdata = PerObjectPS.Shipdata; + pod.Clipdata1 = PerObjectPS.Clipdata1; + pod.Miscdata = PerObjectPS.Miscdata; + pod.EllipsoidRadii = (float4)0; + pod.EllipsoidCenter = (float4)0; + pod.CustomMaskMatrix[0] = IDENTITY_MATRIX; + pod.CustomMaskMatrix[1] = IDENTITY_MATRIX; + pod.CustomMaskData[0] = (float4)0; + pod.CustomMaskData[1] = (float4)0; + pod.CustomMaskMaterialIDs[0] = (float4)0; + pod.CustomMaskMaterialIDs[1] = (float4)0; + pod.CustomMaskTargets[0] = (float4)0; + pod.CustomMaskTargets[1] = (float4)0; + pod.CustomMaskClamps = (float4)0; + pod.CustomData = (float4)0; + // SH lighting coefficients + for( int i = 0; i < 7; ++i ) + { + pod.ShLighting[i] = PerObjectPS.ShLighting[i]; + } + return pod; +} + +#endif \ No newline at end of file From 5c2ebffe3b9fcd38bf380904257dfbf32c701bdf Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 09:20:14 +0000 Subject: [PATCH 67/83] Add attribution --- shaders/Managed/Space/System/Denoise1D.fx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shaders/Managed/Space/System/Denoise1D.fx b/shaders/Managed/Space/System/Denoise1D.fx index 10c45c413..684d12db2 100644 --- a/shaders/Managed/Space/System/Denoise1D.fx +++ b/shaders/Managed/Space/System/Denoise1D.fx @@ -4,6 +4,8 @@ #include "../../../include/Carbon/System.fxh" +// The code is based on https://sourceforge.net/p/g3d/code/HEAD/tree/G3D10/data-files/shader/BilateralFilter/BilateralFilter_apply.pix + Texture2D Source; Texture2D NoiseEstimate; Texture2D DepthBuffer; From abf32ef770151a68cf71011bdb3f95923fada0b3 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 09:34:44 +0000 Subject: [PATCH 68/83] EveSpherePin header --- CMakeLists.txt | 1 + .../Carbon/SpaceScene/EveSpherePin.fxh | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 shaders/include/Carbon/SpaceScene/EveSpherePin.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index eab0c27d6..c84a74663 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,6 +159,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh shaders/include/Carbon/SpaceScene/EveChildQuad.fxh shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh + shaders/include/Carbon/SpaceScene/EveSpherePin.fxh shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh shaders/include/Carbon/SpaceScene/EveStarfield.fxh diff --git a/shaders/include/Carbon/SpaceScene/EveSpherePin.fxh b/shaders/include/Carbon/SpaceScene/EveSpherePin.fxh new file mode 100644 index 000000000..c2dbf96d3 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/EveSpherePin.fxh @@ -0,0 +1,25 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_EVESPHEREPIN_FXH +#define CARBON_EVESPHEREPIN_FXH + +// Data passed from the engine to all shader stages for EveSpherePinData draw calls in "per object" constant buffer. +struct EveSpherePinData +{ + // World transform of this pin + float4x4 WorldMat; + // XYZ - pin position, W - pin radius + float4 PinPosition; + // X - pin rotation, YZW - unused + float4 PinRotation; + // RGBA - pin color + float4 PinColor; + // X - alpha testing threshold, YZW - unused + float4 PinThreshold; + // X - sin(pin radius), Y - cos(pin radius), Z - sin(pin rotation), W - cos(pin rotation) + float4 PinRadiusPrecalc; + // XY - pin UV scale, ZW - pin UV offset + float4 PinUV; +}; + +#endif \ No newline at end of file From f56b58229493d293c15ef068f7f1c6e3b8aafb24 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 10:39:29 +0000 Subject: [PATCH 69/83] Morph target helpers --- CMakeLists.txt | 1 + .../Space/System/Raytracing/SkinVertices.fx | 10 +- .../Carbon/SpaceScene/MeshMorphing.fxh | 113 ++++++++++++++++++ 3 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 shaders/include/Carbon/SpaceScene/MeshMorphing.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index c84a74663..a10e61189 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,6 +169,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/EveTurretSet.fxh shaders/include/Carbon/SpaceScene/FroxelFog.fxh shaders/include/Carbon/SpaceScene/GpuParticles.fxh + shaders/include/Carbon/SpaceScene/MeshMorphing.fxh shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh diff --git a/shaders/Managed/Space/System/Raytracing/SkinVertices.fx b/shaders/Managed/Space/System/Raytracing/SkinVertices.fx index 23a38f899..d3b40c3da 100644 --- a/shaders/Managed/Space/System/Raytracing/SkinVertices.fx +++ b/shaders/Managed/Space/System/Raytracing/SkinVertices.fx @@ -3,16 +3,10 @@ #include "../../../../include/Carbon/System.fxh" #include "../../../../include/Carbon/BoneTransforms.fxh" #include "../../../../include/Carbon/VertexBufferUtil.fxh" +#include "../../../../include/Carbon/SpaceScene/MeshMorphing.fxh" StructuredBuffer InVB; RWStructuredBuffer OutVB; - -struct AnimationData -{ - uint index; - float weight; -}; -StructuredBuffer MorphTargetAnimations ; RWBuffer BakedMorphTargetBuffer ; cbuffer PerObjectVS : register( b3 ) @@ -90,7 +84,7 @@ void SkinVertices( uint3 offset : SV_DispatchThreadID ) float3 tmpPos = pos; for( uint i = 0; i < MorphAnimationDataCount; i++ ) { - AnimationData data = MorphTargetAnimations[MorphAnimationDataOffset + i]; + MorphTargetAnimationData data = MorphTargetAnimations[MorphAnimationDataOffset + i]; int offset = morphOffset + MorphTargetSize * data.index; float3 morphPos = float3( LoadVB( offset ), LoadVB( offset + 1 ), LoadVB( offset + 2 ) ); pos += data.weight * ( morphPos - tmpPos ); diff --git a/shaders/include/Carbon/SpaceScene/MeshMorphing.fxh b/shaders/include/Carbon/SpaceScene/MeshMorphing.fxh new file mode 100644 index 000000000..41c566326 --- /dev/null +++ b/shaders/include/Carbon/SpaceScene/MeshMorphing.fxh @@ -0,0 +1,113 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_MESHMORPHING_FXH +#define CARBON_MESHMORPHING_FXH + + +#include "../VertexBufferUtil.fxh" + +Buffer SharedIndexVertexBuffer ; + +struct MorphTargetAnimationData +{ + uint index; + float weight; +}; +StructuredBuffer MorphTargetAnimations ; + +// the following assumes that all morphed objects will be preprocessed and hence packed +// it also assumes no delta compression is being used +#define MORPH_TARGERT_CONSTANT_SIZE 24 +struct MorphTargetGeometryConstants +{ + uint vertexBufferStride; + uint positionOffset; + uint positionType; + uint tangentOffset; + uint tangentType; + uint vertexCount; +}; + +MorphTargetGeometryConstants GetMorphTargetGeometryConstants( uint4 MorphTargetData ) +{ + MorphTargetGeometryConstants constants; + constants.vertexBufferStride = ReadUInt32( SharedIndexVertexBuffer, MorphTargetData.x + 0 ); + constants.positionOffset = ReadUInt32( SharedIndexVertexBuffer, MorphTargetData.x + 4 ); + constants.positionType = ReadUInt32( SharedIndexVertexBuffer, MorphTargetData.x + 8 ); + constants.tangentOffset = ReadUInt32( SharedIndexVertexBuffer, MorphTargetData.x + 12 ); + constants.tangentType = ReadUInt32( SharedIndexVertexBuffer, MorphTargetData.x + 16 ); + constants.vertexCount = ReadUInt32( SharedIndexVertexBuffer, MorphTargetData.x + 20 ); + + return constants; +} + +void ProcessMorphs( MorphTargetGeometryConstants constants, uint vertexID, uint4 MorphTargetData, inout float3 vtxPos, inout float4 vtxPackedTangent ) +{ + float normalSign = vtxPackedTangent.w; + vtxPackedTangent.w = sqrt( saturate( 1. - dot( vtxPackedTangent.xyz, vtxPackedTangent.xyz ) ) ); + + int dataOffset = MORPH_TARGERT_CONSTANT_SIZE; // MorphTargetGeometryConstants size + dataOffset += MorphTargetData.x; // offset in shared index/vertex buffer + dataOffset += vertexID * constants.vertexBufferStride; + + int posOffset = dataOffset + constants.positionOffset; + int tangentOffset = dataOffset + constants.tangentOffset; + + int morphTargetSize = constants.vertexCount * constants.vertexBufferStride; + + float3 tempPos = vtxPos; + float4 tempPackedTangent = vtxPackedTangent; + for( uint i = 0; i < MorphTargetData.z; i++ ) + { + MorphTargetAnimationData data = MorphTargetAnimations[MorphTargetData.y + i]; + int morphTargetIndex = data.index; + int offset = morphTargetSize * morphTargetIndex; + + float3 pos = ReadFloat32_3( SharedIndexVertexBuffer, posOffset + offset ); + float4 packedTangent = float4( ReadInt16_4( SharedIndexVertexBuffer, tangentOffset + offset ) ); + packedTangent = max( packedTangent * ( 1. / 32767.0f ), float4( -1.0f, -1.0f, -1.0f, -1.0f ) ); + packedTangent.w = sqrt( saturate( 1. - dot( packedTangent.xyz, packedTangent.xyz ) ) ); + + [flatten] + if( dot( packedTangent, tempPackedTangent ) < 0. ) + { + packedTangent = -packedTangent; + } + + vtxPos += data.weight * ( pos - tempPos ); + vtxPackedTangent += data.weight * ( packedTangent - tempPackedTangent ); + } + vtxPackedTangent = normalize( vtxPackedTangent ); + + [flatten] + if( vtxPackedTangent.w < 0. ) + { + vtxPackedTangent = -vtxPackedTangent; + } + + vtxPackedTangent.w = normalSign; +} + +void ProcessMorphs( MorphTargetGeometryConstants constants, uint vertexID, uint4 MorphTargetData, inout float3 vtxPos ) +{ + int dataOffset = MORPH_TARGERT_CONSTANT_SIZE; // MorphTargetGeometryConstants size + dataOffset += MorphTargetData.x; // offset in shared index/vertex buffer + dataOffset += vertexID * constants.vertexBufferStride; + + int posOffset = dataOffset + constants.positionOffset; + + int morphTargetSize = constants.vertexCount * constants.vertexBufferStride; + + float3 tempPos = vtxPos; + for( uint i = 0; i < MorphTargetData.z; i++ ) + { + MorphTargetAnimationData data = MorphTargetAnimations[MorphTargetData.y + i]; + int morphTargetIndex = data.index; + int offset = morphTargetSize * morphTargetIndex; + float3 pos = ReadFloat32_3( SharedIndexVertexBuffer, posOffset + offset ); + vtxPos += data.weight * ( pos - tempPos ); + } +} + + +#endif \ No newline at end of file From 97e7441ad32c358b2e55f3eb1bd7e6cdf7e7eb17 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 11:09:55 +0000 Subject: [PATCH 70/83] Utility shaders --- CMakeLists.txt | 17 ++++ shaders/Managed/Utility/BillboardNoZ.fx | 72 ++++++++++++++++ shaders/Managed/Utility/BillboardPicking.fx | 58 +++++++++++++ shaders/Managed/Utility/Debug.fx | 59 +++++++++++++ shaders/Managed/Utility/DebugLine.fx | 59 +++++++++++++ shaders/Managed/Utility/DebugPrimitive.fx | 85 +++++++++++++++++++ .../Managed/Utility/DebugPrimitivePicking.fx | 50 +++++++++++ shaders/Managed/Utility/Lines.fxh | 42 +++++++++ shaders/Managed/Utility/LinesNoZ.fx | 20 +++++ shaders/Managed/Utility/LinesRotationTool.fx | 59 +++++++++++++ .../Managed/Utility/LinesRotationToolLH.fx | 59 +++++++++++++ shaders/Managed/Utility/LinesWithZ.fx | 20 +++++ shaders/Managed/Utility/PerFrameVSData.fxh | 18 ++++ shaders/Managed/Utility/PrimitivePicking.fx | 56 ++++++++++++ .../Utility/SolidNoLightNoCullWithZ.fx | 48 +++++++++++ shaders/Managed/Utility/Solids.fxh | 52 ++++++++++++ shaders/Managed/Utility/SolidsNoZ.fx | 20 +++++ shaders/Managed/Utility/SolidsWithZ.fx | 20 +++++ 18 files changed, 814 insertions(+) create mode 100644 shaders/Managed/Utility/BillboardNoZ.fx create mode 100644 shaders/Managed/Utility/BillboardPicking.fx create mode 100644 shaders/Managed/Utility/Debug.fx create mode 100644 shaders/Managed/Utility/DebugLine.fx create mode 100644 shaders/Managed/Utility/DebugPrimitive.fx create mode 100644 shaders/Managed/Utility/DebugPrimitivePicking.fx create mode 100644 shaders/Managed/Utility/Lines.fxh create mode 100644 shaders/Managed/Utility/LinesNoZ.fx create mode 100644 shaders/Managed/Utility/LinesRotationTool.fx create mode 100644 shaders/Managed/Utility/LinesRotationToolLH.fx create mode 100644 shaders/Managed/Utility/LinesWithZ.fx create mode 100644 shaders/Managed/Utility/PerFrameVSData.fxh create mode 100644 shaders/Managed/Utility/PrimitivePicking.fx create mode 100644 shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx create mode 100644 shaders/Managed/Utility/Solids.fxh create mode 100644 shaders/Managed/Utility/SolidsNoZ.fx create mode 100644 shaders/Managed/Utility/SolidsWithZ.fx diff --git a/CMakeLists.txt b/CMakeLists.txt index a10e61189..edf1bc1a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -203,6 +203,23 @@ set(_SHADER_SOURCES shaders/Managed/Space/System/Denoise1D.fx shaders/Managed/Space/System/DenoiseEstimate.fx shaders/Managed/Space/System/EstimateNoise.fx + shaders/Managed/Utility/BillboardNoZ.fx + shaders/Managed/Utility/BillboardPicking.fx + shaders/Managed/Utility/Debug.fx + shaders/Managed/Utility/DebugLine.fx + shaders/Managed/Utility/DebugPrimitive.fx + shaders/Managed/Utility/DebugPrimitivePicking.fx + shaders/Managed/Utility/Lines.fxh + shaders/Managed/Utility/LinesNoZ.fx + shaders/Managed/Utility/LinesRotationTool.fx + shaders/Managed/Utility/LinesRotationToolLH.fx + shaders/Managed/Utility/LinesWithZ.fx + shaders/Managed/Utility/PerFrameVSData.fxh + shaders/Managed/Utility/PrimitivePicking.fx + shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx + shaders/Managed/Utility/Solids.fxh + shaders/Managed/Utility/SolidsNoZ.fx + shaders/Managed/Utility/SolidsWithZ.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Managed/Utility/BillboardNoZ.fx b/shaders/Managed/Utility/BillboardNoZ.fx new file mode 100644 index 000000000..76370afb2 --- /dev/null +++ b/shaders/Managed/Utility/BillboardNoZ.fx @@ -0,0 +1,72 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +Texture2D TextureMap +< + bool SasUiVisible = true; +>; + +SamplerState LinearSampler +{ + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; + +struct SolidVertex +{ + float3 position : POSITION; + float4 color : TEXCOORD0; +}; + +struct SolidVertexPS +{ + float4 position : POSITION; + float2 texCoord : TEXCOORD0; + float4 color : TEXCOORD1; +}; + +SolidVertexPS SpriteVS( SolidVertex inVtx ) +{ + SolidVertexPS outVtx; + + float3 posWorld = mul( float4( 0, 0, 0, 1 ), PerObjectVS.WorldMat ).xyz; + float3 posView = mul( float4( posWorld, 1.0f ), PerFrameVS.ViewMat ).xyz; + posView += mul( inVtx.position, (float3x3)PerObjectVS.WorldMat ); + outVtx.position = mul( float4( posView, 1.0f ), PerFrameVS.ProjectionMat ); + outVtx.color = inVtx.color; + outVtx.texCoord = inVtx.position.xy * 0.5 + 0.5; + + return outVtx; +} + +float4 SpritePS( SolidVertexPS inVtx ) : SV_Target +{ + return inVtx.color * TextureMap.Sample( LinearSampler, inVtx.texCoord ); +} + +technique Main +{ + pass P0 + { + ZWriteEnable = False; + ZEnable = False; + AlphaBlendEnable = True; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + CullMode = NONE; + + VertexShader = compile vs_5_0 SpriteVS(); + PixelShader = compile ps_5_0 SpritePS(); + } +} \ No newline at end of file diff --git a/shaders/Managed/Utility/BillboardPicking.fx b/shaders/Managed/Utility/BillboardPicking.fx new file mode 100644 index 000000000..589212d64 --- /dev/null +++ b/shaders/Managed/Utility/BillboardPicking.fx @@ -0,0 +1,58 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +struct SolidVertex +{ + float3 position : POSITION; +}; + +struct SolidVertexPS +{ + float4 position : POSITION; + float2 texCoord : TEXCOORD0; +}; + +// selected.AddTriangle((-1, -1, 0), (1,1,1,1), (1, -1, 0), (1,1,1,1), (-1, 1, 0), (1,1,1,1)) + +SolidVertexPS SpriteVS( SolidVertex inVtx ) +{ + SolidVertexPS outVtx; + + float3 posWorld = mul( float4( 0, 0, 0, 1 ), PerObjectVS.WorldMat ).xyz; + float3 posView = mul( float4( posWorld, 1.0f ), PerFrameVS.ViewMat ).xyz; + posView += mul( inVtx.position, (float3x3)PerObjectVS.WorldMat ); + outVtx.position = mul( float4( posView, 1.0f ), PerFrameVS.ProjectionMat ); + outVtx.texCoord = inVtx.position.xy * 0.5 + 0.5; + + return outVtx; +} + +float objectId = 0; +float areaId = 0; + +float4 SpritePS( SolidVertexPS inVtx ) : SV_Target +{ + return float4( areaId + 1, objectId + 1, 1, 0 ); +} + +technique Main +{ + pass P0 + { + ZWriteEnable = TRUE; + ZEnable = TRUE; + ZFunc = LESSEQUAL; + AlphaBlendEnable = FALSE; + AlphaTestEnable = FALSE; + + VertexShader = compile vs_5_0 SpriteVS(); + PixelShader = compile ps_5_0 SpritePS(); + } +} \ No newline at end of file diff --git a/shaders/Managed/Utility/Debug.fx b/shaders/Managed/Utility/Debug.fx new file mode 100644 index 000000000..0b412a43f --- /dev/null +++ b/shaders/Managed/Utility/Debug.fx @@ -0,0 +1,59 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" + +float4x4 WorldMat; +float4x4 ViewProjectionMat; + +// ------------------------------------------------------------- +// Output channels +// ------------------------------------------------------------- +struct VS_OUTPUT +{ + float4 pos : SV_Position; + float4 col : COLOR0; +}; + +// ------------------------------------------------------------- +// vertex shader function (input channels) +// ------------------------------------------------------------- +VS_OUTPUT PerVertex(float3 pos : POSITION, float4 col : COLOR0 ) +{ + VS_OUTPUT Out = (VS_OUTPUT)0; + + float4 worldpos = mul( float4( pos, 1.0f), WorldMat ); + Out.pos = mul( worldpos, ViewProjectionMat ); + Out.col = col; + return Out; +} + + +// ------------------------------------------------------------- +// Pixel Shader (input channels):output channel +// ------------------------------------------------------------- +float4 PerPixel( VS_OUTPUT inVtx ) : SV_Target +{ + return inVtx.col; +} + + +// ------------------------------------------------------------- +// +// ------------------------------------------------------------- +technique Main +{ + pass P0 + { + ZEnable = FALSE; + ZWriteEnable = TRUE; + ZFunc = LESSEQUAL; + CullMode = NONE; + AlphaBlendEnable = TRUE; + AlphaTestEnable = FALSE; + FillMode = SOLID; + + // compile shaders + VertexShader = compile vs_5_0 PerVertex(); + PixelShader = compile ps_5_0 PerPixel(); + } +} diff --git a/shaders/Managed/Utility/DebugLine.fx b/shaders/Managed/Utility/DebugLine.fx new file mode 100644 index 000000000..caa213cb3 --- /dev/null +++ b/shaders/Managed/Utility/DebugLine.fx @@ -0,0 +1,59 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" + +float4x4 WorldMat; +float4x4 ViewProjectionMat; + +// ------------------------------------------------------------- +// Output channels +// ------------------------------------------------------------- +struct VS_OUTPUT +{ + float4 pos : SV_Position; + float4 col : COLOR0; +}; + +// ------------------------------------------------------------- +// vertex shader function (input channels) +// ------------------------------------------------------------- +VS_OUTPUT PerVertex( float3 pos : POSITION, float4 col : COLOR0 ) +{ + VS_OUTPUT Out = (VS_OUTPUT)0; + + float4 worldpos = mul( float4( pos, 1.0f ), WorldMat ); + Out.pos = mul( worldpos, ViewProjectionMat ); + Out.col = col; + return Out; +} + + +// ------------------------------------------------------------- +// Pixel Shader (input channels):output channel +// ------------------------------------------------------------- +float4 PerPixel( VS_OUTPUT inVtx ) : SV_Target +{ + return inVtx.col; +} + + +// ------------------------------------------------------------- +// +// ------------------------------------------------------------- +technique Main +{ + pass P0 + { + ZEnable = FALSE; + ZWriteEnable = FALSE; + ZFunc = LESSEQUAL; + CullMode = NONE; + AlphaBlendEnable = FALSE; + AlphaTestEnable = FALSE; + FillMode = Wireframe; + + // compile shaders + VertexShader = compile vs_5_0 PerVertex(); + PixelShader = compile ps_5_0 PerPixel(); + } +} \ No newline at end of file diff --git a/shaders/Managed/Utility/DebugPrimitive.fx b/shaders/Managed/Utility/DebugPrimitive.fx new file mode 100644 index 000000000..d67d7cd65 --- /dev/null +++ b/shaders/Managed/Utility/DebugPrimitive.fx @@ -0,0 +1,85 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" +#include "../../include/Carbon/SpaceScene/PerSceneData.fxh" + +struct PerFrameVSData +{ + // matrices + float4x4 ViewInverseTransposeMat; + float4x4 ViewProjectionMat; +} PerFrameVS : register( PERFRAME_VS_STARTREGISTER ); + +EveSpaceSceneDataPS PerFramePS : register( PERFRAME_PS_STARTREGISTER ); + +struct AppDebugVtx +{ + float3 position : POSITION; + float3 normal : NORMAL; + float4 zPassColor : COLOR1; + float4 zFailColor : COLOR2; +}; + +struct DebugVtx +{ + float4 position : SV_Position; + float3 normal : TEXCOORD0; + float4 color : TEXCOORD1; + float4 colorBack : TEXCOORD2; +}; + +Texture2D DepthMap ; +sampler DepthMapSamplerClamp = sampler_state +{ + MinFilter = Point; + MagFilter = Point; + MipFilter = None; + AddressU = Clamp; + AddressV = Clamp; +}; + + +float Get3dUISceneDepthOcclusion( float4 clipPos ) +{ + float depth = clipPos.z; + float sceneDepth = DepthMap.Sample( DepthMapSamplerClamp, clipPos.xy / PerFramePS.RenderTargetData.xy ).r; + return (float)( depth > sceneDepth ); +} + + +DebugVtx DebugVS( AppDebugVtx inVtx, uniform bool front ) +{ + DebugVtx outVtx; + outVtx.position = mul( float4( inVtx.position, 1 ), PerFrameVS.ViewProjectionMat ); + outVtx.normal = inVtx.normal; + outVtx.color = inVtx.zPassColor; + outVtx.colorBack = inVtx.zFailColor; + return outVtx; +} + +float4 DebugPS( DebugVtx inVtx ) : SV_Target +{ + float4 color = lerp( inVtx.colorBack, inVtx.color, Get3dUISceneDepthOcclusion( inVtx.position ) ); + color = color.bgra; + if( any( inVtx.normal != 0 ) ) + { + float3 normal = normalize( inVtx.normal ); + float diffuse = lerp( 0.3, 1, saturate( dot( normal, 1 ) ) ); + color.rgb *= diffuse; + } + return color; +} + +technique Main +{ + pass P0 + { + ZFunc = LessEqual; + AlphaTestEnable = False; + AlphaBlendEnable = True; + SrcBlend = SrcAlpha; + DestBlend = InvSrcAlpha; + VertexShader = compile vs_3_0 DebugVS( true ); + PixelShader = compile ps_3_0 DebugPS(); + } +} \ No newline at end of file diff --git a/shaders/Managed/Utility/DebugPrimitivePicking.fx b/shaders/Managed/Utility/DebugPrimitivePicking.fx new file mode 100644 index 000000000..6bcd29ef3 --- /dev/null +++ b/shaders/Managed/Utility/DebugPrimitivePicking.fx @@ -0,0 +1,50 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" + +struct PerFrameVSData +{ + // matrices + float4x4 ViewInverseTransposeMat; + float4x4 ViewProjectionMat; +} PerFrameVS : register( PERFRAME_VS_STARTREGISTER ); + +struct AppDebugVtx +{ + float3 position : POSITION; + float2 index : TEXCOORD0; +}; + +struct DebugVtx +{ + float4 position : SV_Position; + float4 output : TEXCOORD0; +}; + + +DebugVtx DebugVS( AppDebugVtx inVtx ) +{ + DebugVtx outVtx; + outVtx.position = mul( float4( inVtx.position, 1 ), PerFrameVS.ViewProjectionMat ); + outVtx.output = float4( inVtx.index, outVtx.position.zw ); + return outVtx; +} + +float4 DebugPS( DebugVtx inVtx ) : SV_Target +{ + return float4( inVtx.output.xy, inVtx.output.z / inVtx.output.w, 0 ); +} + +technique Main +{ + pass P0 + { + ZEnable = True; + ZWriteEnable = True; + ZFunc = GreaterEqual; + AlphaTestEnable = False; + AlphaBlendEnable = False; + VertexShader = compile vs_3_0 DebugVS(); + PixelShader = compile ps_3_0 DebugPS(); + } +} \ No newline at end of file diff --git a/shaders/Managed/Utility/Lines.fxh b/shaders/Managed/Utility/Lines.fxh new file mode 100644 index 000000000..d641820d9 --- /dev/null +++ b/shaders/Managed/Utility/Lines.fxh @@ -0,0 +1,42 @@ +// Copyright © 2026 CCP ehf. + +#ifndef LINES_FXH +#define LINES_FXH + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +struct LineVertex +{ + float3 position : POSITION; + float4 color : TEXCOORD0; +}; + +struct LineVertexPS +{ + float4 position : SV_Position; + float4 color : TEXCOORD0; +}; + +LineVertexPS SpriteVS( LineVertex inVtx ) +{ + LineVertexPS outVtx; + + const float4 posWorld = mul( float4( inVtx.position, 1.0f ), PerObjectVS.WorldMat ); + outVtx.position = mul( posWorld, PerFrameVS.ViewProjectionMat ); + outVtx.color = inVtx.color; + + return outVtx; +} + +float4 SpritePS( LineVertexPS inVtx ) : COLOR +{ + return inVtx.color; +} + +#endif \ No newline at end of file diff --git a/shaders/Managed/Utility/LinesNoZ.fx b/shaders/Managed/Utility/LinesNoZ.fx new file mode 100644 index 000000000..3e949afdb --- /dev/null +++ b/shaders/Managed/Utility/LinesNoZ.fx @@ -0,0 +1,20 @@ +// Copyright © 2026 CCP ehf. + +#include "Lines.fxh" + +technique Main +{ + pass P0 + { + ZWriteEnable = TRUE; + ZEnable = FALSE; + + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + VertexShader = compile vs_3_0 SpriteVS(); + PixelShader = compile ps_3_0 SpritePS(); + } +} diff --git a/shaders/Managed/Utility/LinesRotationTool.fx b/shaders/Managed/Utility/LinesRotationTool.fx new file mode 100644 index 000000000..6b8c04c72 --- /dev/null +++ b/shaders/Managed/Utility/LinesRotationTool.fx @@ -0,0 +1,59 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +struct LineVertex +{ + float3 position : POSITION; + float4 color : TEXCOORD0; +}; + +struct LineVertexPS +{ + float4 position : SV_Position; + float4 color : TEXCOORD0; +}; + +LineVertexPS SpriteVS( LineVertex inVtx ) +{ + LineVertexPS outVtx; + const float4 posCenter = mul( float4( 0.0, 0.0, 0.0, 1.0 ), PerObjectVS.WorldMat ); + const float4 normal = float4( PerFrameVS.ViewMat[0][2], PerFrameVS.ViewMat[1][2], PerFrameVS.ViewMat[2][2], 1.0 ); + + const float4 posWorld = mul( float4( inVtx.position, 1.0f ), PerObjectVS.WorldMat ); + outVtx.position = mul( posWorld, PerFrameVS.ViewProjectionMat ); + outVtx.color = inVtx.color; + if( dot( posWorld - posCenter, normal ) < 0.0 ) + { + outVtx.color.a = 0.0; + } + + return outVtx; +} +float4 SpritePS( LineVertexPS inVtx ) : SV_Target +{ + return inVtx.color; +} + +technique Main +{ + pass P0 + { + ZWriteEnable = FALSE; + ZEnable = FALSE; + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + + VertexShader = compile vs_3_0 SpriteVS(); + PixelShader = compile ps_3_0 SpritePS(); + } +} diff --git a/shaders/Managed/Utility/LinesRotationToolLH.fx b/shaders/Managed/Utility/LinesRotationToolLH.fx new file mode 100644 index 000000000..80228ccef --- /dev/null +++ b/shaders/Managed/Utility/LinesRotationToolLH.fx @@ -0,0 +1,59 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +struct LineVertex +{ + float3 position : POSITION; + float4 color : TEXCOORD0; +}; + +struct LineVertexPS +{ + float4 position : SV_Position; + float4 color : TEXCOORD0; +}; + +LineVertexPS SpriteVS( LineVertex inVtx ) +{ + LineVertexPS outVtx; + const float4 posCenter = mul( float4( 0.0, 0.0, 0.0, 1.0 ), PerObjectVS.WorldMat ); + const float4 normal = float4( PerFrameVS.ViewMat[0][2], PerFrameVS.ViewMat[1][2], PerFrameVS.ViewMat[2][2], 1.0 ); + + const float4 posWorld = mul( float4( inVtx.position, 1.0f ), PerObjectVS.WorldMat ); + outVtx.position = mul( posWorld, PerFrameVS.ViewProjectionMat ); + outVtx.color = inVtx.color; + if( dot( posWorld - posCenter, normal ) > 0.0 ) + { + outVtx.color.a = 0.0; + } + + return outVtx; +} +float4 SpritePS( LineVertexPS inVtx ) : SV_Target +{ + return inVtx.color; +} + +technique Main +{ + pass P0 + { + ZWriteEnable = FALSE; + ZEnable = FALSE; + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + + VertexShader = compile vs_3_0 SpriteVS(); + PixelShader = compile ps_3_0 SpritePS(); + } +} diff --git a/shaders/Managed/Utility/LinesWithZ.fx b/shaders/Managed/Utility/LinesWithZ.fx new file mode 100644 index 000000000..29fdb3356 --- /dev/null +++ b/shaders/Managed/Utility/LinesWithZ.fx @@ -0,0 +1,20 @@ +// Copyright © 2026 CCP ehf. + +#include "Lines.fxh" + +technique Main +{ + pass P0 + { + ZWriteEnable = TRUE; + ZEnable = TRUE; + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + DepthBias = 0.001; + VertexShader = compile vs_3_0 SpriteVS(); + PixelShader = compile ps_3_0 SpritePS(); + } +} diff --git a/shaders/Managed/Utility/PerFrameVSData.fxh b/shaders/Managed/Utility/PerFrameVSData.fxh new file mode 100644 index 000000000..22ade7000 --- /dev/null +++ b/shaders/Managed/Utility/PerFrameVSData.fxh @@ -0,0 +1,18 @@ +// Copyright © 2026 CCP ehf. + +#ifndef PERFRAMEVSDATA_FXH +#define PERFRAMEVSDATA_FXH + +#include "../../include/Carbon/System.fxh" + +struct PerFrameVSData +{ + float4x4 ViewInverseTransposeMat; + float4 SunWorldDir; + float4 SceneFogColor; + float4x4 ViewProjectionMat; + float4x4 ViewMat; + float4x4 ProjectionMat; +} PerFrameVS : register( PERFRAME_VS_STARTREGISTER ); + +#endif \ No newline at end of file diff --git a/shaders/Managed/Utility/PrimitivePicking.fx b/shaders/Managed/Utility/PrimitivePicking.fx new file mode 100644 index 000000000..d5bc0592a --- /dev/null +++ b/shaders/Managed/Utility/PrimitivePicking.fx @@ -0,0 +1,56 @@ +// Copyright © 2026 CCP ehf. + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +float objectId = 0; +float areaId = 0; + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +struct PickingAppVtx +{ + float3 pos : POSITION; + float2 tex : TEXCOORD0; +}; + +struct StandardShaderVtx +{ + float4 posClip : SV_Position; + float4 eyeDirWorld : TEXCOORD0; + float4 texcoord01 : TEXCOORD1; +}; + +float4 PickingPS( StandardShaderVtx inVtx ) : SV_Target +{ + return float4( areaId + 1, objectId + 1, inVtx.eyeDirWorld.w, 0 ); +} + +StandardShaderVtx PickingVS( PickingAppVtx inVtx ) +{ + StandardShaderVtx outVtx = (StandardShaderVtx)0; + + float4 posWorld = mul( float4( inVtx.pos, 1.0f ), PerObjectVS.WorldMat ); + outVtx.posClip = mul( posWorld, PerFrameVS.ViewProjectionMat ); + outVtx.eyeDirWorld = mul( posWorld, PerFrameVS.ViewMat ); + outVtx.texcoord01 = float4( inVtx.tex, 0, 0 ); + return outVtx; +} + +technique Main +{ + pass P0 + { + ZWriteEnable = TRUE; + ZEnable = TRUE; + ZFunc = LESSEQUAL; + AlphaBlendEnable = FALSE; + AlphaTestEnable = FALSE; + + VertexShader = compile vs_3_0 PickingVS(); + PixelShader = compile ps_3_0 PickingPS(); + } +} diff --git a/shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx b/shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx new file mode 100644 index 000000000..bd19b9ed9 --- /dev/null +++ b/shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx @@ -0,0 +1,48 @@ +// Copyright © 2026 CCP ehf. + +#include "Solids.fxh" + +struct SolidColorVertex +{ + float3 position : POSITION; + float4 color : TEXCOORD0; +}; + +struct SolidColorVertexPS +{ + float4 position : SV_Position; + float4 color : TEXCOORD0; +}; + +SolidColorVertexPS SpriteSolidColorVS( SolidColorVertex inVtx ) +{ + SolidColorVertexPS outVtx; + + const float4 posWorld = mul( float4( inVtx.position, 1.0f ), PerObjectVS.WorldMat ); + outVtx.position = mul( posWorld, PerFrameVS.ViewProjectionMat ); + + outVtx.color = inVtx.color; + return outVtx; +} + +float4 SpriteSolidColorPS( SolidColorVertexPS inVtx ) : SV_Target +{ + return inVtx.color; +} + +technique Main +{ + pass P0 + { + ZWriteEnable = FALSE; + ZEnable = TRUE; + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + CullMode = NONE; + VertexShader = compile vs_3_0 SpriteSolidColorVS(); + PixelShader = compile ps_3_0 SpriteSolidColorPS(); + } +} diff --git a/shaders/Managed/Utility/Solids.fxh b/shaders/Managed/Utility/Solids.fxh new file mode 100644 index 000000000..b5fd50c2a --- /dev/null +++ b/shaders/Managed/Utility/Solids.fxh @@ -0,0 +1,52 @@ +// Copyright © 2026 CCP ehf. + +#ifndef SOLIDS_FXH +#define SOLIDS_FXH + +#include "../../include/Carbon/System.fxh" +#include "PerFrameVSData.fxh" + +struct PerObjectVSData +{ + float4x4 WorldMat : World; +} PerObjectVS : register( PEROBJECT_VS_STARTREGISTER ); + +struct SolidVertex +{ + float3 position : POSITION; + float3 normal : NORMAL; + float4 color : TEXCOORD0; +}; + +struct SolidVertexPS +{ + float4 position : SV_Position; + float4 color : TEXCOORD0; + float3 viewNormal : TEXCOORD1; + float3 vtxNormal : TEXCOORD2; +}; + +SolidVertexPS SpriteVS( SolidVertex inVtx ) +{ + SolidVertexPS outVtx; + + const float4 posWorld = mul( float4( inVtx.position, 1.0f ), PerObjectVS.WorldMat ); + outVtx.position = mul( posWorld, PerFrameVS.ViewProjectionMat ); + const float4 normal = float4( PerFrameVS.ViewMat[0][2], PerFrameVS.ViewMat[1][2], PerFrameVS.ViewMat[2][2], 0.0 ); + + outVtx.color = inVtx.color; + outVtx.vtxNormal = normalize( mul( float4( inVtx.normal, 0.0f ), PerObjectVS.WorldMat ).xyz ); + outVtx.viewNormal = normal.xyz; + + return outVtx; +} + +float4 SpritePS( SolidVertexPS inVtx ) : SV_Target +{ + float alpha = inVtx.color.a; + float4 color = inVtx.color * saturate( dot( inVtx.vtxNormal, inVtx.viewNormal ) ); + color.a = alpha; + return color; +} + +#endif \ No newline at end of file diff --git a/shaders/Managed/Utility/SolidsNoZ.fx b/shaders/Managed/Utility/SolidsNoZ.fx new file mode 100644 index 000000000..6e9eea3c7 --- /dev/null +++ b/shaders/Managed/Utility/SolidsNoZ.fx @@ -0,0 +1,20 @@ +// Copyright © 2026 CCP ehf. + +#include "Solids.fxh" + +technique Main +{ + pass P0 + { + ZWriteEnable = TRUE; + ZEnable = FALSE; + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + + VertexShader = compile vs_3_0 SpriteVS(); + PixelShader = compile ps_3_0 SpritePS(); + } +} \ No newline at end of file diff --git a/shaders/Managed/Utility/SolidsWithZ.fx b/shaders/Managed/Utility/SolidsWithZ.fx new file mode 100644 index 000000000..48162dad5 --- /dev/null +++ b/shaders/Managed/Utility/SolidsWithZ.fx @@ -0,0 +1,20 @@ +// Copyright © 2026 CCP ehf. + +#include "Solids.fxh" + +technique Main +{ + pass P0 + { + ZWriteEnable = TRUE; + ZEnable = TRUE; + AlphaBlendEnable = TRUE; + BlendOp = ADD; + SrcBlend = SRCALPHA; + DestBlend = INVSRCALPHA; + AlphaTestEnable = FALSE; + DepthBias = 0.0001; + VertexShader = compile vs_3_0 SpriteVS(); + PixelShader = compile ps_3_0 SpritePS(); + } +} From a14c5917e6f657ae0532f8f5e4eb85e0965a470a Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 11:40:12 +0000 Subject: [PATCH 71/83] UI shader include --- CMakeLists.txt | 1 + shaders/include/Carbon/UI/UI.fxh | 82 ++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 shaders/include/Carbon/UI/UI.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index edf1bc1a5..cf30115ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,6 +173,7 @@ set(_SHADER_SOURCES shaders/include/Carbon/SpaceScene/PerObjectData.fxh shaders/include/Carbon/SpaceScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Volumetrics.fxh + shaders/include/Carbon/UI/UI.fxh shaders/include/Carbon/Bindless.fxh shaders/include/Carbon/BoneTransforms.fxh shaders/include/Carbon/Intersections.fxh diff --git a/shaders/include/Carbon/UI/UI.fxh b/shaders/include/Carbon/UI/UI.fxh new file mode 100644 index 000000000..4c2701558 --- /dev/null +++ b/shaders/include/Carbon/UI/UI.fxh @@ -0,0 +1,82 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_UI_FXH +#define CARBON_UI_FXH + + +// The following constants mirror the Tr2SpriteObjectBlendMode enum in C++ +static const uint TR2_SBM_NONE = 0; +static const uint TR2_SBM_BLEND = 1; +static const uint TR2_SBM_ADD = 2; +static const uint TR2_SBM_ADDX2 = 3; + +static const uint S2D_TS_TILE_X = 8; +static const uint S2D_TS_TILE_Y = 16; + +static const uint S2D_RT_COLOR = 1 << 3; +static const uint S2D_RT_GLOW = 1 << 4; + + +// The following constants mirror the Tr2SpriteObjectEffect enum in C++ +static const uint TR2_SFX_FILL = 0; +static const uint TR2_SFX_FILL_AA = 1; + +static const uint TR2_SFX_COPY = 32; +static const uint TR2_SFX_DOT = 33; +static const uint TR2_SFX_NOALPHA = 34; +static const uint TR2_SFX_DROPSHADOW = 35; +static const uint TR2_SFX_OUTLINE = 36; +static const uint TR2_SFX_COLOROVERLAY = 37; +static const uint TR2_SFX_SOFTLIGHT = 38; +static const uint TR2_SFX_BLUR = 39; +static const uint TR2_SFX_BLURBACKGROUNDCOLORED = 40; +static const uint TR2_SFX_BLURBACKGROUND = 41; +static const uint TR2_SFX_GLOW = 42; +static const uint TR2_SFX_FONT = 43; +static const uint TR2_SFX_NOISEFADE = 44; + +static const uint TR2_SFX_MODULATE = 64; +static const uint TR2_SFX_MASK = 65; + +#define TR2_SS_MAX_TRANSFORM_COUNT 32 + +// x, y = 1/width, 1/height of the containing atlas texture, always +// z, w = 0.5/width, 0.5/height of the atlas texture: the shift to apply to TEX2D to sample the texel center. +float4 g_texelSizeUI0; +float4 g_texelSizeUI1; + +// x, y = width, height of the viewport in pixels +float4 UIViewportSize; + +// UI transform stack +float4x4 g_uiTransforms[TR2_SS_MAX_TRANSFORM_COUNT] : register( c5 ); + +// Vertex as it is passed from the application to the vertex shader +struct UIVertexInput +{ + // Vertex position + float3 pos : POSITION; + // Sprite color + float4 color : COLOR0; + // Outline color + float4 outlineColor : COLOR1; + // Texture coordinates for the primary texture + float2 tex0 : TEXCOORD0; + // Texture coordinates for the secondary texture + float2 tex1 : TEXCOORD1; + // Clipping rectangle for the sprite (left, top, right, bottom) + float4 clipRect : TEXCOORD2; + // Glow brightness for the sprite + float glowBrightness : TEXCOORD3; + // Threshold value for the opacity of the outline effect + float outlineThreshold : TEXCOORD4; + + // data.x : transform index + // data.y : blend mode + // data.z : sprite effect (0-2 bits), glow bit (3 bit) + // data.w : tile mode + uint4 data : BLENDINDICES; +}; + + +#endif \ No newline at end of file From 4a31f4180b65e53a34b6119d5e55d5d0d13f4092 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 13:49:56 +0000 Subject: [PATCH 72/83] Utility shaders --- CMakeLists.txt | 4 + shaders/Utility/CubeTextureViewer.fx | 81 +++++++ shaders/Utility/GeometryViewer.fx | 175 +++++++++++++++ shaders/Utility/LineGraph.fx | 43 ++++ shaders/Utility/TextureViewer.fx | 323 +++++++++++++++++++++++++++ 5 files changed, 626 insertions(+) create mode 100644 shaders/Utility/CubeTextureViewer.fx create mode 100644 shaders/Utility/GeometryViewer.fx create mode 100644 shaders/Utility/LineGraph.fx create mode 100644 shaders/Utility/TextureViewer.fx diff --git a/CMakeLists.txt b/CMakeLists.txt index cf30115ee..adac31389 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,6 +221,10 @@ set(_SHADER_SOURCES shaders/Managed/Utility/Solids.fxh shaders/Managed/Utility/SolidsNoZ.fx shaders/Managed/Utility/SolidsWithZ.fx + shaders/Utility/CubeTextureViewer.fx + shaders/Utility/GeometryViewer.fx + shaders/Utility/LineGraph.fx + shaders/Utility/TextureViewer.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) diff --git a/shaders/Utility/CubeTextureViewer.fx b/shaders/Utility/CubeTextureViewer.fx new file mode 100644 index 000000000..eee9e4eb6 --- /dev/null +++ b/shaders/Utility/CubeTextureViewer.fx @@ -0,0 +1,81 @@ +// Copyright © 2026 CCP ehf. + +#include "../include/Carbon/System.fxh" + +TextureCube Texture; +float4 ColorTransform0; +float4 ColorTransform1; +float4 ColorTransform2; +float4 ColorTransform3; +float4 MinValue; +float4 MaxValue; +float UseForceMipMap; +float ForceMipMap; +float MsaaType; + +float4x4 ViewMat; + +SamplerState AutoMipMapTexture +{ + AddressU = Border; + AddressV = Border; + BorderColor = 0; + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; +}; + +SamplerState NoMipMapTexture +{ + AddressU = Border; + AddressV = Border; + BorderColor = 0; + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; +}; + +struct BlitAppVertex +{ + float4 pos : POSITION; + float2 texCoord : TEXCOORD0; +}; + +struct BlitVertex +{ + float4 pos : SV_Position; + float2 texCoord : TEXCOORD0; +}; + + +BlitVertex BlitVS( BlitAppVertex inVtx ) +{ + BlitVertex outVtx = { inVtx.pos, inVtx.texCoord }; + return outVtx; +} + +float4 BlitPS( BlitVertex inVtx ) : SV_Target +{ + float2 pos = inVtx.texCoord * 2 - 1; + float3 viewDir = float3( pos.x, -pos.y, -1 ); + float3 dir = mul( (float3x3)ViewMat, viewDir ); + float4x4 ColorTransform = { ColorTransform0, ColorTransform1, ColorTransform2, ColorTransform3 }; + float4 color; + + color = lerp( Texture.Sample( AutoMipMapTexture, dir ), Texture.SampleLevel( NoMipMapTexture, dir, ForceMipMap ), UseForceMipMap ); + + color = mul( color, ColorTransform ); + color = ( color - MinValue ) / ( MaxValue - MinValue ); + return float4( color.rgb, 1 ); +} + +technique Main +{ + pass P0 + { + AlphaBlendEnable = False; + + VertexShader = compile vs_3_0 BlitVS(); + PixelShader = compile ps_3_0 BlitPS(); + } +} diff --git a/shaders/Utility/GeometryViewer.fx b/shaders/Utility/GeometryViewer.fx new file mode 100644 index 000000000..7971c2fd5 --- /dev/null +++ b/shaders/Utility/GeometryViewer.fx @@ -0,0 +1,175 @@ +// Copyright © 2026 CCP ehf. + +#pragma permutation(FILL_MODE, values=(FILL_SOLID, FILL_WIREFRAME, FILL_NORMALS, FILL_TANGENTS), default=FILL_WIREFRAME) +#pragma permutation(COLOR_MODE, values=(COLOR_SOLID, COLOR_LIT, COLOR_UV0, COLOR_UV1, COLOR_VERTEX_COLOR)) +#pragma permutation(TANGENT_PACKING, values=(TANGENT_NONE, TANGENT_PACKED, TANGENT_UNPACKED, TANGENT_NORMALS)) + +#include "../include/Carbon/System.fxh" +#include "../include/Carbon/Math.fxh" +#include "../include/Carbon/PackedTangents.fxh" + +struct VSIn +{ + float3 position : POSITION; +#if TANGENT_PACKING == TANGENT_PACKED + float4 tangents : TANGENT; +#elif TANGENT_PACKING == TANGENT_UNPACKED + float3 normal : NORMAL; + float3 tangent : TANGENT; + float3 binormal : BINORMAL; +#elif TANGENT_PACKING == TANGENT_NORMALS + float3 normal : NORMAL; +#endif + +#if COLOR_MODE == COLOR_UV0 + float2 texCoord : TEXCOORD0; +#elif COLOR_MODE == COLOR_UV1 + float2 texCoord : TEXCOORD1; +#elif COLOR_MODE == COLOR_VERTEX_COLOR + float4 color : COLOR; +#endif +}; + +struct VSOut +{ + float4 position : SV_Position; + float4 normal : TEXCOORD0; + float3 tangent : TEXCOORD1; + float3 bitangent : TEXCOORD2; + float3 modelPos : TEXCOORD3; +}; + +struct PerFrameVSData +{ + float4x4 ViewInverseTransposeMat; + float4x4 ViewProjectionMat; +} PerFrameVS : register( PERFRAME_VS_STARTREGISTER ); + + +TangentSpace UnpackTangentSpace( VSIn inVtx ) +{ + TangentSpace ts; +#if TANGENT_PACKING == TANGENT_PACKED + ts = UnpackTangentSpaceLegacy( inVtx.tangents ); +#elif TANGENT_PACKING == TANGENT_NORMALS + ts.normal = inVtx.normal; + ts.tangent = 0; + ts.bitangent = 0; +#elif TANGENT_PACKING == TANGENT_UNPACKED + ts.normal = inVtx.normal; + ts.tangent = inVtx.tangent; + ts.bitangent = inVtx.binormal; +#else + ts.normal = 1; + ts.tangent = 1; + ts.bitangent = 1; +#endif + return ts; +} + +VSOut VS( VSIn inVtx ) +{ + VSOut outVtx; + outVtx.position = mul( float4( inVtx.position, 1 ), PerFrameVS.ViewProjectionMat ); + outVtx.normal = 1; + outVtx.tangent = 1; + outVtx.bitangent = 1; + outVtx.modelPos = inVtx.position; +#if COLOR_MODE == COLOR_LIT || FILL_MODE == FILL_NORMALS || FILL_MODE == FILL_TANGENTS + TangentSpace ts = UnpackTangentSpace( inVtx ); + outVtx.normal.xyz = ts.normal; + outVtx.tangent = ts.tangent; + outVtx.bitangent = ts.bitangent; +#elif COLOR_MODE == COLOR_UV0 || COLOR_MODE == COLOR_UV1 + outVtx.normal.xy = inVtx.texCoord; +#elif COLOR_MODE == COLOR_VERTEX_COLOR + outVtx.normal = inVtx.color; +#endif + return outVtx; +} + +void AddVector( VSOut vertex, float3 direction, float4 color, inout LineStream triStream ) +{ + float4 p0 = mul( float4( vertex.modelPos, 1 ), PerFrameVS.ViewProjectionMat ); + float length = p0.z; + float4 p1 = mul( float4( vertex.modelPos + normalize( direction ) * length, 1 ), PerFrameVS.ViewProjectionMat ); + + VSOut p = (VSOut)0; + p.normal = color; + + triStream.RestartStrip(); + + p.position = p0; + triStream.Append( p ); + + p.position = p1; + triStream.Append( p ); +} + +[maxvertexcount( 18 )] +void GS( triangle VSOut inVtx[3], inout LineStream triStream, uint primitiveID : SV_PrimitiveID ) +{ + for( int i = 0; i < 3; ++i ) + { + VSOut vertex = inVtx[i]; + AddVector( vertex, vertex.normal.xyz, float4( 0, 0, 1, 1 ), triStream ); +#if FILL_MODE == FILL_TANGENTS + AddVector( vertex, vertex.tangent, float4( 1, 0, 0, 1 ), triStream ); + AddVector( vertex, vertex.bitangent, float4( 0, 1, 0, 1 ), triStream ); +#endif + } +} + +float4 SolidPS( VSOut inVtx ) : SV_Target +{ + return inVtx.normal; +} + +float4 PS( VSOut inVtx ) : SV_Target +{ +#if COLOR_MODE == COLOR_LIT + return saturate( dot( normalize( inVtx.normal.xyz ), normalize( float3( 1, 1, 1 ) ) ) ) * 0.9 + 0.1; +#elif COLOR_MODE == COLOR_UV0 || COLOR_MODE == COLOR_UV1 + return float4( inVtx.normal.xy, 0, 1 ); +#elif COLOR_MODE == COLOR_VERTEX_COLOR + return inVtx.normal; +#endif + return 1; +} + +technique Main +{ +#if FILL_MODE == FILL_WIREFRAME + pass p0 + { + FillMode = Solid; + ColorWriteEnable = 0; + + VertexShader = compile vs_3_0 VS(); + PixelShader = compile ps_3_0 PS(); + } + pass p1 + { + ColorWriteEnable = 0xf; + FillMode = Wireframe; + SlopeScaleDepthBias = 0.5; + + VertexShader = compile vs_3_0 VS(); + PixelShader = compile ps_3_0 PS(); + } +#elif (FILL_MODE == FILL_TANGENTS || FILL_MODE == FILL_NORMALS) && PLATFORM_SUPPORTS_GEOMETRY_SHADERS + pass p1 + { + CullMode = None; + VertexShader = compile vs_3_0 VS(); + GeometryShader = compile gs_5_0 GS(); + PixelShader = compile ps_3_0 SolidPS(); + } +#else + pass p1 + { + VertexShader = compile vs_3_0 VS(); + PixelShader = compile ps_3_0 PS(); + } +#endif +} \ No newline at end of file diff --git a/shaders/Utility/LineGraph.fx b/shaders/Utility/LineGraph.fx new file mode 100644 index 000000000..43894d488 --- /dev/null +++ b/shaders/Utility/LineGraph.fx @@ -0,0 +1,43 @@ +// Copyright © 2026 CCP ehf. + +#include "../include/Carbon/System.fxh" + +float4 lineGraphColor; +float lineGraphScale; + +struct AppVertex +{ + float2 pos : POSITION; +}; + +struct ShaderVertex +{ + float4 posClip : SV_Position; +}; + +ShaderVertex VS( AppVertex inVtx ) +{ + ShaderVertex outVtx; + outVtx.posClip.x = inVtx.pos.x; + outVtx.posClip.y = inVtx.pos.y * lineGraphScale * 2.0f - 1.0f; + outVtx.posClip.z = 0; + outVtx.posClip.w = 1; + return outVtx; +} + +float4 PS( ShaderVertex inVtx ) : SV_Target +{ + return lineGraphColor; +} + +technique Main +{ + pass P0 + { + ZEnable = False; + AlphaBlendEnable = False; + AlphaTestEnable = False; + VertexShader = compile vs_3_0 VS(); + PixelShader = compile ps_3_0 PS(); + } +} diff --git a/shaders/Utility/TextureViewer.fx b/shaders/Utility/TextureViewer.fx new file mode 100644 index 000000000..3a161719b --- /dev/null +++ b/shaders/Utility/TextureViewer.fx @@ -0,0 +1,323 @@ +// Copyright © 2026 CCP ehf. + +#pragma permutation(TEXTURE_TYPE, values=(TEXTURE_2D, TEXTURE_CUBE, TEXTURE_3D), default=TEXTURE_2D, description="Texture type") +#pragma permutation(TEXTURE_MSAA, values=(MSAA_NO, MSAA_YES), default=MSAA_NO, description="Texture MSAA type") +#pragma permutation(TEXTURE_ARRAY, values=(ARRAY_NO, ARRAY_YES), default=ARRAY_NO, description="Texture array type") +#pragma permutation(TEXTURE_FORMAT, values=(FORMAT_FLOAT, FORMAT_INT, FORMAT_UINT)) +#pragma permutation(COLOR_SPACE, values = ( LINEAR_SPACE, SRGB_SPACE, LOGARITHMIC_SPACE ) ) +#pragma permutation(CUBE_RENDERING_MODE, values=(VIEW, CROSS, ROWS, FORWARD, BACKWARD, RIGHT, LEFT, UP, DOWN), default=VIEW, description="Cube Texture Rendering Mode") + +#include "../include/Carbon/System.fxh" + + +// TODO: Support metal and CubeArrays +#if PLATFORM == PLATFORM_METAL +#define TEXTURE_ARRAY ARRAY_NO +#endif + +#if TEXTURE_ARRAY == ARRAY_NO + +#if TEXTURE_TYPE == TEXTURE_2D +#if TEXTURE_MSAA == MSAA_NO +#define _TEXTURE_TYPE Texture2D +#else // TEXTURE_MSAA == MSAA_NO +#define _TEXTURE_TYPE Texture2DMS +#endif // TEXTURE_MSAA == MSAA_NO +#elif TEXTURE_TYPE == TEXTURE_CUBE +#define _TEXTURE_TYPE TextureCube +#else // TEXTURE_TYPE +#define _TEXTURE_TYPE Texture3D +#endif // TEXTURE_TYPE + +#else // TEXTURE_ARRAY + +#if TEXTURE_TYPE == TEXTURE_2D +#if TEXTURE_MSAA == MSAA_NO +#define _TEXTURE_TYPE Texture2DArray +#else // TEXTURE_MSAA == MSAA_NO +#define _TEXTURE_TYPE Texture2DMSArray +#endif // TEXTURE_MSAA == MSAA_NO +#elif TEXTURE_TYPE == TEXTURE_CUBE +#define _TEXTURE_TYPE TextureCubeArray +#else // TEXTURE_TYPE +// There is no 3DArray +#define _TEXTURE_TYPE Texture3D +#endif // TEXTURE_TYPE + +#endif // TEXTURE_ARRAY + +#if TEXTURE_FORMAT == FORMAT_INT +#define _TEXTURE_FORMAT +#elif TEXTURE_FORMAT == FORMAT_UINT +#define _TEXTURE_FORMAT +#else +#define _TEXTURE_FORMAT +#endif + +_TEXTURE_TYPE _TEXTURE_FORMAT Texture; + +float4 ColorTransform0; +float4 ColorTransform1; +float4 ColorTransform2; +float4 ColorTransform3; +float4 MinValue; +float4 MaxValue; +float UseForceMipMap; +float ForceMipMap; +float VolumeSlice = 0; +float ArraySlice = 0; + + +float4x4 ViewMat; + +SamplerState AutoMipMapTexture +{ + AddressU = Border; + AddressV = Border; + AddressW = Clamp; + BorderColor = 0; + MinFilter = Linear; + MagFilter = Linear; + MipFilter = Linear; +}; + +SamplerState NoMipMapTexture +{ + AddressU = Border; + AddressV = Border; + AddressW = Clamp; + BorderColor = 0; + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; +}; + +struct BlitAppVertex +{ + float4 pos : POSITION; + float2 texCoord : TEXCOORD0; +}; + +struct BlitVertex +{ + float4 pos : SV_Position; + float2 texCoord : TEXCOORD0; +}; + + +BlitVertex BlitVS( BlitAppVertex inVtx ) +{ + BlitVertex outVtx = { inVtx.pos, inVtx.texCoord }; + return outVtx; +} + +float4 LinearToSRGB( float4 inColor ) +{ + float4 result; + result.r = inColor.r < 0.0031308 ? inColor.r * 12.92 : pow( saturate( inColor.r ), 1 / 2.4 ) * 1.055 - 0.055; + result.g = inColor.g < 0.0031308 ? inColor.g * 12.92 : pow( saturate( inColor.g ), 1 / 2.4 ) * 1.055 - 0.055; + result.b = inColor.b < 0.0031308 ? inColor.b * 12.92 : pow( saturate( inColor.b ), 1 / 2.4 ) * 1.055 - 0.055; + result.a = inColor.w; + return result; +} + +float4 SRGBToLinear( float4 inColor ) +{ + float4 result; + result.r = inColor.r < 0.040449936 ? inColor.r / 12.92 : pow( abs( ( inColor.r + 0.055 ) / 1.055 ), 2.4 ); + result.g = inColor.g < 0.040449936 ? inColor.g / 12.92 : pow( abs( ( inColor.g + 0.055 ) / 1.055 ), 2.4 ); + result.b = inColor.b < 0.040449936 ? inColor.b / 12.92 : pow( abs( ( inColor.b + 0.055 ) / 1.055 ), 2.4 ); + result.a = inColor.a < 0.040449936 ? inColor.a / 12.92 : pow( abs( ( inColor.a + 0.055 ) / 1.055 ), 2.4 ); + return result; +} + +float4 LogarithmicToLinearish( float4 inColor ) +{ + // Avert your eyes! Extreme HACK ahead! + return pow( abs( inColor ), float4( 0.25, 0.25, 0.25, 0.25 ) ); +} + + +#if TEXTURE_TYPE == TEXTURE_CUBE && TEXTURE_ARRAY == ARRAY_NO + +static const float3x3 POS_X_ROTATION = float3x3( 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 0.0 ); +static const float3x3 NEG_X_ROTATION = float3x3( 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0 ); +static const float3x3 POS_Z_ROTATION = float3x3( -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0 ); +static const float3x3 NEG_Z_ROTATION = float3x3( 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ); +static const float3x3 POS_Y_ROTATION = float3x3( -1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, -1.0, 0.0 ); +static const float3x3 NEG_Y_ROTATION = float3x3( -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0 ); +static const float3x3 ERROR_ROTATION = float3x3( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ); + +float3 ConvertUvToViewDir( float2 uv ) +{ + float2 pos = uv * 2 - 1; + return float3( pos.x, -pos.y, -1 ); +} +// returns the correct 3d view direction +float3 GetView( float2 uv, float2 columnRow, float2 size, float3x3 rotation ) +{ + uv -= columnRow * size; + uv /= size; + // rotate the view direction + return mul( rotation, ConvertUvToViewDir( uv ) ); +} +// returns the column and row for a specific grid size +float2 GetColumnRow( float2 uv, float columns, float rows ) +{ + return float2( floor( uv.x * columns ), floor( uv.y * rows ) ); +} +// moves a float value to a new min max +float MoveValueToRange( float2 oldMinMax, float2 newMinMax, float value ) +{ + return newMinMax.x + ( newMinMax.y - newMinMax.x ) / ( oldMinMax.y - oldMinMax.x ) * ( value - oldMinMax.x ); +} +// returns a +float4 CubeColor( float2 uv ) +{ + float3 viewDir; +#if CUBE_RENDERING_MODE == CROSS + // up + // left forward right back + // down + float gutter = 1.0 / 8.0; + if( uv.y < gutter || uv.y > 1.0 - gutter ) + { + // gutter + return float4( 0, 0, 0, 0 ); + } + // rejig the uv to go from float2([0-1], [gutter - (1 - gutter)]) to float2([0-1], [0-1]) + float2 transformedUv = float2( uv.x, MoveValueToRange( float2( gutter, 1.0 - gutter ), float2( 0, 1 ), uv.y ) ); + float3x3 ROTATION_MATRICES[12] = + { + ERROR_ROTATION, POS_Y_ROTATION, ERROR_ROTATION, ERROR_ROTATION, + NEG_X_ROTATION, POS_Z_ROTATION, POS_X_ROTATION, NEG_Z_ROTATION, + ERROR_ROTATION, NEG_Y_ROTATION, ERROR_ROTATION, ERROR_ROTATION + }; + float2 gridSize = float2( 4.0, 3.0 ); + float2 columnRow = GetColumnRow( transformedUv, gridSize.x, gridSize.y ); + + float3x3 rotation = ROTATION_MATRICES[columnRow.x + 4 * columnRow.y]; + // check the dead zone + if( !any( mul( rotation, float3( 1, 1, 1 ) ) ) ) + { + return float4( 0, 0, 0, 0 ); + } + viewDir = GetView( transformedUv, columnRow, 1.0 / gridSize, rotation ); +#elif CUBE_RENDERING_MODE == ROWS + // recalculate the direction to show all rows + // left right up + // forward back down + float gutter = 1.0 / 6.0; + if(uv.y < gutter || uv.y > 1.0 - gutter ) + { + // gutter + return float4(0, 0, 0, 0); + } + + float3x3 ROTATION_MATRICES[6] = { + NEG_X_ROTATION, POS_X_ROTATION, POS_Y_ROTATION, + POS_Z_ROTATION, NEG_Z_ROTATION, NEG_Y_ROTATION + }; + // rejig the uv to go from float2([0-1], [gutter - (1 - gutter)]) to float2([0-1], [0-1]) + float2 transformedUv = float2(uv.x, MoveValueToRange(float2(gutter, 1.0 - gutter), float2(0, 1), uv.y)); + float2 gridSize = float2(3.0, 2.0); + float2 columnRow = GetColumnRow(transformedUv, gridSize.x, gridSize.y); + viewDir = GetView(transformedUv, columnRow, 1.0 / gridSize, ROTATION_MATRICES[columnRow.x + 3 * columnRow.y]); +#elif CUBE_RENDERING_MODE == FORWARD + // recalculate the direction to show only -z + viewDir = mul( POS_Z_ROTATION, ConvertUvToViewDir(uv) ); +#elif CUBE_RENDERING_MODE == BACKWARD + // recalculate the direction to show only z + viewDir = mul( NEG_Z_ROTATION, ConvertUvToViewDir(uv) ); + +#elif CUBE_RENDERING_MODE == RIGHT + // recalculate the direction to show only x + viewDir = mul( POS_X_ROTATION, ConvertUvToViewDir(uv) ); + +#elif CUBE_RENDERING_MODE == LEFT + // recalculate the direction to show only -x + viewDir = mul( NEG_X_ROTATION, ConvertUvToViewDir(uv) ); + +#elif CUBE_RENDERING_MODE == UP + // recalculate the direction to show only y + viewDir = mul( POS_Y_ROTATION, ConvertUvToViewDir(uv) ); + +#elif CUBE_RENDERING_MODE == DOWN + // recalculate the direction to show only -y + viewDir = mul( NEG_Y_ROTATION, ConvertUvToViewDir(uv) ); +#else // CUBE + viewDir = mul( ( float3x3 )ViewMat, ConvertUvToViewDir(uv) ); +#endif + return lerp( Texture.Sample( AutoMipMapTexture, viewDir ), Texture.SampleLevel( NoMipMapTexture, viewDir, ForceMipMap ), UseForceMipMap ); +} +#endif + + +float4 BlitPS( BlitVertex inVtx ) : COLOR +{ + float2 UV = inVtx.texCoord; // * Zoom.xy + Zoom.zw; + float4x4 ColorTransform = { ColorTransform0, ColorTransform1, ColorTransform2, ColorTransform3 }; + float4 color; + +#if TEXTURE_TYPE == TEXTURE_2D +#if TEXTURE_MSAA == MSAA_YES + uint w, h, d, s; +#if TEXTURE_ARRAY == ARRAY_NO + Texture.GetDimensions( w, h, d ); + color = float4( Texture.Load( UV * float2( w, h ), 0 ) ); +#else + Texture.GetDimensions( w, h, d, s ); + color = float4( Texture.Load( float3(UV * float2( w, h ), ArraySlice), 0 ) ); +#endif +#elif ( TEXTURE_FORMAT == FORMAT_INT || TEXTURE_FORMAT == FORMAT_UINT || TEXTURE_ARRAY == ARRAY_YES ) + uint w, h, d; + uint mip = UseForceMipMap ? ForceMipMap : 0; +#if TEXTURE_ARRAY == ARRAY_NO + Texture.GetDimensions( w, h ); + color = float4( Texture.Load( float3( UV * float2( w, h ), mip ) ) ); +#else + Texture.GetDimensions( w, h, d ); + color = float4( Texture.Load( float4( UV * float2( w, h ), ArraySlice, mip ) ) ); +#endif +#else + color = lerp( Texture.Sample( AutoMipMapTexture, UV ), Texture.SampleLevel( NoMipMapTexture, UV, ForceMipMap ), UseForceMipMap ); +#endif +#elif TEXTURE_TYPE == TEXTURE_3D +#if ( TEXTURE_FORMAT == FORMAT_INT || TEXTURE_FORMAT == FORMAT_UINT ) + uint w, h, d; + Texture.GetDimensions( w, h, d ); + uint mip = UseForceMipMap ? ForceMipMap : 0; + color = float4( Texture.Load( float4( UV * float2( w, h ), VolumeSlice * d, mip ) ) ); +#else + color = lerp( Texture.Sample( AutoMipMapTexture, float3( UV, VolumeSlice ) ), Texture.SampleLevel( NoMipMapTexture, float3( UV, VolumeSlice ), ForceMipMap ), UseForceMipMap ); +#endif +#else +#if ( TEXTURE_FORMAT == FORMAT_INT || TEXTURE_FORMAT == FORMAT_UINT || TEXTURE_ARRAY == ARRAY_YES ) + color = 0; +#else + color = CubeColor(inVtx.texCoord); +#endif +#endif + +#if COLOR_SPACE == SRGB_SPACE + color = SRGBToLinear( color ); +#elif COLOR_SPACE == LOGARITHMIC_SPACE + color = LogarithmicToLinearish( color ); +#endif + + color = mul( color, ColorTransform ); + color = ( color - MinValue ) / ( MaxValue - MinValue ); + color = LinearToSRGB( color ); + return float4( color.rgb, 1 ); +} + +technique Main +{ + pass P0 + { + AlphaBlendEnable = False; + + VertexShader = compile vs_3_0 BlitVS(); + PixelShader = compile ps_3_0 BlitPS(); + } +} From 87a516518fa8b0b771288f544160f1a82cda304f Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 14:25:35 +0000 Subject: [PATCH 73/83] Interior includes --- CMakeLists.txt | 2 + .../Carbon/InteriorScene/PerObjectData.fxh | 59 +++++++++++++++++++ .../Carbon/InteriorScene/PerSceneData.fxh | 39 ++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 shaders/include/Carbon/InteriorScene/PerObjectData.fxh create mode 100644 shaders/include/Carbon/InteriorScene/PerSceneData.fxh diff --git a/CMakeLists.txt b/CMakeLists.txt index adac31389..f16b098c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,6 +141,8 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() set(_SHADER_SOURCES + shaders/include/Carbon/InteriorScene/PerObjectData.fxh + shaders/include/Carbon/InteriorScene/PerSceneData.fxh shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh diff --git a/shaders/include/Carbon/InteriorScene/PerObjectData.fxh b/shaders/include/Carbon/InteriorScene/PerObjectData.fxh new file mode 100644 index 000000000..e17020513 --- /dev/null +++ b/shaders/include/Carbon/InteriorScene/PerObjectData.fxh @@ -0,0 +1,59 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_INTERIOR_PEROBJECTDATA_FXH +#define CARBON_INTERIOR_PEROBJECTDATA_FXH + +#include "../System.fxh" + +// Constant buffer format for per-object data for interior scene objects. This data is provided by the engine to the vertex shader stage. +struct InteriorObjectDataVS +{ + // World transform of this object + float4x4 WorldMat; + float4 boundingBoxData; +}; + +struct InteriorSkinnedObjectDataVS +{ + // Set this up as a column-major 4x3 matrix, which is like a + // row-major 3x4. This allows us to use the same mul syntax + // as we normally do, but still allow packing of a 3x4 into + // 3 registers. + column_major float4x3 JointMat[69]; + float4x4 WorldMat; + float3 WorldPos; +}; + + +// interior +struct InteriorObjectLightData +{ + float4 position; // position in [x,y,z], radius in [w] + float4 color; // color in [r,g,b], falloff in [a] + float4 exData; // additional data: [x] = shadow0 influence, [y] = shadow1 influence, [z] = cos of spotlight outer cone alpha, [w] = cos of spotlight inner cone alpha + // or box light's world to box transform row 1 for box lights + float4 spotDirection; // spotlight's direction: [x,y,z} = normalized direction + // or box light's world to box transform row 2 for box lights + float4 boxTransformRow3; // box light's world to box transform row 3 + float4 boxTransformRow4; // box light's world to box transform row 4 +}; + +#define NUM_INTERIORLIGHTS 10 + +// Constant buffer format for per-object data for interior scene objects. This data is provided by the engine to the pixel shader stage. +struct InteriorObjectDataPS +{ + int4 pointLightsCount; // yzw - unused + + // data on lights + InteriorObjectLightData lights[NUM_INTERIORLIGHTS]; + // data on the shadow casting point lights: [x,y,z] = position, [w] = radius + float4 shadowCaster0; + float4 shadowCaster1; + // spotlight view projection matrices + float4x4 spotLights[4]; +}; + + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/InteriorScene/PerSceneData.fxh b/shaders/include/Carbon/InteriorScene/PerSceneData.fxh new file mode 100644 index 000000000..a5452c3a1 --- /dev/null +++ b/shaders/include/Carbon/InteriorScene/PerSceneData.fxh @@ -0,0 +1,39 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_INTERIOR_PERSCENEDATA_FXH +#define CARBON_INTERIOR_PERSCENEDATA_FXH + + +#include "../System.fxh" + + +// Per-scene (per-frame) constant buffer data for the vertex shader. +struct InteriorSceneDataVS +{ + float4x4 ViewInverseTransposeMat; + float4 sunDirWorld; + float4 sceneFogColor; + + float4x4 ViewProjectionMat; + float4x4 ViewMat; + float4x4 ProjectionMat; +}; + +// Per-scene (per-frame) constant buffer data for the pixel shader. +struct InteriorSceneDataPS +{ + float4x4 ViewInverseTransposeMat; + float4 sceneAmbientColor; + float4 sceneFogColor; + float4 sunDirWorld; + float4 sunDiffuseColor; + float4 sunSpecularColor; + float4 fogValues; // x = maxFogAmount, y = maxFogDistance, z = minFogDistance, w unused + float4x4 ViewProjectionMat; + float4 misc; // x = Global spherical harmonic scale factor, y = shadow count, z = inv.shadow size, w = radius + float4 viewPort; // xy - viewport width/height, zw - viewport offset + float4x4 ViewProjInverse; +}; + + +#endif \ No newline at end of file From 6a14aa849f9ccb82c3edcc471ab5274696109dfb Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 14:38:12 +0000 Subject: [PATCH 74/83] Moved shaders into src directory --- .../Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx | 0 shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx | 0 shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx | 0 .../Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx | 0 .../Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx | 0 shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx | 0 .../{ => src}/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx | 0 .../{ => src}/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx | 0 shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Update.fx | 0 .../Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx | 0 .../Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx | 0 .../Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx | 0 .../Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx | 0 .../Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx | 0 .../Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx | 0 shaders/{ => src}/Managed/Space/System/ComputeLightLists.fx | 0 shaders/{ => src}/Managed/Space/System/Denoise1D.fx | 0 shaders/{ => src}/Managed/Space/System/DenoiseEstimate.fx | 0 shaders/{ => src}/Managed/Space/System/EstimateNoise.fx | 0 shaders/{ => src}/Managed/Space/System/Raytracing/SkinVertices.fx | 0 shaders/{ => src}/Managed/Utility/BillboardNoZ.fx | 0 shaders/{ => src}/Managed/Utility/BillboardPicking.fx | 0 shaders/{ => src}/Managed/Utility/Debug.fx | 0 shaders/{ => src}/Managed/Utility/DebugLine.fx | 0 shaders/{ => src}/Managed/Utility/DebugPrimitive.fx | 0 shaders/{ => src}/Managed/Utility/DebugPrimitivePicking.fx | 0 shaders/{ => src}/Managed/Utility/Lines.fxh | 0 shaders/{ => src}/Managed/Utility/LinesNoZ.fx | 0 shaders/{ => src}/Managed/Utility/LinesRotationTool.fx | 0 shaders/{ => src}/Managed/Utility/LinesRotationToolLH.fx | 0 shaders/{ => src}/Managed/Utility/LinesWithZ.fx | 0 shaders/{ => src}/Managed/Utility/PerFrameVSData.fxh | 0 shaders/{ => src}/Managed/Utility/PrimitivePicking.fx | 0 shaders/{ => src}/Managed/Utility/SolidNoLightNoCullWithZ.fx | 0 shaders/{ => src}/Managed/Utility/Solids.fxh | 0 shaders/{ => src}/Managed/Utility/SolidsNoZ.fx | 0 shaders/{ => src}/Managed/Utility/SolidsWithZ.fx | 0 shaders/{ => src}/Utility/CubeTextureViewer.fx | 0 shaders/{ => src}/Utility/GeometryViewer.fx | 0 shaders/{ => src}/Utility/LineGraph.fx | 0 shaders/{ => src}/Utility/TextureViewer.fx | 0 41 files changed, 0 insertions(+), 0 deletions(-) rename shaders/{ => src}/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Particles/Gpu/Update.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx (100%) rename shaders/{ => src}/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx (100%) rename shaders/{ => src}/Managed/Space/System/ComputeLightLists.fx (100%) rename shaders/{ => src}/Managed/Space/System/Denoise1D.fx (100%) rename shaders/{ => src}/Managed/Space/System/DenoiseEstimate.fx (100%) rename shaders/{ => src}/Managed/Space/System/EstimateNoise.fx (100%) rename shaders/{ => src}/Managed/Space/System/Raytracing/SkinVertices.fx (100%) rename shaders/{ => src}/Managed/Utility/BillboardNoZ.fx (100%) rename shaders/{ => src}/Managed/Utility/BillboardPicking.fx (100%) rename shaders/{ => src}/Managed/Utility/Debug.fx (100%) rename shaders/{ => src}/Managed/Utility/DebugLine.fx (100%) rename shaders/{ => src}/Managed/Utility/DebugPrimitive.fx (100%) rename shaders/{ => src}/Managed/Utility/DebugPrimitivePicking.fx (100%) rename shaders/{ => src}/Managed/Utility/Lines.fxh (100%) rename shaders/{ => src}/Managed/Utility/LinesNoZ.fx (100%) rename shaders/{ => src}/Managed/Utility/LinesRotationTool.fx (100%) rename shaders/{ => src}/Managed/Utility/LinesRotationToolLH.fx (100%) rename shaders/{ => src}/Managed/Utility/LinesWithZ.fx (100%) rename shaders/{ => src}/Managed/Utility/PerFrameVSData.fxh (100%) rename shaders/{ => src}/Managed/Utility/PrimitivePicking.fx (100%) rename shaders/{ => src}/Managed/Utility/SolidNoLightNoCullWithZ.fx (100%) rename shaders/{ => src}/Managed/Utility/Solids.fxh (100%) rename shaders/{ => src}/Managed/Utility/SolidsNoZ.fx (100%) rename shaders/{ => src}/Managed/Utility/SolidsWithZ.fx (100%) rename shaders/{ => src}/Utility/CubeTextureViewer.fx (100%) rename shaders/{ => src}/Utility/GeometryViewer.fx (100%) rename shaders/{ => src}/Utility/LineGraph.fx (100%) rename shaders/{ => src}/Utility/TextureViewer.fx (100%) diff --git a/shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx b/shaders/src/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx rename to shaders/src/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx b/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Update.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx rename to shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Update.fx diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx b/shaders/src/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx rename to shaders/src/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx b/shaders/src/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx rename to shaders/src/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx b/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx rename to shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx b/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx rename to shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx b/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx rename to shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx diff --git a/shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx b/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx similarity index 100% rename from shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx rename to shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx diff --git a/shaders/Managed/Space/System/ComputeLightLists.fx b/shaders/src/Managed/Space/System/ComputeLightLists.fx similarity index 100% rename from shaders/Managed/Space/System/ComputeLightLists.fx rename to shaders/src/Managed/Space/System/ComputeLightLists.fx diff --git a/shaders/Managed/Space/System/Denoise1D.fx b/shaders/src/Managed/Space/System/Denoise1D.fx similarity index 100% rename from shaders/Managed/Space/System/Denoise1D.fx rename to shaders/src/Managed/Space/System/Denoise1D.fx diff --git a/shaders/Managed/Space/System/DenoiseEstimate.fx b/shaders/src/Managed/Space/System/DenoiseEstimate.fx similarity index 100% rename from shaders/Managed/Space/System/DenoiseEstimate.fx rename to shaders/src/Managed/Space/System/DenoiseEstimate.fx diff --git a/shaders/Managed/Space/System/EstimateNoise.fx b/shaders/src/Managed/Space/System/EstimateNoise.fx similarity index 100% rename from shaders/Managed/Space/System/EstimateNoise.fx rename to shaders/src/Managed/Space/System/EstimateNoise.fx diff --git a/shaders/Managed/Space/System/Raytracing/SkinVertices.fx b/shaders/src/Managed/Space/System/Raytracing/SkinVertices.fx similarity index 100% rename from shaders/Managed/Space/System/Raytracing/SkinVertices.fx rename to shaders/src/Managed/Space/System/Raytracing/SkinVertices.fx diff --git a/shaders/Managed/Utility/BillboardNoZ.fx b/shaders/src/Managed/Utility/BillboardNoZ.fx similarity index 100% rename from shaders/Managed/Utility/BillboardNoZ.fx rename to shaders/src/Managed/Utility/BillboardNoZ.fx diff --git a/shaders/Managed/Utility/BillboardPicking.fx b/shaders/src/Managed/Utility/BillboardPicking.fx similarity index 100% rename from shaders/Managed/Utility/BillboardPicking.fx rename to shaders/src/Managed/Utility/BillboardPicking.fx diff --git a/shaders/Managed/Utility/Debug.fx b/shaders/src/Managed/Utility/Debug.fx similarity index 100% rename from shaders/Managed/Utility/Debug.fx rename to shaders/src/Managed/Utility/Debug.fx diff --git a/shaders/Managed/Utility/DebugLine.fx b/shaders/src/Managed/Utility/DebugLine.fx similarity index 100% rename from shaders/Managed/Utility/DebugLine.fx rename to shaders/src/Managed/Utility/DebugLine.fx diff --git a/shaders/Managed/Utility/DebugPrimitive.fx b/shaders/src/Managed/Utility/DebugPrimitive.fx similarity index 100% rename from shaders/Managed/Utility/DebugPrimitive.fx rename to shaders/src/Managed/Utility/DebugPrimitive.fx diff --git a/shaders/Managed/Utility/DebugPrimitivePicking.fx b/shaders/src/Managed/Utility/DebugPrimitivePicking.fx similarity index 100% rename from shaders/Managed/Utility/DebugPrimitivePicking.fx rename to shaders/src/Managed/Utility/DebugPrimitivePicking.fx diff --git a/shaders/Managed/Utility/Lines.fxh b/shaders/src/Managed/Utility/Lines.fxh similarity index 100% rename from shaders/Managed/Utility/Lines.fxh rename to shaders/src/Managed/Utility/Lines.fxh diff --git a/shaders/Managed/Utility/LinesNoZ.fx b/shaders/src/Managed/Utility/LinesNoZ.fx similarity index 100% rename from shaders/Managed/Utility/LinesNoZ.fx rename to shaders/src/Managed/Utility/LinesNoZ.fx diff --git a/shaders/Managed/Utility/LinesRotationTool.fx b/shaders/src/Managed/Utility/LinesRotationTool.fx similarity index 100% rename from shaders/Managed/Utility/LinesRotationTool.fx rename to shaders/src/Managed/Utility/LinesRotationTool.fx diff --git a/shaders/Managed/Utility/LinesRotationToolLH.fx b/shaders/src/Managed/Utility/LinesRotationToolLH.fx similarity index 100% rename from shaders/Managed/Utility/LinesRotationToolLH.fx rename to shaders/src/Managed/Utility/LinesRotationToolLH.fx diff --git a/shaders/Managed/Utility/LinesWithZ.fx b/shaders/src/Managed/Utility/LinesWithZ.fx similarity index 100% rename from shaders/Managed/Utility/LinesWithZ.fx rename to shaders/src/Managed/Utility/LinesWithZ.fx diff --git a/shaders/Managed/Utility/PerFrameVSData.fxh b/shaders/src/Managed/Utility/PerFrameVSData.fxh similarity index 100% rename from shaders/Managed/Utility/PerFrameVSData.fxh rename to shaders/src/Managed/Utility/PerFrameVSData.fxh diff --git a/shaders/Managed/Utility/PrimitivePicking.fx b/shaders/src/Managed/Utility/PrimitivePicking.fx similarity index 100% rename from shaders/Managed/Utility/PrimitivePicking.fx rename to shaders/src/Managed/Utility/PrimitivePicking.fx diff --git a/shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx b/shaders/src/Managed/Utility/SolidNoLightNoCullWithZ.fx similarity index 100% rename from shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx rename to shaders/src/Managed/Utility/SolidNoLightNoCullWithZ.fx diff --git a/shaders/Managed/Utility/Solids.fxh b/shaders/src/Managed/Utility/Solids.fxh similarity index 100% rename from shaders/Managed/Utility/Solids.fxh rename to shaders/src/Managed/Utility/Solids.fxh diff --git a/shaders/Managed/Utility/SolidsNoZ.fx b/shaders/src/Managed/Utility/SolidsNoZ.fx similarity index 100% rename from shaders/Managed/Utility/SolidsNoZ.fx rename to shaders/src/Managed/Utility/SolidsNoZ.fx diff --git a/shaders/Managed/Utility/SolidsWithZ.fx b/shaders/src/Managed/Utility/SolidsWithZ.fx similarity index 100% rename from shaders/Managed/Utility/SolidsWithZ.fx rename to shaders/src/Managed/Utility/SolidsWithZ.fx diff --git a/shaders/Utility/CubeTextureViewer.fx b/shaders/src/Utility/CubeTextureViewer.fx similarity index 100% rename from shaders/Utility/CubeTextureViewer.fx rename to shaders/src/Utility/CubeTextureViewer.fx diff --git a/shaders/Utility/GeometryViewer.fx b/shaders/src/Utility/GeometryViewer.fx similarity index 100% rename from shaders/Utility/GeometryViewer.fx rename to shaders/src/Utility/GeometryViewer.fx diff --git a/shaders/Utility/LineGraph.fx b/shaders/src/Utility/LineGraph.fx similarity index 100% rename from shaders/Utility/LineGraph.fx rename to shaders/src/Utility/LineGraph.fx diff --git a/shaders/Utility/TextureViewer.fx b/shaders/src/Utility/TextureViewer.fx similarity index 100% rename from shaders/Utility/TextureViewer.fx rename to shaders/src/Utility/TextureViewer.fx From 3e04b30f5444b19b74e01796f279da44e1bee5f4 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 9 Oct 2026 14:48:51 +0000 Subject: [PATCH 75/83] Sparate CMakeLists.txt for shaders --- CMakeLists.txt | 97 +------------------------------------- shaders/CMakeLists.txt | 103 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 96 deletions(-) create mode 100644 shaders/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index f16b098c6..cf3c24a45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,7 @@ endif () add_subdirectory(trinityal) add_subdirectory(trinity) +add_subdirectory(shaders) if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) # Determine if/when to generate/build documentation. The rules are as follows: @@ -140,99 +141,3 @@ if(CMAKE_PROJECT_NAME STREQUAL carbon-trinity AND NOT BUILD_FOR_PYTHON_2) endif() endif() -set(_SHADER_SOURCES - shaders/include/Carbon/InteriorScene/PerObjectData.fxh - shaders/include/Carbon/InteriorScene/PerSceneData.fxh - shaders/include/Carbon/SpaceScene/Raytracing/GeometryData.fxh - shaders/include/Carbon/SpaceScene/Raytracing/ShadowData.fxh - shaders/include/Carbon/SpaceScene/BehaviorGroupBooster.fxh - shaders/include/Carbon/SpaceScene/DepthMap.fxh - shaders/include/Carbon/SpaceScene/DynamicLighting.fxh - shaders/include/Carbon/SpaceScene/EnvironmentMap.fxh - shaders/include/Carbon/SpaceScene/EveBannerSet.fxh - shaders/include/Carbon/SpaceScene/EveBoosterSet.fxh - shaders/include/Carbon/SpaceScene/EveChildBoosterSet.fxh - shaders/include/Carbon/SpaceScene/EveChildBulletStorm.fxh - shaders/include/Carbon/SpaceScene/EveChildCloud.fxh - shaders/include/Carbon/SpaceScene/EveChildCloud2.fxh - shaders/include/Carbon/SpaceScene/EveHazeSet.fxh - shaders/include/Carbon/SpaceScene/EveLensflare.fxh - shaders/include/Carbon/SpaceScene/EveOccluder.fxh - shaders/include/Carbon/SpaceScene/EvePlaneSet.fxh - shaders/include/Carbon/SpaceScene/EveChildQuad.fxh - shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh - shaders/include/Carbon/SpaceScene/EveSpherePin.fxh - shaders/include/Carbon/SpaceScene/EveSpotlightSet.fxh - shaders/include/Carbon/SpaceScene/EveSpriteSet.fxh - shaders/include/Carbon/SpaceScene/EveStarfield.fxh - shaders/include/Carbon/SpaceScene/EveTransform.fxh - shaders/include/Carbon/SpaceScene/EveStretch2.fxh - shaders/include/Carbon/SpaceScene/EveTacticalOverlay.fxh - shaders/include/Carbon/SpaceScene/EveTurretSet.fxh - shaders/include/Carbon/SpaceScene/FroxelFog.fxh - shaders/include/Carbon/SpaceScene/GpuParticles.fxh - shaders/include/Carbon/SpaceScene/MeshMorphing.fxh - shaders/include/Carbon/SpaceScene/PerObjectData.fxh - shaders/include/Carbon/SpaceScene/PerSceneData.fxh - shaders/include/Carbon/SpaceScene/Volumetrics.fxh - shaders/include/Carbon/UI/UI.fxh - shaders/include/Carbon/Bindless.fxh - shaders/include/Carbon/BoneTransforms.fxh - shaders/include/Carbon/Intersections.fxh - shaders/include/Carbon/Math.fxh - shaders/include/Carbon/PackedTangents.fxh - shaders/include/Carbon/ParticleAnnotations.fxh - shaders/include/Carbon/RandomXOrShift.fxh - shaders/include/Carbon/System.fxh - shaders/include/Carbon/Tr2CurveLineSet.fxh - shaders/include/Carbon/VertexBufferUtil.fxh - shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx - shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx - shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx - shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx - shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx - shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx - shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx - shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx - shaders/Managed/Space/System/Raytracing/SkinVertices.fx - shaders/Managed/Space/System/ComputeLightLists.fx - shaders/Managed/Space/System/Denoise1D.fx - shaders/Managed/Space/System/DenoiseEstimate.fx - shaders/Managed/Space/System/EstimateNoise.fx - shaders/Managed/Utility/BillboardNoZ.fx - shaders/Managed/Utility/BillboardPicking.fx - shaders/Managed/Utility/Debug.fx - shaders/Managed/Utility/DebugLine.fx - shaders/Managed/Utility/DebugPrimitive.fx - shaders/Managed/Utility/DebugPrimitivePicking.fx - shaders/Managed/Utility/Lines.fxh - shaders/Managed/Utility/LinesNoZ.fx - shaders/Managed/Utility/LinesRotationTool.fx - shaders/Managed/Utility/LinesRotationToolLH.fx - shaders/Managed/Utility/LinesWithZ.fx - shaders/Managed/Utility/PerFrameVSData.fxh - shaders/Managed/Utility/PrimitivePicking.fx - shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx - shaders/Managed/Utility/Solids.fxh - shaders/Managed/Utility/SolidsNoZ.fx - shaders/Managed/Utility/SolidsWithZ.fx - shaders/Utility/CubeTextureViewer.fx - shaders/Utility/GeometryViewer.fx - shaders/Utility/LineGraph.fx - shaders/Utility/TextureViewer.fx - ) - -add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) -source_group( - TREE "${CMAKE_CURRENT_SOURCE_DIR}/shaders" - FILES ${_SHADER_SOURCES} -) - -install(DIRECTORY shaders/ DESTINATION shaders) diff --git a/shaders/CMakeLists.txt b/shaders/CMakeLists.txt new file mode 100644 index 000000000..89812b3f4 --- /dev/null +++ b/shaders/CMakeLists.txt @@ -0,0 +1,103 @@ +# Copyright © 2026 CCP ehf. + +cmake_minimum_required(VERSION 3.16) + +project(TrinityShaders VERSION 1.0.0) + +set(_SHADER_SOURCES + include/Carbon/InteriorScene/PerObjectData.fxh + include/Carbon/InteriorScene/PerSceneData.fxh + include/Carbon/SpaceScene/Raytracing/GeometryData.fxh + include/Carbon/SpaceScene/Raytracing/ShadowData.fxh + include/Carbon/SpaceScene/BehaviorGroupBooster.fxh + include/Carbon/SpaceScene/DepthMap.fxh + include/Carbon/SpaceScene/DynamicLighting.fxh + include/Carbon/SpaceScene/EnvironmentMap.fxh + include/Carbon/SpaceScene/EveBannerSet.fxh + include/Carbon/SpaceScene/EveBoosterSet.fxh + include/Carbon/SpaceScene/EveChildBoosterSet.fxh + include/Carbon/SpaceScene/EveChildBulletStorm.fxh + include/Carbon/SpaceScene/EveChildCloud.fxh + include/Carbon/SpaceScene/EveChildCloud2.fxh + include/Carbon/SpaceScene/EveHazeSet.fxh + include/Carbon/SpaceScene/EveLensflare.fxh + include/Carbon/SpaceScene/EveOccluder.fxh + include/Carbon/SpaceScene/EvePlaneSet.fxh + include/Carbon/SpaceScene/EveChildQuad.fxh + include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh + include/Carbon/SpaceScene/EveSpherePin.fxh + include/Carbon/SpaceScene/EveSpotlightSet.fxh + include/Carbon/SpaceScene/EveSpriteSet.fxh + include/Carbon/SpaceScene/EveStarfield.fxh + include/Carbon/SpaceScene/EveTransform.fxh + include/Carbon/SpaceScene/EveStretch2.fxh + include/Carbon/SpaceScene/EveTacticalOverlay.fxh + include/Carbon/SpaceScene/EveTurretSet.fxh + include/Carbon/SpaceScene/FroxelFog.fxh + include/Carbon/SpaceScene/GpuParticles.fxh + include/Carbon/SpaceScene/MeshMorphing.fxh + include/Carbon/SpaceScene/PerObjectData.fxh + include/Carbon/SpaceScene/PerSceneData.fxh + include/Carbon/SpaceScene/Volumetrics.fxh + include/Carbon/UI/UI.fxh + include/Carbon/Bindless.fxh + include/Carbon/BoneTransforms.fxh + include/Carbon/Intersections.fxh + include/Carbon/Math.fxh + include/Carbon/PackedTangents.fxh + include/Carbon/ParticleAnnotations.fxh + include/Carbon/RandomXOrShift.fxh + include/Carbon/System.fxh + include/Carbon/Tr2CurveLineSet.fxh + include/Carbon/VertexBufferUtil.fxh + src/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx + src/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx + src/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx + src/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx + src/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx + src/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx + src/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx + src/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx + src/Managed/Space/SpecialFX/Particles/Gpu/Update.fx + src/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx + src/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx + src/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx + src/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx + src/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx + src/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx + src/Managed/Space/System/Raytracing/SkinVertices.fx + src/Managed/Space/System/ComputeLightLists.fx + src/Managed/Space/System/Denoise1D.fx + src/Managed/Space/System/DenoiseEstimate.fx + src/Managed/Space/System/EstimateNoise.fx + src/Managed/Utility/BillboardNoZ.fx + src/Managed/Utility/BillboardPicking.fx + src/Managed/Utility/Debug.fx + src/Managed/Utility/DebugLine.fx + src/Managed/Utility/DebugPrimitive.fx + src/Managed/Utility/DebugPrimitivePicking.fx + src/Managed/Utility/Lines.fxh + src/Managed/Utility/LinesNoZ.fx + src/Managed/Utility/LinesRotationTool.fx + src/Managed/Utility/LinesRotationToolLH.fx + src/Managed/Utility/LinesWithZ.fx + src/Managed/Utility/PerFrameVSData.fxh + src/Managed/Utility/PrimitivePicking.fx + src/Managed/Utility/SolidNoLightNoCullWithZ.fx + src/Managed/Utility/Solids.fxh + src/Managed/Utility/SolidsNoZ.fx + src/Managed/Utility/SolidsWithZ.fx + src/Utility/CubeTextureViewer.fx + src/Utility/GeometryViewer.fx + src/Utility/LineGraph.fx + src/Utility/TextureViewer.fx + ) + +add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) +source_group( + TREE "${CMAKE_CURRENT_SOURCE_DIR}" + FILES ${_SHADER_SOURCES} +) + +install(DIRECTORY shaders/include DESTINATION shaders) +install(DIRECTORY shaders/src DESTINATION shaders) From 0471a4186082eebc4927ce292b3a7a715deb2372 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 12 Oct 2026 10:26:01 +0000 Subject: [PATCH 76/83] Fix the build and address some PR comments --- shadercompiler/CachingIncludeHandler.cpp | 24 ++++++++++++++++++++++-- shadercompiler/MSLInclude.h | 7 +++++-- shadercompiler/ModifiedTime.cpp | 11 ++++++----- shadercompiler/ParserUtils.cpp | 2 +- shaders/CMakeLists.txt | 4 ++-- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/shadercompiler/CachingIncludeHandler.cpp b/shadercompiler/CachingIncludeHandler.cpp index 00f89401e..d80eadccc 100644 --- a/shadercompiler/CachingIncludeHandler.cpp +++ b/shadercompiler/CachingIncludeHandler.cpp @@ -61,6 +61,26 @@ std::optional JoinPath( const char* path1, const char* path2 ) #endif } +std::optional JoinPathAndCheckExists( const char* path1, const char* path2 ) +{ + if( auto joined = JoinPath( path1, path2 ) ) + { +#if _WIN32 + if( PathFileExists( joined->c_str() ) ) + { + return joined; + } +#else + struct stat buffer; + if( stat( joined->c_str(), &buffer ) == 0 ) + { + return joined; + } +#endif + } + return std::nullopt; +} + } @@ -110,7 +130,7 @@ std::optional CachingIncludeHandler::Open( parentPath = ""; } } - if( auto joined = JoinPath( parentPath.c_str(), fileName ) ) + if( auto joined = JoinPathAndCheckExists( parentPath.c_str(), fileName ) ) { fullPath = *joined; return true; @@ -120,7 +140,7 @@ std::optional CachingIncludeHandler::Open( auto FindSystemPath = [&]() -> bool { for( auto it = m_systemIncludePaths.begin(); it != m_systemIncludePaths.end(); ++it ) { - if( auto joined = JoinPath( it->c_str(), fileName ) ) + if( auto joined = JoinPathAndCheckExists( it->c_str(), fileName ) ) { fullPath = *joined; return true; diff --git a/shadercompiler/MSLInclude.h b/shadercompiler/MSLInclude.h index 8916757f1..df28ca854 100644 --- a/shadercompiler/MSLInclude.h +++ b/shadercompiler/MSLInclude.h @@ -335,11 +335,14 @@ void GetDimensions( texturecube tex, thread W& w, thread H& h ) template void GetDimensions( texturecube tex, uint mip, thread W& w, thread H& h, thread M& m ) { - w = W( tex.get_width() ); - h = H( tex.get_height() ); + w = W( tex.get_width( mip ) ); + h = H( tex.get_height( mip ) ); m = M( tex.get_num_mip_levels() ); } +)MSL" +R"MSL( + template void GetDimensions( texture3d tex, thread W& w, thread H& h, thread D& d ) { diff --git a/shadercompiler/ModifiedTime.cpp b/shadercompiler/ModifiedTime.cpp index b741bdd24..4dbee5566 100644 --- a/shadercompiler/ModifiedTime.cpp +++ b/shadercompiler/ModifiedTime.cpp @@ -47,7 +47,7 @@ struct HashCheckArguments std::mutex s_modifiedOutputsCS; std::set s_modifiedOutputs; -const std::regex s_include( "#[[:space:]]*include[[:space:]]*[<\"]([^>\"]*)" ); +const std::regex s_include( "#[[:space:]]*include[[:space:]]*([<\"])([^>\"]*)" ); bool IsOutputUpToDate( const char* path, const std::string& sourceHash ) { @@ -112,14 +112,14 @@ bool CheckHash( const HashCheckArguments& query ) return true; } -void GetSourceHash( const char* sourcePath, const char* parentData, const char* rootPath, std::set& visited, MD5& md5 ) +void GetSourceHash( const char* sourcePath, const char* parentData, const char* rootPath, CachingIncludeHandler::IncludeType includeType, std::set& visited, MD5& md5 ) { if( visited.find( sourcePath ) != end( visited ) ) { return; } visited.insert( sourcePath ); - if( auto opened = s_includeHandler.Open( sourcePath, CachingIncludeHandler::IncludeLocal, parentData, rootPath ) ) + if( auto opened = s_includeHandler.Open( sourcePath, includeType, parentData, rootPath ) ) { md5.add( opened->data, opened->size ); @@ -127,7 +127,8 @@ void GetSourceHash( const char* sourcePath, const char* parentData, const char* auto begin = opened->data; while( std::regex_search( begin, opened->data + opened->size, match, s_include ) ) { - GetSourceHash( match[1].str().c_str(), opened->data, rootPath, visited, md5 ); + CachingIncludeHandler::IncludeType it = match[1].str() == "<" ? CachingIncludeHandler::IncludeSystem : CachingIncludeHandler::IncludeLocal; + GetSourceHash( match[2].str().c_str(), opened->data, rootPath, it, visited, md5 ); begin += match.position() + match.length(); } } @@ -159,7 +160,7 @@ std::string GetSourceHash( const char* sourcePath, const std::vector& def md5.add( &g_generatePDB, sizeof( g_generatePDB ) ); md5.add( &g_skipOptimization, sizeof( g_skipOptimization ) ); - GetSourceHash( sourcePath, nullptr, sourcePath, visited, md5 ); + GetSourceHash( sourcePath, nullptr, sourcePath, CachingIncludeHandler::IncludeLocal, visited, md5 ); return md5.getHash(); } diff --git a/shadercompiler/ParserUtils.cpp b/shadercompiler/ParserUtils.cpp index 2d0f33e76..a3c313409 100644 --- a/shadercompiler/ParserUtils.cpp +++ b/shadercompiler/ParserUtils.cpp @@ -921,7 +921,7 @@ int GetNodeOrder( ASTNode* t ) } else { - if ( t->GetType().modifier == OP_CONST && t->GetType().storageClass == OP_STATIC ) + if( t->GetType().modifier == OP_CONST && t->GetType().storageClass == OP_STATIC ) { return 1; } diff --git a/shaders/CMakeLists.txt b/shaders/CMakeLists.txt index 89812b3f4..3f6da3262 100644 --- a/shaders/CMakeLists.txt +++ b/shaders/CMakeLists.txt @@ -99,5 +99,5 @@ source_group( FILES ${_SHADER_SOURCES} ) -install(DIRECTORY shaders/include DESTINATION shaders) -install(DIRECTORY shaders/src DESTINATION shaders) +install(DIRECTORY include DESTINATION shaders) +install(DIRECTORY src DESTINATION shaders) From 1367e6b612ed5bb28f36bd478402b9692ef81e94 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 12 Oct 2026 10:38:11 +0000 Subject: [PATCH 77/83] Formatting --- shadercompiler/MSLInclude.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shadercompiler/MSLInclude.h b/shadercompiler/MSLInclude.h index df28ca854..0bf2a50a4 100644 --- a/shadercompiler/MSLInclude.h +++ b/shadercompiler/MSLInclude.h @@ -341,7 +341,7 @@ void GetDimensions( texturecube tex, uint mip, thread W& w, thread H& h, thre } )MSL" -R"MSL( + R"MSL( template void GetDimensions( texture3d tex, thread W& w, thread H& h, thread D& d ) From e60df2d5e5e13f9f7d122665e5d8d281f5db9f02 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 12 Oct 2026 10:57:19 +0000 Subject: [PATCH 78/83] Move "src" files back up the directory so that local includes are still valid --- .../Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx | 0 shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx | 0 shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx | 0 .../Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx | 0 .../Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx | 0 shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx | 0 .../{src => }/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx | 0 .../{src => }/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx | 0 shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Update.fx | 0 .../Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx | 0 .../Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx | 0 .../Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx | 0 .../Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx | 0 .../Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx | 0 .../Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx | 0 shaders/{src => }/Managed/Space/System/ComputeLightLists.fx | 0 shaders/{src => }/Managed/Space/System/Denoise1D.fx | 0 shaders/{src => }/Managed/Space/System/DenoiseEstimate.fx | 0 shaders/{src => }/Managed/Space/System/EstimateNoise.fx | 0 shaders/{src => }/Managed/Space/System/Raytracing/SkinVertices.fx | 0 shaders/{src => }/Managed/Utility/BillboardNoZ.fx | 0 shaders/{src => }/Managed/Utility/BillboardPicking.fx | 0 shaders/{src => }/Managed/Utility/Debug.fx | 0 shaders/{src => }/Managed/Utility/DebugLine.fx | 0 shaders/{src => }/Managed/Utility/DebugPrimitive.fx | 0 shaders/{src => }/Managed/Utility/DebugPrimitivePicking.fx | 0 shaders/{src => }/Managed/Utility/Lines.fxh | 0 shaders/{src => }/Managed/Utility/LinesNoZ.fx | 0 shaders/{src => }/Managed/Utility/LinesRotationTool.fx | 0 shaders/{src => }/Managed/Utility/LinesRotationToolLH.fx | 0 shaders/{src => }/Managed/Utility/LinesWithZ.fx | 0 shaders/{src => }/Managed/Utility/PerFrameVSData.fxh | 0 shaders/{src => }/Managed/Utility/PrimitivePicking.fx | 0 shaders/{src => }/Managed/Utility/SolidNoLightNoCullWithZ.fx | 0 shaders/{src => }/Managed/Utility/Solids.fxh | 0 shaders/{src => }/Managed/Utility/SolidsNoZ.fx | 0 shaders/{src => }/Managed/Utility/SolidsWithZ.fx | 0 shaders/{src => }/Utility/CubeTextureViewer.fx | 0 shaders/{src => }/Utility/GeometryViewer.fx | 0 shaders/{src => }/Utility/LineGraph.fx | 0 shaders/{src => }/Utility/TextureViewer.fx | 0 41 files changed, 0 insertions(+), 0 deletions(-) rename shaders/{src => }/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Particles/Gpu/Update.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx (100%) rename shaders/{src => }/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx (100%) rename shaders/{src => }/Managed/Space/System/ComputeLightLists.fx (100%) rename shaders/{src => }/Managed/Space/System/Denoise1D.fx (100%) rename shaders/{src => }/Managed/Space/System/DenoiseEstimate.fx (100%) rename shaders/{src => }/Managed/Space/System/EstimateNoise.fx (100%) rename shaders/{src => }/Managed/Space/System/Raytracing/SkinVertices.fx (100%) rename shaders/{src => }/Managed/Utility/BillboardNoZ.fx (100%) rename shaders/{src => }/Managed/Utility/BillboardPicking.fx (100%) rename shaders/{src => }/Managed/Utility/Debug.fx (100%) rename shaders/{src => }/Managed/Utility/DebugLine.fx (100%) rename shaders/{src => }/Managed/Utility/DebugPrimitive.fx (100%) rename shaders/{src => }/Managed/Utility/DebugPrimitivePicking.fx (100%) rename shaders/{src => }/Managed/Utility/Lines.fxh (100%) rename shaders/{src => }/Managed/Utility/LinesNoZ.fx (100%) rename shaders/{src => }/Managed/Utility/LinesRotationTool.fx (100%) rename shaders/{src => }/Managed/Utility/LinesRotationToolLH.fx (100%) rename shaders/{src => }/Managed/Utility/LinesWithZ.fx (100%) rename shaders/{src => }/Managed/Utility/PerFrameVSData.fxh (100%) rename shaders/{src => }/Managed/Utility/PrimitivePicking.fx (100%) rename shaders/{src => }/Managed/Utility/SolidNoLightNoCullWithZ.fx (100%) rename shaders/{src => }/Managed/Utility/Solids.fxh (100%) rename shaders/{src => }/Managed/Utility/SolidsNoZ.fx (100%) rename shaders/{src => }/Managed/Utility/SolidsWithZ.fx (100%) rename shaders/{src => }/Utility/CubeTextureViewer.fx (100%) rename shaders/{src => }/Utility/GeometryViewer.fx (100%) rename shaders/{src => }/Utility/LineGraph.fx (100%) rename shaders/{src => }/Utility/TextureViewer.fx (100%) diff --git a/shaders/src/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx b/shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx rename to shaders/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Update.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Particles/Gpu/Update.fx rename to shaders/Managed/Space/SpecialFX/Particles/Gpu/Update.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx b/shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx rename to shaders/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx b/shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx rename to shaders/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx rename to shaders/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx rename to shaders/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx rename to shaders/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx diff --git a/shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx b/shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx similarity index 100% rename from shaders/src/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx rename to shaders/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx diff --git a/shaders/src/Managed/Space/System/ComputeLightLists.fx b/shaders/Managed/Space/System/ComputeLightLists.fx similarity index 100% rename from shaders/src/Managed/Space/System/ComputeLightLists.fx rename to shaders/Managed/Space/System/ComputeLightLists.fx diff --git a/shaders/src/Managed/Space/System/Denoise1D.fx b/shaders/Managed/Space/System/Denoise1D.fx similarity index 100% rename from shaders/src/Managed/Space/System/Denoise1D.fx rename to shaders/Managed/Space/System/Denoise1D.fx diff --git a/shaders/src/Managed/Space/System/DenoiseEstimate.fx b/shaders/Managed/Space/System/DenoiseEstimate.fx similarity index 100% rename from shaders/src/Managed/Space/System/DenoiseEstimate.fx rename to shaders/Managed/Space/System/DenoiseEstimate.fx diff --git a/shaders/src/Managed/Space/System/EstimateNoise.fx b/shaders/Managed/Space/System/EstimateNoise.fx similarity index 100% rename from shaders/src/Managed/Space/System/EstimateNoise.fx rename to shaders/Managed/Space/System/EstimateNoise.fx diff --git a/shaders/src/Managed/Space/System/Raytracing/SkinVertices.fx b/shaders/Managed/Space/System/Raytracing/SkinVertices.fx similarity index 100% rename from shaders/src/Managed/Space/System/Raytracing/SkinVertices.fx rename to shaders/Managed/Space/System/Raytracing/SkinVertices.fx diff --git a/shaders/src/Managed/Utility/BillboardNoZ.fx b/shaders/Managed/Utility/BillboardNoZ.fx similarity index 100% rename from shaders/src/Managed/Utility/BillboardNoZ.fx rename to shaders/Managed/Utility/BillboardNoZ.fx diff --git a/shaders/src/Managed/Utility/BillboardPicking.fx b/shaders/Managed/Utility/BillboardPicking.fx similarity index 100% rename from shaders/src/Managed/Utility/BillboardPicking.fx rename to shaders/Managed/Utility/BillboardPicking.fx diff --git a/shaders/src/Managed/Utility/Debug.fx b/shaders/Managed/Utility/Debug.fx similarity index 100% rename from shaders/src/Managed/Utility/Debug.fx rename to shaders/Managed/Utility/Debug.fx diff --git a/shaders/src/Managed/Utility/DebugLine.fx b/shaders/Managed/Utility/DebugLine.fx similarity index 100% rename from shaders/src/Managed/Utility/DebugLine.fx rename to shaders/Managed/Utility/DebugLine.fx diff --git a/shaders/src/Managed/Utility/DebugPrimitive.fx b/shaders/Managed/Utility/DebugPrimitive.fx similarity index 100% rename from shaders/src/Managed/Utility/DebugPrimitive.fx rename to shaders/Managed/Utility/DebugPrimitive.fx diff --git a/shaders/src/Managed/Utility/DebugPrimitivePicking.fx b/shaders/Managed/Utility/DebugPrimitivePicking.fx similarity index 100% rename from shaders/src/Managed/Utility/DebugPrimitivePicking.fx rename to shaders/Managed/Utility/DebugPrimitivePicking.fx diff --git a/shaders/src/Managed/Utility/Lines.fxh b/shaders/Managed/Utility/Lines.fxh similarity index 100% rename from shaders/src/Managed/Utility/Lines.fxh rename to shaders/Managed/Utility/Lines.fxh diff --git a/shaders/src/Managed/Utility/LinesNoZ.fx b/shaders/Managed/Utility/LinesNoZ.fx similarity index 100% rename from shaders/src/Managed/Utility/LinesNoZ.fx rename to shaders/Managed/Utility/LinesNoZ.fx diff --git a/shaders/src/Managed/Utility/LinesRotationTool.fx b/shaders/Managed/Utility/LinesRotationTool.fx similarity index 100% rename from shaders/src/Managed/Utility/LinesRotationTool.fx rename to shaders/Managed/Utility/LinesRotationTool.fx diff --git a/shaders/src/Managed/Utility/LinesRotationToolLH.fx b/shaders/Managed/Utility/LinesRotationToolLH.fx similarity index 100% rename from shaders/src/Managed/Utility/LinesRotationToolLH.fx rename to shaders/Managed/Utility/LinesRotationToolLH.fx diff --git a/shaders/src/Managed/Utility/LinesWithZ.fx b/shaders/Managed/Utility/LinesWithZ.fx similarity index 100% rename from shaders/src/Managed/Utility/LinesWithZ.fx rename to shaders/Managed/Utility/LinesWithZ.fx diff --git a/shaders/src/Managed/Utility/PerFrameVSData.fxh b/shaders/Managed/Utility/PerFrameVSData.fxh similarity index 100% rename from shaders/src/Managed/Utility/PerFrameVSData.fxh rename to shaders/Managed/Utility/PerFrameVSData.fxh diff --git a/shaders/src/Managed/Utility/PrimitivePicking.fx b/shaders/Managed/Utility/PrimitivePicking.fx similarity index 100% rename from shaders/src/Managed/Utility/PrimitivePicking.fx rename to shaders/Managed/Utility/PrimitivePicking.fx diff --git a/shaders/src/Managed/Utility/SolidNoLightNoCullWithZ.fx b/shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx similarity index 100% rename from shaders/src/Managed/Utility/SolidNoLightNoCullWithZ.fx rename to shaders/Managed/Utility/SolidNoLightNoCullWithZ.fx diff --git a/shaders/src/Managed/Utility/Solids.fxh b/shaders/Managed/Utility/Solids.fxh similarity index 100% rename from shaders/src/Managed/Utility/Solids.fxh rename to shaders/Managed/Utility/Solids.fxh diff --git a/shaders/src/Managed/Utility/SolidsNoZ.fx b/shaders/Managed/Utility/SolidsNoZ.fx similarity index 100% rename from shaders/src/Managed/Utility/SolidsNoZ.fx rename to shaders/Managed/Utility/SolidsNoZ.fx diff --git a/shaders/src/Managed/Utility/SolidsWithZ.fx b/shaders/Managed/Utility/SolidsWithZ.fx similarity index 100% rename from shaders/src/Managed/Utility/SolidsWithZ.fx rename to shaders/Managed/Utility/SolidsWithZ.fx diff --git a/shaders/src/Utility/CubeTextureViewer.fx b/shaders/Utility/CubeTextureViewer.fx similarity index 100% rename from shaders/src/Utility/CubeTextureViewer.fx rename to shaders/Utility/CubeTextureViewer.fx diff --git a/shaders/src/Utility/GeometryViewer.fx b/shaders/Utility/GeometryViewer.fx similarity index 100% rename from shaders/src/Utility/GeometryViewer.fx rename to shaders/Utility/GeometryViewer.fx diff --git a/shaders/src/Utility/LineGraph.fx b/shaders/Utility/LineGraph.fx similarity index 100% rename from shaders/src/Utility/LineGraph.fx rename to shaders/Utility/LineGraph.fx diff --git a/shaders/src/Utility/TextureViewer.fx b/shaders/Utility/TextureViewer.fx similarity index 100% rename from shaders/src/Utility/TextureViewer.fx rename to shaders/Utility/TextureViewer.fx From 635bfbc7c76bc0575be0dbb6c400089a6b2f502c Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Mon, 12 Oct 2026 12:44:26 +0000 Subject: [PATCH 79/83] Update shader paths --- shaders/CMakeLists.txt | 85 +++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/shaders/CMakeLists.txt b/shaders/CMakeLists.txt index 3f6da3262..d8146bab9 100644 --- a/shaders/CMakeLists.txt +++ b/shaders/CMakeLists.txt @@ -50,47 +50,47 @@ set(_SHADER_SOURCES include/Carbon/System.fxh include/Carbon/Tr2CurveLineSet.fxh include/Carbon/VertexBufferUtil.fxh - src/Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx - src/Managed/Space/SpecialFX/Particles/Gpu/Clear.fx - src/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx - src/Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx - src/Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx - src/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx - src/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx - src/Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx - src/Managed/Space/SpecialFX/Particles/Gpu/Update.fx - src/Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx - src/Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx - src/Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx - src/Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx - src/Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx - src/Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx - src/Managed/Space/System/Raytracing/SkinVertices.fx - src/Managed/Space/System/ComputeLightLists.fx - src/Managed/Space/System/Denoise1D.fx - src/Managed/Space/System/DenoiseEstimate.fx - src/Managed/Space/System/EstimateNoise.fx - src/Managed/Utility/BillboardNoZ.fx - src/Managed/Utility/BillboardPicking.fx - src/Managed/Utility/Debug.fx - src/Managed/Utility/DebugLine.fx - src/Managed/Utility/DebugPrimitive.fx - src/Managed/Utility/DebugPrimitivePicking.fx - src/Managed/Utility/Lines.fxh - src/Managed/Utility/LinesNoZ.fx - src/Managed/Utility/LinesRotationTool.fx - src/Managed/Utility/LinesRotationToolLH.fx - src/Managed/Utility/LinesWithZ.fx - src/Managed/Utility/PerFrameVSData.fxh - src/Managed/Utility/PrimitivePicking.fx - src/Managed/Utility/SolidNoLightNoCullWithZ.fx - src/Managed/Utility/Solids.fxh - src/Managed/Utility/SolidsNoZ.fx - src/Managed/Utility/SolidsWithZ.fx - src/Utility/CubeTextureViewer.fx - src/Utility/GeometryViewer.fx - src/Utility/LineGraph.fx - src/Utility/TextureViewer.fx + Managed/Space/SpecialFX/Lensflares/OccluderManagement.fx + Managed/Space/SpecialFX/Particles/Gpu/Clear.fx + Managed/Space/SpecialFX/Particles/Gpu/Emit.fx + Managed/Space/SpecialFX/Particles/Gpu/SetDrawParameters.fx + Managed/Space/SpecialFX/Particles/Gpu/SetSortArgs.fx + Managed/Space/SpecialFX/Particles/Gpu/Sort.fx + Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx + Managed/Space/SpecialFX/Particles/Gpu/SortStep.fx + Managed/Space/SpecialFX/Particles/Gpu/Update.fx + Managed/Space/SpecialFX/Volumetric/Fog/ApplyFroxels.fx + Managed/Space/SpecialFX/Volumetric/Fog/FilterFroxels.fx + Managed/Space/SpecialFX/Volumetric/Fog/RaymarchFroxels.fx + Managed/Space/SpecialFX/Volumetric/Fog/UpdateMieEnvironmentMap.fx + Managed/Space/SpecialFX/Volumetric/BlurVolumetric.fx + Managed/Space/SpecialFX/Volumetric/DownsampleDepth.fx + Managed/Space/System/Raytracing/SkinVertices.fx + Managed/Space/System/ComputeLightLists.fx + Managed/Space/System/Denoise1D.fx + Managed/Space/System/DenoiseEstimate.fx + Managed/Space/System/EstimateNoise.fx + Managed/Utility/BillboardNoZ.fx + Managed/Utility/BillboardPicking.fx + Managed/Utility/Debug.fx + Managed/Utility/DebugLine.fx + Managed/Utility/DebugPrimitive.fx + Managed/Utility/DebugPrimitivePicking.fx + Managed/Utility/Lines.fxh + Managed/Utility/LinesNoZ.fx + Managed/Utility/LinesRotationTool.fx + Managed/Utility/LinesRotationToolLH.fx + Managed/Utility/LinesWithZ.fx + Managed/Utility/PerFrameVSData.fxh + Managed/Utility/PrimitivePicking.fx + Managed/Utility/SolidNoLightNoCullWithZ.fx + Managed/Utility/Solids.fxh + Managed/Utility/SolidsNoZ.fx + Managed/Utility/SolidsWithZ.fx + Utility/CubeTextureViewer.fx + Utility/GeometryViewer.fx + Utility/LineGraph.fx + Utility/TextureViewer.fx ) add_custom_target(Shaders SOURCES ${_SHADER_SOURCES}) @@ -99,5 +99,4 @@ source_group( FILES ${_SHADER_SOURCES} ) -install(DIRECTORY include DESTINATION shaders) -install(DIRECTORY src DESTINATION shaders) +install(DIRECTORY . DESTINATION shaders FILES_MATCHING PATTERN "*.fx" PATTERN "*.fxh") From 77ee0043f105cb043b00fc564a33ec58195431c8 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Tue, 13 Oct 2026 13:01:09 +0000 Subject: [PATCH 80/83] Address PR comments --- shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx | 2 ++ shaders/Managed/Space/System/ComputeLightLists.fx | 2 +- shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx index d7c94669d..f778edf3b 100644 --- a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Emit.fx @@ -121,6 +121,8 @@ void Emit( uint3 grid : SV_GroupID, uint groupIndex : SV_GroupIndex, uint3 threa } else { + int ignored; + InterlockedAdd( ParticleCounters[0], 1, ignored ); break; } } diff --git a/shaders/Managed/Space/System/ComputeLightLists.fx b/shaders/Managed/Space/System/ComputeLightLists.fx index c4189c855..62614cb23 100644 --- a/shaders/Managed/Space/System/ComputeLightLists.fx +++ b/shaders/Managed/Space/System/ComputeLightLists.fx @@ -179,7 +179,7 @@ void AddLight( uint light, uint heapOffset, uint indexBufferSize, bool transpare uint head = iHead; head = head * 2 + heapOffset; - if( head < indexBufferSize ) + if( head + 1 < indexBufferSize ) { if( transparent ) { diff --git a/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh b/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh index f856aa356..e551c5937 100644 --- a/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh +++ b/shaders/include/Carbon/SpaceScene/EveSpaceObjectDecal.fxh @@ -47,6 +47,7 @@ EveSpaceObjectData CreateEveSpaceObjectData( EveSpaceObjectDecalDataVS perObject EveSpaceObjectData pod; pod.WorldMat = perObjectData.WorldMat; pod.WorldMatLast = (float4x4)0; + pod.InvWorldMat = perObjectData.InvWorldMat; pod.BoneOffsets = (uint4)0; pod.Shipdata = (float4)0; From 5129962bbd4af656bbc2ef399419322ca301712e Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Tue, 13 Oct 2026 14:37:51 +0000 Subject: [PATCH 81/83] Emit an error if the compiler cannot deduce a texture from the sampler state when patching dx9-style texture functions --- shadercompiler/TextureFunctionConversionDX11.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/shadercompiler/TextureFunctionConversionDX11.cpp b/shadercompiler/TextureFunctionConversionDX11.cpp index c3fa7a993..f61a52a8c 100644 --- a/shadercompiler/TextureFunctionConversionDX11.cpp +++ b/shadercompiler/TextureFunctionConversionDX11.cpp @@ -596,6 +596,7 @@ static void PatchCalls( ParserState& state, } if( texture == nullptr || texture->type.symbol ) { + state.ShowMessage( node->GetLocation(), EC_CUSTOM_ERROR, "Sampler %s is used in a dx9-style texture sampling function without a link to the texture", ToString( samplerArg->name ).c_str() ); assert( false ); return; } From 71cc9d209769e55764146d2d69e078f3c9dd5c9e Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Thu, 15 Oct 2026 09:14:02 +0000 Subject: [PATCH 82/83] Absorb new changes to shaders: picking and fog --- shaders/CMakeLists.txt | 1 + shaders/Managed/Utility/BillboardPicking.fx | 7 ++-- .../Managed/Utility/DebugPrimitivePicking.fx | 12 +++--- shaders/Managed/Utility/PrimitivePicking.fx | 6 +-- shaders/include/Carbon/Picking.fxh | 39 +++++++++++++++++++ .../Carbon/SpaceScene/PerSceneData.fxh | 2 +- .../include/Carbon/SpaceScene/Volumetrics.fxh | 1 + 7 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 shaders/include/Carbon/Picking.fxh diff --git a/shaders/CMakeLists.txt b/shaders/CMakeLists.txt index d8146bab9..38a60a771 100644 --- a/shaders/CMakeLists.txt +++ b/shaders/CMakeLists.txt @@ -46,6 +46,7 @@ set(_SHADER_SOURCES include/Carbon/Math.fxh include/Carbon/PackedTangents.fxh include/Carbon/ParticleAnnotations.fxh + include/Carbon/Picking.fxh include/Carbon/RandomXOrShift.fxh include/Carbon/System.fxh include/Carbon/Tr2CurveLineSet.fxh diff --git a/shaders/Managed/Utility/BillboardPicking.fx b/shaders/Managed/Utility/BillboardPicking.fx index 589212d64..64838521a 100644 --- a/shaders/Managed/Utility/BillboardPicking.fx +++ b/shaders/Managed/Utility/BillboardPicking.fx @@ -1,6 +1,7 @@ // Copyright © 2026 CCP ehf. #include "../../include/Carbon/System.fxh" +#include "../../include/Carbon/Picking.fxh" #include "PerFrameVSData.fxh" struct PerObjectVSData @@ -34,12 +35,10 @@ SolidVertexPS SpriteVS( SolidVertex inVtx ) return outVtx; } -float objectId = 0; -float areaId = 0; - float4 SpritePS( SolidVertexPS inVtx ) : SV_Target { - return float4( areaId + 1, objectId + 1, 1, 0 ); + // Primitive scene in Trinity uses a completely different picking scheme compared to EveSpaceScene. + return float4( areaId + 1, pickingObjectLowBits + 1, 1, 0 ); } technique Main diff --git a/shaders/Managed/Utility/DebugPrimitivePicking.fx b/shaders/Managed/Utility/DebugPrimitivePicking.fx index 6bcd29ef3..ac4458738 100644 --- a/shaders/Managed/Utility/DebugPrimitivePicking.fx +++ b/shaders/Managed/Utility/DebugPrimitivePicking.fx @@ -30,9 +30,13 @@ DebugVtx DebugVS( AppDebugVtx inVtx ) return outVtx; } -float4 DebugPS( DebugVtx inVtx ) : SV_Target +uint PickingPointerLowBits; +uint PickingPointerHighBits; +uint PickingArea; + +uint4 DebugPS( DebugVtx inVtx ) : COLOR { - return float4( inVtx.output.xy, inVtx.output.z / inVtx.output.w, 0 ); + return uint4( PickingPointerLowBits, PickingPointerHighBits, PickingArea, 0 ); } technique Main @@ -41,9 +45,7 @@ technique Main { ZEnable = True; ZWriteEnable = True; - ZFunc = GreaterEqual; - AlphaTestEnable = False; - AlphaBlendEnable = False; + ZFunc = LessEqual; VertexShader = compile vs_3_0 DebugVS(); PixelShader = compile ps_3_0 DebugPS(); } diff --git a/shaders/Managed/Utility/PrimitivePicking.fx b/shaders/Managed/Utility/PrimitivePicking.fx index d5bc0592a..aba0dfa03 100644 --- a/shaders/Managed/Utility/PrimitivePicking.fx +++ b/shaders/Managed/Utility/PrimitivePicking.fx @@ -1,10 +1,9 @@ // Copyright © 2026 CCP ehf. #include "../../include/Carbon/System.fxh" +#include "../../include/Carbon/Picking.fxh" #include "PerFrameVSData.fxh" -float objectId = 0; -float areaId = 0; struct PerObjectVSData { @@ -26,7 +25,8 @@ struct StandardShaderVtx float4 PickingPS( StandardShaderVtx inVtx ) : SV_Target { - return float4( areaId + 1, objectId + 1, inVtx.eyeDirWorld.w, 0 ); + // Primitive scene in Trinity uses a completely different picking scheme compared to EveSpaceScene. + return float4( areaId + 1, pickingObjectLowBits + 1, inVtx.eyeDirWorld.w, 0 ); } StandardShaderVtx PickingVS( PickingAppVtx inVtx ) diff --git a/shaders/include/Carbon/Picking.fxh b/shaders/include/Carbon/Picking.fxh new file mode 100644 index 000000000..43fca2b7d --- /dev/null +++ b/shaders/include/Carbon/Picking.fxh @@ -0,0 +1,39 @@ +// Copyright © 2026 CCP ehf. + +#ifndef CARBON_PICKING_FXH +#define CARBON_PICKING_FXH + +// Picking object ID (64 bits) is split into two 32-bit unsigned integers for shader compatibility. +// These variables are provided by Trinity when rendering objects for picking purposes. +// Picking pixel shader needs to forward these values to the output target. +uint pickingObjectLowBits; +uint pickingObjectHighBits; +uint areaId; + + +// The expected output of a picking pixel shader. +// To be filled with CreatePickingOutput or CreateInstancedPickingOutput functions. +struct TrinityPickingOutput +{ + uint4 pickingTarget : SV_Target; +}; + +// Creates a TrinityPickingOutput for a non-instanced object. +TrinityPickingOutput CreatePickingOutput() +{ + TrinityPickingOutput result; + result.pickingTarget = uint4( pickingObjectLowBits, pickingObjectHighBits, areaId, 0 ); + return result; +} + +// Creates a TrinityPickingOutput for an instanced object. +// Instance data is piped from the instance vertex buffer. +TrinityPickingOutput CreateInstancedPickingOutput( uint2 instanceData ) +{ + TrinityPickingOutput result; + result.pickingTarget = uint4( pickingObjectLowBits, pickingObjectHighBits, instanceData ); + return result; +} + + +#endif \ No newline at end of file diff --git a/shaders/include/Carbon/SpaceScene/PerSceneData.fxh b/shaders/include/Carbon/SpaceScene/PerSceneData.fxh index 3b022e8b1..f1b0e9951 100644 --- a/shaders/include/Carbon/SpaceScene/PerSceneData.fxh +++ b/shaders/include/Carbon/SpaceScene/PerSceneData.fxh @@ -17,7 +17,7 @@ struct FroxelPerFrameData float EnvironmentIntensity; float EnvironmentG; - float _pad0; + float FogMultiplier; float _pad1; float _pad2; diff --git a/shaders/include/Carbon/SpaceScene/Volumetrics.fxh b/shaders/include/Carbon/SpaceScene/Volumetrics.fxh index 2e4a7d476..39ff72939 100644 --- a/shaders/include/Carbon/SpaceScene/Volumetrics.fxh +++ b/shaders/include/Carbon/SpaceScene/Volumetrics.fxh @@ -158,6 +158,7 @@ float4 SampleEveSceneFroxelFog( float2 texCoords, float sceneDepth, EveSpaceScen froxel += ((1.0 - extinction) * shadowing * sceneData.FroxelFogData.EnvironmentIntensity) * (environmentLighting * sceneData.FroxelFogData.FogColor); } + froxel.rgb *= sceneData.FroxelFogData.FogMultiplier; return float4( froxel, extinction ); } From f6deb2fcc102c84e9656d8077e18e90ed4339094 Mon Sep 17 00:00:00 2001 From: Filipp Pavlov Date: Fri, 16 Oct 2026 12:45:34 +0000 Subject: [PATCH 83/83] Remove unused defines --- shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx | 1 - shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx | 1 - 2 files changed, 2 deletions(-) diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx index f5b9001a3..0c1a9f509 100644 --- a/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/Sort.fx @@ -9,7 +9,6 @@ #define HALF_SIZE 256 // (SORT_SIZE/2) #define ITERATIONS 1 // (HALF_SIZE > 1024 ? HALF_SIZE/1024 : 1) #define NUM_THREADS 256 // (HALF_SIZE/ITERATIONS) -#define INVERSION (16*2 + 8*3) RWStructuredBuffer VisibleBuffer; diff --git a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx index 8b13149a0..bb8303aed 100644 --- a/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx +++ b/shaders/Managed/Space/SpecialFX/Particles/Gpu/SortInner.fx @@ -7,7 +7,6 @@ #define SORT_SIZE 512 #define NUM_THREADS 256 // (SORT_SIZE/2) -#define INVERSION (16*2 + 8*3) RWStructuredBuffer VisibleBuffer; Buffer SortParameters;