|
|
@ -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"); |
|
|
|
``` |