-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
raylib generic uber shader and custom shaders
Dealing with custom shaders and making them generic is not an easy task. There are many things to consider for a shader because, after all, shaders are responsible for processing all the data sent to the GPU (mesh, materials, textures, lighting) to generate the final frame.
Finding a unified generic shader to deal with all kinds of stuff is very complicated so, after analyzing some of the big engines out there, I decided to go for a custom uber-shader-based solution.
By default, raylib's shader struct is defined as:
typedef struct Shader {
unsigned int id; // Shader program id
int *locs; // Shader locations array (MAX_SHADER_LOCATIONS)
} Shader;
This struct provides an array to store shader locations, those locations can be accessed by position using predefined enum values for convenience:
// Shader location point type
typedef enum {
SHADER_LOC_VERTEX_POSITION = 0,
SHADER_LOC_VERTEX_TEXCOORD01,
SHADER_LOC_VERTEX_TEXCOORD02,
SHADER_LOC_VERTEX_NORMAL,
SHADER_LOC_VERTEX_TANGENT,
SHADER_LOC_VERTEX_COLOR,
SHADER_LOC_MATRIX_MVP,
SHADER_LOC_MATRIX_MODEL,
SHADER_LOC_MATRIX_VIEW,
SHADER_LOC_MATRIX_PROJECTION,
SHADER_LOC_VECTOR_VIEW,
SHADER_LOC_COLOR_DIFFUSE,
SHADER_LOC_COLOR_SPECULAR,
SHADER_LOC_COLOR_AMBIENT,
SHADER_LOC_MAP_ALBEDO, // SHADER_LOC_MAP_DIFFUSE
SHADER_LOC_MAP_METALNESS, // SHADER_LOC_MAP_SPECULAR
SHADER_LOC_MAP_NORMAL,
SHADER_LOC_MAP_ROUGHNESS,
SHADER_LOC_MAP_OCCUSION,
SHADER_LOC_MAP_EMISSION,
SHADER_LOC_MAP_HEIGHT,
SHADER_LOC_MAP_CUBEMAP,
SHADER_LOC_MAP_IRRADIANCE,
SHADER_LOC_MAP_PREFILTER,
SHADER_LOC_MAP_BRDF
} ShaderLocationIndex;
#define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO
#define SHADER_LOC_MAP_SPECULAR SHADER_LOC_MAP_METALNESS
When loading a shader, raylib tries to find some default attributes and uniforms locations:
#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1
#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2
#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5
#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
#define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
#define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
#define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix
#define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))
#define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color)
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
The uniform locations belong to VertexShader or FragmentShader:
uniform mat4 mvp; // VS: ModelViewProjection matrix
uniform mat4 matView; // VS: View matrix
uniform mat4 matProjection; // VS: Projection matrix
uniform mat4 matModel; // VS: Model matrix
uniform mat4 matNormal; // VS: Normal matrix
uniform vec4 colDiffuse; // FS: Diffuse color
uniform sampler2D texture0; // FS: GL_TEXTURE0
uniform sampler2D texture1; // FS: GL_TEXTURE1
uniform sampler2D texture2; // FS: GL_TEXTURE2
Those are the attributes/uniform names used by the internal default shader. It's recommended to use that naming convention on custom shaders as well to make sure everything will be automatically set up on LoadShader()
. However, some of the default attribute names could be re-defined in config.h in case it was necessary.
Shaders are also directly related to the Material struct:
// Material type (generic)
typedef struct Material {
Shader shader; // Material shader
MaterialMap *maps; // Material maps array (MAX_MATERIAL_MAPS)
float *params; // Material generic parameters (if required)
} Material;
Material supports by default a number of maps (texture and properties) that can be accessed for convenience using the provided values:
// Material map type
typedef enum {
MATERIAL_MAP_ALBEDO = 0, // MATERIAL_MAP_DIFFUSE
MATERIAL_MAP_METALNESS = 1, // MATERIAL_MAP_SPECULAR
MATERIAL_MAP_NORMAL = 2,
MATERIAL_MAP_ROUGHNESS = 3,
MATERIAL_MAP_OCCLUSION,
MATERIAL_MAP_EMISSION,
MATERIAL_MAP_HEIGHT,
MATERIAL_MAP_CUBEMAP, // NOTE: Uses GL_TEXTURE_CUBE_MAP
MATERIAL_MAP_IRRADIANCE, // NOTE: Uses GL_TEXTURE_CUBE_MAP
MATERIAL_MAP_PREFILTER, // NOTE: Uses GL_TEXTURE_CUBE_MAP
MATERIAL_MAP_BRDF
} TexmapIndex;
#define MATERIAL_MAP_DIFFUSE MATERIAL_MAP_ALBEDO
#define MATERIAL_MAP_SPECULAR MATERIAL_MAP_METALNESS
When drawing, maps are internally bound or not depending on the availability:
// Default material loading example
Material material = LoadMaterialDefault(); // Default shader assigned to material
material.maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture("tex_diffuse.png"); // texture unit 0 activated (available in material shader)
material.maps[MATERIAL_MAP_SPECULAR].texture = LoadTexture("tex_specular.png"); // texture unit 1 activated (available in material shader)
User can load any custom shader using provided Material
and Shader
structs:
Material material = { 0 }; // Empty material
material.shader = LoadShader("custom_shader.vs", "custom_shader.fs");
// Setup location points in case names are not predefined ones or more locations are required
// Use: GetShaderLocation() and SetShaderValue*() functions
material.maps[0].texture = LoadTexture("tex_albedo.png");
material.maps[1].texture = LoadTexture("tex_metalness.png");
material.maps[2].texture = LoadTexture("tex_normal.png");
www.raylib.com | itch.io | GitHub | Discord | YouTube
- Architecture
- Syntax analysis
- Data structures
- Enumerated types
- External dependencies
- GLFW dependency
- libc dependency
- Platforms and graphics
- Input system
- Default shader
- Custom shaders
- Coding conventions
- Integration with other libs
- Working on Windows
- Working on macOS
- Working on GNU Linux
- Working on Chrome OS
- Working on FreeBSD
- Working on Raspberry Pi
- Working for Android
- Working for Web (HTML5)
- Working on exaequOS Web Computer
- Creating Discord Activities
- Working anywhere with CMake
- CMake Build Options
- raylib templates: Get started easily
- How To: Quick C/C++ Setup in Visual Studio 2022, GCC or MinGW
- How To: C# Visual Studio Setup
- How To: VSCode
- How To: Eclipse
- How To: Sublime Text
- How To: Code::Blocks