Прежде чем тело шейдера (переданное в качестве параметров data и count) будет передано компилятору, ему будет добавлен заголовок и футер.
Заголовок
Версия шейдера
#version 330 core // Только для OpenGL
#version 300 es // Только для OpenGLES3
Предопределенные макросы типа шейдера
- COVELLITE_SHADER_DESKTOP или COVELLITE_SHADER_MOBILE
- COVELLITE_SHADER_HLSL или COVELLITE_SHADER_GLSL
- COVELLITE_SHADER_VERTEX или COVELLITE_SHADER_PIXEL
Файл вспомогательных определений для создания унифицированных шейдеров
#ifdef COVELLITE_SHADER_HLSL // ********************************************* //
#define mediump
#define lowp
#define ivec4 int4
#define vec4 float4
#define vec3 float3
#define vec2 float2
#define mat4 float4x4
#define mat3 float3x3
#define ToMatrix3x3(m) (float3x3)m
#define dFdx(a) ddx(a)
#define dFdy(a) ddy(a)
#define mix(a, b, c) lerp(a, b, c)
#define COVELLITE_INPUT_SEMANTIC(value) \
: value
#define COVELLITE_DECLARE_CONST_BUFFER(type, cbname, name, index) \
cbuffer cb##name : register(b##index) { const type name; }
#define COVELLITE_DECLARE_CONST_BUFFER_INSIDE(type, name, index) \
COVELLITE_DECLARE_CONST_BUFFER(type, dummy, name, index)
#define COVELLITE_DECLARE_STATIC \
static
#define COVELLITE_MATRIX_ROW(m, index) \
m[index]
#define COVELLITE_MATRIX_COLUMN(m, index) \
float4(m[0][index], m[1][index], m[2][index], m[3][index])
#define COVELLITE_DECLARE_TEX2D(name, index) \
Texture2D name : register(t##index); \
SamplerState TexSampler##index : register(s##index);
#define COVELLITE_TEX2D_COLOR(tex, uv) \
tex.Sample(TexSampler0, uv)
#define COVELLITE_DECLARE_MULTI_TARGET_STRUCTURE(name, count) \
struct name { float4 Target[count] : SV_Target; }
#elif defined COVELLITE_SHADER_GLSL // ************************************** //
precision highp float;
precision highp int;
#define int4 ivec4
#define float4 vec4
#define float3 vec3
#define float2 vec2
#define float4x4 mat4
#define float3x3 mat3
#define ToMatrix3x3(m) mat3(m)
#define ddx(a) dFdx(a)
#define ddy(a) dFdy(a)
#define mul(a, b) ((a) * (b))
#define saturate(a) clamp(a, 0.0f, 1.0f)
#define rsqrt(a) (1.0f / sqrt(a))
#define lerp(a, b, c) mix(a, b, c)
#define COVELLITE_INPUT_SEMANTIC(value)
#define COVELLITE_DECLARE_CONST_BUFFER(type, cbname, name, index) \
layout (std140) uniform cbname { type name; }
#define COVELLITE_DECLARE_CONST_BUFFER_INSIDE(type, name, index) \
uniform type name
#define COVELLITE_DECLARE_STATIC
#define COVELLITE_MATRIX_ROW(m, index) \
float4(m[0][index], m[1][index], m[2][index], m[3][index])
#define COVELLITE_MATRIX_COLUMN(m, index) \
m[index]
#define COVELLITE_DECLARE_TEX2D(name, index) \
uniform sampler2D name
#define COVELLITE_TEX2D_COLOR(tex, uv) \
texture(tex, uv)
#define COVELLITE_DECLARE_MULTI_TARGET_STRUCTURE(name, count) \
struct name { float4 Target[count]; }; \
out float4 Covellite_MultiOutPixelColor[count]
#endif // ******************************************************************* //
#define COVELLITE_DECLARE_CONST_USER_BUFFER(type, cbname, name) \
COVELLITE_DECLARE_CONST_BUFFER(type, cbname, name, COVELLITE_BUFFER_INDEX_USER)
#define ToFloat3(v) v.xyz
Файл объвления структур для передачи данных шейдеру
#ifndef COVELLITE_API_CONSTANT_BUFFERS_HEADER
#define COVELLITE_API_CONSTANT_BUFFERS_HEADER
#ifdef GLM_VERSION
using float4x4 = ::glm::mat4;
#define mediump
#define lowp
#endif // GLM_VERSION
#define COVELLITE_BUFFER_INDEX_CAMERA 0
#define COVELLITE_BUFFER_INDEX_OBJECT 1
#define COVELLITE_BUFFER_INDEX_USER 2
struct Camera
{
float4x4 Projection;
float4x4 View;
float4x4 ViewInverse;
};
struct Object
{
float4x4 World;
};
#endif // COVELLITE_API_CONSTANT_BUFFERS_HEADER
Файл объявления форматов входных данных шейдеров
#define COVELLITE_INSTANCE_DATA_STRUCTURE \
/* place for instance variables */
#ifdef COVELLITE_SHADER_GLSL // ********************************************* //
#ifdef COVELLITE_SHADER_VERTEX /////////////////////////////////////////////////
#define COVELLITE_IN in
// Covellite++ GLSL input data vertex shader.
in vec4 Covellite_VertexPosition;
in mediump vec2 Covellite_VertexTexCoord;
in vec4 Covellite_VertexExtra;
COVELLITE_INSTANCE_DATA_STRUCTURE
#undef COVELLITE_IN
#endif /////////////////////////////////////////////////////////////////////////
#endif // ******************************************************************* //
#define COVELLITE_IN
COVELLITE_DECLARE_CONST_BUFFER_INSIDE(Camera, CameraData, COVELLITE_BUFFER_INDEX_CAMERA);
COVELLITE_DECLARE_CONST_BUFFER_INSIDE(Object, ObjectData, COVELLITE_BUFFER_INDEX_OBJECT);
// Input data vertex shader (union objects).
struct Vertex
{
float4 Position COVELLITE_INPUT_SEMANTIC(POSITION);
mediump float2 TexCoord COVELLITE_INPUT_SEMANTIC(TEXCOORD);
float4 Extra COVELLITE_INPUT_SEMANTIC(NORMAL);
COVELLITE_INSTANCE_DATA_STRUCTURE
};
// Output data vertex shader and input data pixel shader.
struct Pixel
{
float4 ScreenPos COVELLITE_INPUT_SEMANTIC(SV_POSITION);
lowp float4 Color COVELLITE_INPUT_SEMANTIC(COLOR);
float3 Normal COVELLITE_INPUT_SEMANTIC(NORMAL);
mediump float2 TexCoord COVELLITE_INPUT_SEMANTIC(TEXCOORD0);
float4 WorldPos COVELLITE_INPUT_SEMANTIC(POSITION0);
};
- Заметки
- В случае ошибки компиляции шейдера описание исключения будет содержать количество строк, добавленных фреймворком к переданному телу шейдера.
Тело шейдера
Тело шейдера должно содержать определение функции, имя которой передается компоненту шейдера как параметр entry. Имя этой функции может быть любым, но сигнатура ее должна соответствовать одной из следующего набора (тип входного параметра определяет тип шейдера и формат передаваемых ему данных):
Pixel entry(Vertex _Value);
float4 entry(Pixel _Value);
Если указаны бинарные данные шейдера (параметры data и count), в качестве тела шейдера будет использован переданный буфер, если нет, то вместо них будут использоваться шейдеры по умолчанию (те, что использует сам фреймворк для рендеринга Gui):
#ifdef COVELLITE_SHADER_VERTEX /////////////////////////////////////////////////
// ************************************************************************** //
Pixel vsFlat(Vertex _Value)
{
float4x4 ViewProjection = mul(CameraData.View, CameraData.Projection);
float4 WorldPos = mul(_Value.Position, ObjectData.World);
Pixel Result;
Result.ScreenPos = mul(WorldPos, ViewProjection);
Result.Color = _Value.Extra;
Result.Normal = float3(0.0f, 0.0f, 1.0f);
Result.TexCoord = _Value.TexCoord;
Result.WorldPos = float4(0.0f, 0.0f, 0.0f, 1.0f);
return Result;
}
Pixel vsVolume(Vertex _Value)
{
float4x4 ViewProjection = mul(CameraData.View, CameraData.Projection);
float4 WorldPos = mul(_Value.Position, ObjectData.World);
Pixel Result;
Result.ScreenPos = mul(WorldPos, ViewProjection);
Result.Color = float4(1.0f, 0.0f, 0.0f, 1.0f);
Result.Normal = normalize(mul(ToFloat3(_Value.Extra), ToMatrix3x3(ObjectData.World)));
Result.TexCoord = _Value.TexCoord;
Result.WorldPos = WorldPos;
return Result;
}
#elif defined COVELLITE_SHADER_PIXEL ///////////////////////////////////////////
COVELLITE_DECLARE_TEX2D(TexDiffuse, 0);
float4 psColored(Pixel _Value)
{
return _Value.Color;
}
float4 psTextured(Pixel _Value)
{
return COVELLITE_TEX2D_COLOR(TexDiffuse, _Value.TexCoord) * _Value.Color;
}
#endif /////////////////////////////////////////////////////////////////////////
Футер
В конце тела шейдера добавляется определение функции, которая будет вызывать функцию, указанную в качестве параметра entry (это сделано для возможности создания единого унифицированного HLSL и GLSL тела шейдера).
HLSL (вертексный шейдер)
Ничего не добавляется, указанная функция вызывается напрямую.
HLSL (пиксельный шейдер)
float4 psMain(Pixel _Value) : SV_Target
{
return entry(_Value);
}
GLSL (вертексный шейдер)
out Pixel PixelValue;
void main()
{
Vertex InputData;
InputData.Position = Covellite_VertexPosition;
InputData.TexCoord = Covellite_VertexTexCoord;
InputData.Extra = Covellite_VertexExtra;
PixelValue = entry(InputData);
gl_Position = PixelValue.ScreenPos;
}
GLSL (пиксельный шейдер)
in Pixel PixelValue;
out vec4 Covellite_OutPixelColor;
void main()
{
Covellite_OutPixelColor = entry(PixelValue);
}