diff --git a/raylib-generic-uber-shader-and-custom-shaders.md b/raylib-generic-uber-shader-and-custom-shaders.md index 4659a79..f45a1f1 100644 --- a/raylib-generic-uber-shader-and-custom-shaders.md +++ b/raylib-generic-uber-shader-and-custom-shaders.md @@ -1,70 +1,114 @@ -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, the shader is responsible for processing all the data sent to the GPU (e.g. mesh, materials, textures, lighting) to generate the final frame. +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, the shader is 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 and, 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 supports the following data: +By default, raylib's shader struct is defined as: ```c typedef struct Shader { - unsigned int id; // Shader program id - - // Vertex attributes locations (default locations) - int vertexLoc; // Vertex attribute location point (default-location = 0) - int texcoordLoc; // Texcoord attribute location point (default-location = 1) - int texcoord2Loc; // Texcoord2 attribute location point (default-location = 5) - int normalLoc; // Normal attribute location point (default-location = 2) - int tangentLoc; // Tangent attribute location point (default-location = 4) - int colorLoc; // Color attibute location point (default-location = 3) - - // Uniform locations - int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) - int tintColorLoc; // Diffuse color uniform location point (fragment shader) - - // Texture map locations (generic for any kind of map) - int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0) - int mapTexture1Loc; // Map texture uniform location point (default-texture-unit = 1) - int mapTexture2Loc; // Map texture uniform location point (default-texture-unit = 2) + unsigned int id; // Shader program id + int locs[MAX_SHADER_LOCATIONS]; // Shader locations array } Shader; ``` -As you can see, most of the location points are pre-defined **on shader loading**; custom shaders developed for raylib must follow those conventions. +This struct provides an array to store shader locations, those locations can be accessed by position using predefined values for convenience: +```c +// 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; -On shader load, the following fixed location names are expected for maps: +#define LOC_MAP_DIFFUSE LOC_MAP_ALBEDO +#define LOC_MAP_SPECULAR LOC_MAP_METALNESS +``` + +On shader loading, the following location names are checked: ```glsl -uniform sampler2D texture0; // GL_TEXTURE0 -uniform sampler2D texture1; // GL_TEXTURE1 -uniform sampler2D texture2; // GL_TEXTURE2 +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 ``` Shaders are also directly related to the Material struct: ```c // Material type typedef struct Material { - Shader shader; // Standard shader (supports 3 map textures) - - Texture2D texDiffuse; // Diffuse texture (bound to shader mapTexture0Loc) - Texture2D texNormal; // Normal texture (bound to shader mapTexture1Loc) - Texture2D texSpecular; // Specular texture (bound to shader mapTexture2Loc) - - Color colDiffuse; // Diffuse color - Color colAmbient; // Ambient color - Color colSpecular; // Specular color - - float glossiness; // Glossiness level (Ranges from 0 to 1000) +// Material type (generic) +typedef struct Material { + Shader shader; // Material shader + MaterialMap maps[MAX_MATERIAL_MAPS]; // Material maps + float *params; // Material generic parameters (if required) } Material; ``` -Where three texture maps (texDiffuse, texNormal, texSpecular) will bind to shader location points. -When drawing, textures are internally bound or not depending on the selected shader and material: +Material support by default a number of maps (texture and properties) that can be accessed for convenience using the provided values: + ```c -// Default material loading example -Material material = LoadDefaultMaterial(); // Default shader assigned to material (supports only diffuse map) -material.texDiffuse = LoadTexture("wood_diffuse.png"); // texture unit 0 activated (available in material shader) -material.texSpecular = LoadTexture("wood_specular.png"); // texture unit 2 activated (available in material shader) +// 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 +``` -// Standard material loading example -Material material = LoadStandardMaterial(); // Standard shader assigned to material (supports diffuse, normal and specular maps) -material.texDiffuse = LoadTexture("wood_diffuse.png"); // texture unit 0 activated (available in material shader) -material.texSpecular = LoadTexture("wood_specular.png"); // texture unit 2 NOT activated (not available in material shader) +When drawing, maps are internally bound or not depending on the availability: +```c +// Default material loading example +Material material = LoadMaterialDefault(); // Default shader assigned to material +material.maps[MAP_DIFFUSE] = LoadTexture("tex_diffuse.png"); // texture unit 0 activated (available in material shader) +material.maps[MAP_SPECULAR] = LoadTexture("tex_specular.png"); // texture unit 1 activated (available in material shader) ``` -Despite its name on material struct (`texDiffuse`, `texNormal`, `texSpecular`), the user is free to use those maps in any way inside the **custom** shader. +User can load any custom shader using provided `Material` and `Shader`structs: + +```c +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] = LoadTexture("tex_albedo.png"); +material.maps[1] = LoadTexture("tex_metalness.png"); +material.maps[2] = LoadTexture("tex_normal.png"); +```