-
Notifications
You must be signed in to change notification settings - Fork 10
Creating a custom type, usable in and by ShaderWriter
- Introduction
- Custom type creation
- Use inside a Uniform Buffer
- Use inside a Storage Buffer
- Conclusion
ShaderWriter allows you to create your own types, to use for example inside an UBO or an SSBO, or as a function parameter.
Doing so is not that complex, but a few things need to be done.
Let's say we want to create a Light
custom type holding a color and an intensity, and write a function computing some stuff from it.
The GLSL code for such a light, and its use as an array inside an UBO would look like this
struct Light
{
vec3 color;
float intensity;
};
layout(binding = 0, std140) uniform LightUbo
{
Light lights[8];
};
vec3 getLightRealColor( in Light light )
{
return color * intensity;
}
The first step is the creation of the custom light type.
As it is meant to be used as an instance of a shader structure, and to be usable by ShaderWriter, some constraints are necessary:
- It must inherit from
sdw::StructInstance
. - It's constructor must be in the form
MyClass(sdw::ShaderWriter & writer, ast::expr::ExprPtr expr, bool enabled);
. - It must implement shallow copy and move assignment operators, or use the macro
SDW_DeclStructInstance
. - It must implement a static member function
static ast::type::StructPtr makeType(ast::type::TypesCache & cache);
.
All those steps can be bypassed, using the helper sdw::StructInstanceHelperT
, which is used in the rest of this small tutorial.
Lets see the declaration of our brand new Light shader structure:
#include <ShaderWriter/CompositeTypes/StructInstance.hpp>
#include <ShaderWriter/BaseTypes/Float.hpp>
#include <ShaderWriter/VecTypes/Vec3.hpp>
namespace shader
{
struct Light
: public sdw::StructInstanceHelperT< "Light" // The structure name
, ast::type::MemoryLayout::eStd140 // Its memory layout
, sdw::StructFieldT< sdw::Vec4, "colorIntensity" > > // And its fields (of course, you can have more than one).
{
Light( sdw::ShaderWriter & writer, ast::expr::ExprPtr expr, bool enabled )
: StructInstanceHelperT{ writer, std::move( expr ), enabled }
{
}
auto colorIntensity() { return getMember< "colorIntensity" >(); }
auto color() { return colorIntensity().xyz(); }
auto intensity() { return colorIntensity().w(); }
};
// Useful macro for parameter types definitions.
Writer_Parameter( Light );
}
Now, we have a valid interface for ShaderWriter, that can be used in your C++ shader code.
The use of sdw::StructInstanceHelperT
also provides a compile time implementation for it.
That's all for the structure creation.
Now, we can use it as an array member of a uniform buffer.
To do that, we'll simply use sdw::Ubo, and add our structure to it:
// Declare the Uniform Buffer itself
auto lightsUbo = writer.declUniformBuffer<>( "LightsUbo", 0u /*binding*/, 0u /*set*/, ast::type::MemoryLayout::eStd140 };
// Our light array member of this Uniform Buffer
auto lights = lightsUbo.declStructMember< Light >( "lights", 8u );
lightsUbo.end();
// Let's declare the getLightRealColor function
auto getLightRealColor = writer.implementFunction< Vec3 >( "getLightRealColor"
, [&]( Light const & light )
{
writer.returnStmt( light.color() * intensity() );
}
, InLight{ writer, "light" } ); // This InLight type is generated from the macro Writer_Parameter
// ...
// Usage:
fragOutput = getLightRealColor( lights[0] );
Of course, we can use it inside a storage buffer, the same way we did for uniform buffer (using sdw::ShaderWriter::declShaderStorageBuffer
).
Additionally, we can use sdw::ArrayStorageBufferT
:
// The only thing needed is to declare the ArrayStorageBufferT
auto lights = writer.declArrayShaderStorageBuffer< Light >( "LightsSsbo", 0u /*binding*/, 0u /*set*/ );
// ...
// Usage:
fragOutput = getLightRealColor( lights[0] );
Enjoy :D.