-
-
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 {
LOC_VERTEX_POSITION = 0,
LOC_VERTEX_TEXCOORD01,
LOC_VERTEX_TEXCOORD02,
LOC_VERTEX_NORMAL,
LOC_VERTEX_TANGENT,
LOC_VERTEX_COLOR,
LOC_MATRIX_MVP,
LOC_MATRIX_MODEL,
LOC_MATRIX_VIEW,
LOC_MATRIX_PROJECTION,
LOC_VECTOR_VIEW,
LOC_COLOR_DIFFUSE,
LOC_COLOR_SPECULAR,
LOC_COLOR_AMBIENT,
LOC_MAP_ALBEDO, // LOC_MAP_DIFFUSE
LOC_MAP_METALNESS, // LOC_MAP_SPECULAR
LOC_MAP_NORMAL,
LOC_MAP_ROUGHNESS,
LOC_MAP_OCCUSION,
LOC_MAP_EMISSION,
LOC_MAP_HEIGHT,
LOC_MAP_CUBEMAP,
LOC_MAP_IRRADIANCE,
LOC_MAP_PREFILTER,
LOC_MAP_BRDF
} ShaderLocationIndex;
#define LOC_MAP_DIFFUSE LOC_MAP_ALBEDO
#define LOC_MAP_SPECULAR LOC_MAP_METALNESS
When loading a shader, raylib tries to bind by default the following vertex shader attributes:
// Default shader vertex attribute names to set location points
#define DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: 0
#define DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: 1
#define DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: 2
#define DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3
#define DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4
#define DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: 5
And also the following uniform location names are checked:
uniform mat4 mvp; // VS: ModelViewProjection matrix
uniform mat4 projection; // VS: Projection matrix
uniform mat4 view; // VS: View 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 also on custom shaders to make sure everything will be automatically setup on LoadShader()
but some of the default attribute names could 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 {
MAP_ALBEDO = 0, // MAP_DIFFUSE
MAP_METALNESS = 1, // MAP_SPECULAR
MAP_NORMAL = 2,
MAP_ROUGHNESS = 3,
MAP_OCCLUSION,
MAP_EMISSION,
MAP_HEIGHT,
MAP_CUBEMAP, // NOTE: Uses GL_TEXTURE_CUBE_MAP
MAP_IRRADIANCE, // NOTE: Uses GL_TEXTURE_CUBE_MAP
MAP_PREFILTER, // NOTE: Uses GL_TEXTURE_CUBE_MAP
MAP_BRDF
} TexmapIndex;
#define MAP_DIFFUSE MAP_ALBEDO
#define MAP_SPECULAR 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[MAP_DIFFUSE].texture = LoadTexture("tex_diffuse.png"); // texture unit 0 activated (available in material shader)
material.maps[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