summaryrefslogtreecommitdiffhomepage
path: root/examples/shaders/rpbr.h
diff options
context:
space:
mode:
Diffstat (limited to 'examples/shaders/rpbr.h')
-rw-r--r--examples/shaders/rpbr.h466
1 files changed, 466 insertions, 0 deletions
diff --git a/examples/shaders/rpbr.h b/examples/shaders/rpbr.h
new file mode 100644
index 00000000..a8b7e939
--- /dev/null
+++ b/examples/shaders/rpbr.h
@@ -0,0 +1,466 @@
+/**********************************************************************************************
+*
+* raylib.pbr - Some useful functions to deal with pbr materials and lights
+*
+* CONFIGURATION:
+*
+* #define RPBR_IMPLEMENTATION
+* Generates the implementation of the library into the included file.
+* If not defined, the library is in header only mode and can be included in other headers
+* or source files without problems. But only ONE file should hold the implementation.
+*
+* LICENSE: zlib/libpng
+*
+* Copyright (c) 2023-2024 Afan OLOVCIC (@_DevDad) 2017-2020 Victor Fisac(@victorfisac),Ramon Santamaria (@raysan5)
+*
+* This software is provided "as-is", without any express or implied warranty. In no event
+* will the authors be held liable for any damages arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose, including commercial
+* applications, and to alter it and redistribute it freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not claim that you
+* wrote the original software. If you use this software in a product, an acknowledgment
+* in the product documentation would be appreciated but is not required.
+*
+* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
+* as being the original software.
+*
+* 3. This notice may not be removed or altered from any source distribution.
+*
+**********************************************************************************************/
+
+#ifndef RPBR_H
+#define RPBR_H
+#include "raylib.h"
+
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#define MAX_LIGHTS 4 // Max dynamic lights supported by shader
+#define SHADER_LOC_MAP_MRA SHADER_LOC_MAP_METALNESS //METALLIC, ROUGHNESS and AO
+#define SHADER_LOC_MAP_EMISSIVE SHADER_LOC_MAP_HEIGHT //EMISSIVE
+#define MATERIAL_MAP_MRA MATERIAL_MAP_METALNESS
+#define MATERIAL_MAP_EMISSIVE MATERIAL_MAP_HEIGHT
+#define NULL 0
+#define COLOR_TO_ARRAY(c)
+
+typedef struct {
+ int enabled;
+ int type;
+ Vector3 position;
+ Vector3 target;
+ float color[4];
+ float intensity;
+
+ int enabledLoc;
+ int typeLoc;
+ int positionLoc;
+ int targetLoc;
+ int colorLoc;
+ int intensityLoc;
+} PBRLight;
+
+typedef enum {
+ LIGHT_DIRECTIONAL = 0,
+ LIGHT_POINT,
+ LIGHT_SPOT
+} PBRLightType;
+
+typedef struct{
+ Shader pbrShader;
+ Shader skyShader;
+ unsigned int cubemap;
+ unsigned int irradiance;
+ unsigned int prefilter;
+ unsigned int brdf;
+ int modelMatrixLoc;
+ int pbrViewLoc;
+ int skyViewLoc;
+ int skyResolutionLoc;
+} PBREnvironment;
+
+typedef enum{
+ PBR_COLOR_ALBEDO = 0,
+ PBR_COLOR_EMISSIVE
+}PBRColorType;
+
+typedef enum{
+ PBR_VEC2_TILING = 0,
+ PBR_VEC2_OFFSET
+}PBRVec2Type;
+
+typedef enum{
+ PBR_PARAM_NORMAL =0,
+ PBR_PARAM_METALLIC,
+ PBR_PARAM_ROUGHNESS,
+ PBR_PARAM_EMISSIVE,
+ PBR_PARAM_AO
+}PBRFloatType;
+
+typedef enum{
+ PBR_TEXTURE_ALBEDO = 0,
+ PBR_TEXTURE_NORMAL,
+ PBR_TEXTURE_MRA,
+ PBR_TEXTURE_EMISSIVE
+}PBRTexType;
+
+// Textures are moved to material from params to pack better and use less textures on the end
+// texture MRAE 4Channel R: Metallic G: Roughness B: A: Ambient Occlusion
+// texEmissive use just one channel, so we have 3 channels still to use if we need
+typedef struct {
+ Shader pbrShader;
+ float albedo[4];
+ float normal;
+ float metallic;
+ float roughness;
+ float ao;
+ float emissive[4];
+ float ambient[3];
+ float emissivePower;
+
+ Texture2D texAlbedo;
+ Texture2D texNormal;
+ Texture2D texMRA;//r: Metallic g: Roughness b: AO a:Empty
+ Texture2D texEmissive; //Emissive Texture
+ // Using float4 to store tilling at 1st and 2nd position and offset at 3rd and 4th
+ float texTiling[2];
+ float texOffset[2];
+
+ int useTexAlbedo;
+ int useTexNormal;
+ int useTexMRA;
+ int useTexEmissive;
+
+ int albedoLoc;
+ int normalLoc;
+ int metallicLoc;
+ int roughnessLoc;
+ int aoLoc;
+ int emissiveColorLoc;
+ int emissivePowerLoc;
+
+ int texTilingLoc;
+ int texOffsetLoc;
+
+ int useTexAlbedoLoc;
+ int useTexNormalLoc;
+ int useTexMRAELoc;
+ int useTexEmissiveLoc;
+} PBRMaterial;
+
+typedef struct{
+ Model model;
+ PBRMaterial pbrMat;
+}PBRModel;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+
+// Create a light and get shader locations
+PBRLight PBRLightCreate(int type, Vector3 position, Vector3 target, Color color,float intensity, Shader shader);
+// Send light properties to shader
+void PBRLightUpdate(Shader shader, PBRLight light);
+
+//For now until we do real skylight
+void PBRSetAmbient(Shader shader, Color color, float intensity);
+
+PBRModel PBRModelLoad(const char *fileName);
+PBRModel PBRModelLoadFromMesh(Mesh mesh);
+
+void PBRLoadTextures(PBRMaterial *pbrMat,PBRTexType pbrTexType,const char *fileName);
+void UnloadPBRMaterial(PBRMaterial pbrMat);
+void PBRSetColor(PBRMaterial *pbrMat,PBRColorType pbrColorType,Color color);
+void PBRSetVec2(PBRMaterial *pbrMat,PBRVec2Type type,Vector2 value);
+void PBRSetFloat(PBRMaterial *pbrMat, PBRFloatType pbrParamType, float value);
+
+void PBRMaterialSetup( PBRMaterial *pbrMat,Shader pbrShader, PBREnvironment* environment);
+void PBRSetMaterial(PBRModel* model,PBRMaterial* pbrMat,int matIndex);
+void PBRDrawModel(PBRModel pbrModel, Vector3 position, float scale);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //RPBR_H
+
+/***********************************************************************************
+*
+* RPBR IMPLEMENTATION
+*
+************************************************************************************/
+
+#if defined(RPBR_IMPLEMENTATION)
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+static int lightsCount = 0; // Current amount of created lights
+
+// Create a light and get shader locations
+PBRLight PBRLightCreate(int type, Vector3 position, Vector3 target, Color color,float intensity, Shader shader)
+{
+ PBRLight light = { 0 };
+
+ if (lightsCount < MAX_LIGHTS)
+ {
+ light.enabled = 1;
+ light.type = type;
+ light.position = position;
+ light.target = target;
+ light.color[0] = (float)color.r/(float)255;
+ light.color[1] = (float)color.g/(float)255;
+ light.color[2] = (float)color.b/(float)255;
+ light.color[3] = (float)color.a/(float)255;
+ light.intensity = intensity;
+ // NOTE: Lighting shader naming must be the provided ones
+ light.enabledLoc = GetShaderLocation(shader, TextFormat("lights[%i].enabled", lightsCount));
+ light.typeLoc = GetShaderLocation(shader, TextFormat("lights[%i].type", lightsCount));
+ light.positionLoc = GetShaderLocation(shader, TextFormat("lights[%i].position", lightsCount));
+ light.targetLoc = GetShaderLocation(shader, TextFormat("lights[%i].target", lightsCount));
+ light.colorLoc = GetShaderLocation(shader, TextFormat("lights[%i].color", lightsCount));
+ light.intensityLoc = GetShaderLocation(shader, TextFormat("lights[%i].intensity", lightsCount));
+ PBRLightUpdate(shader, light);
+
+ lightsCount++;
+ }
+
+ return light;
+}
+
+// Send light properties to shader
+// NOTE: Light shader locations should be available
+void PBRLightUpdate(Shader shader, PBRLight light)
+{
+ SetShaderValue(shader, light.enabledLoc, &light.enabled, SHADER_UNIFORM_INT);
+ SetShaderValue(shader, light.typeLoc, &light.type, SHADER_UNIFORM_INT);
+ // Send to shader light position values
+ float position[3] = { light.position.x, light.position.y, light.position.z };
+ SetShaderValue(shader, light.positionLoc, position, SHADER_UNIFORM_VEC3);
+
+ // Send to shader light target position values
+ float target[3] = { light.target.x, light.target.y, light.target.z };
+ SetShaderValue(shader, light.targetLoc, target, SHADER_UNIFORM_VEC3);
+ SetShaderValue(shader, light.colorLoc, light.color, SHADER_UNIFORM_VEC4);
+ SetShaderValue(shader, light.intensityLoc, &light.intensity, SHADER_UNIFORM_FLOAT);
+}
+
+void PBRSetAmbient(Shader shader, Color color, float intensity){
+ float col[3] = {color.r/255,color.g/255,color.b/255};
+ SetShaderValue(shader, GetShaderLocation(shader, "ambientColor"), col, SHADER_UNIFORM_VEC3);
+ SetShaderValue(shader, GetShaderLocation(shader, "ambient"), &intensity, SHADER_UNIFORM_FLOAT);
+}
+
+void PBRMaterialSetup(PBRMaterial *pbrMat, Shader pbrShader, PBREnvironment* environment){
+ pbrMat->pbrShader = pbrShader;
+
+ pbrMat->texAlbedo = (Texture2D){0};
+ pbrMat->texNormal = (Texture2D){0};
+ pbrMat->texMRA = (Texture2D){0};
+ pbrMat->texEmissive = (Texture2D){0};
+
+ //PBRParam
+ pbrMat->albedo[0] = 1.0;
+ pbrMat->albedo[1] = 1.0;
+ pbrMat->albedo[2] = 1.0;
+ pbrMat->albedo[3] = 1.0;
+ pbrMat->metallic = 0;
+ pbrMat->roughness = 0;
+ pbrMat->ao = 1.0;
+ pbrMat->normal = 1;
+ pbrMat->emissive[0] = 0;
+ pbrMat->emissive[1] = 0;
+ pbrMat->emissive[2] = 0;
+ pbrMat->emissive[3] = 0;
+
+ pbrMat->texTiling[0] = 1.0;
+ pbrMat->texTiling[1] = 1.0;
+ pbrMat->texOffset[0] = 0.0;
+ pbrMat->texOffset[1] = 0.0;
+ pbrMat->emissivePower = 1.0;
+ // Set up PBR shader material locations
+
+ pbrMat->albedoLoc = GetShaderLocation(pbrMat->pbrShader, "albedoColor");
+ pbrMat->normalLoc = GetShaderLocation(pbrMat->pbrShader, "normalValue");
+ pbrMat->metallicLoc = GetShaderLocation(pbrMat->pbrShader, "metallicValue");
+ pbrMat->roughnessLoc = GetShaderLocation(pbrMat->pbrShader, "roughnessValue");
+ pbrMat->aoLoc = GetShaderLocation(pbrMat->pbrShader, "aoValue");
+ pbrMat->emissiveColorLoc = GetShaderLocation(pbrMat->pbrShader, "emissiveColor");
+ pbrMat->emissivePowerLoc = GetShaderLocation(pbrMat->pbrShader, "emissivePower");
+
+ pbrMat->texTilingLoc = GetShaderLocation(pbrMat->pbrShader, "tiling");
+ pbrMat->texOffsetLoc = GetShaderLocation(pbrMat->pbrShader, "offset");
+
+ pbrMat->useTexAlbedoLoc = GetShaderLocation(pbrMat->pbrShader, "useTexAlbedo");
+ pbrMat->useTexNormalLoc = GetShaderLocation(pbrMat->pbrShader, "useTexNormal");
+ pbrMat->useTexMRAELoc = GetShaderLocation(pbrMat->pbrShader, "useTexMRA");
+ pbrMat->useTexEmissiveLoc = GetShaderLocation(pbrMat->pbrShader, "useTexEmissive");
+
+ SetShaderValue(pbrMat->pbrShader,pbrMat->albedoLoc,pbrMat->albedo,SHADER_UNIFORM_VEC4);
+ SetShaderValue(pbrMat->pbrShader, pbrMat->emissiveColorLoc, pbrMat->emissive, SHADER_UNIFORM_VEC4);
+ SetShaderValue(pbrMat->pbrShader, pbrMat->emissivePowerLoc, &pbrMat->emissivePower, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->metallicLoc,&pbrMat->metallic,SHADER_UNIFORM_FLOAT);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->roughnessLoc,&pbrMat->roughness,SHADER_UNIFORM_FLOAT);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->aoLoc,&pbrMat->ao,SHADER_UNIFORM_FLOAT);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->normalLoc,&pbrMat->normal,SHADER_UNIFORM_FLOAT);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->texTilingLoc,pbrMat->texTiling,SHADER_UNIFORM_VEC2);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->texOffsetLoc,pbrMat->texOffset,SHADER_UNIFORM_VEC2);
+}
+
+void PBRLoadTextures(PBRMaterial *pbrMat,PBRTexType pbrTexType,const char *fileName){
+ if(pbrMat == NULL) return;
+ switch(pbrTexType){
+ case PBR_TEXTURE_ALBEDO:
+ pbrMat->texAlbedo = LoadTexture(fileName);
+ pbrMat->useTexAlbedo = 1;
+ break;
+ case PBR_TEXTURE_MRA:
+ pbrMat->texMRA = LoadTexture(fileName);
+ pbrMat->useTexMRA = 1;
+ break;
+ case PBR_TEXTURE_NORMAL:
+ pbrMat->texNormal = LoadTexture(fileName);
+ pbrMat->useTexNormal = 1;
+ break;
+ case PBR_TEXTURE_EMISSIVE:
+ pbrMat->texEmissive = LoadTexture(fileName);
+ pbrMat->useTexEmissive = 1;
+ break;
+ }
+}
+
+void UnloadPBRMaterial(PBRMaterial pbrMat){
+ if(pbrMat.useTexAlbedo == 1) UnloadTexture(pbrMat.texAlbedo);
+ if(pbrMat.useTexNormal == 1) UnloadTexture(pbrMat.texNormal);
+ if(pbrMat.useTexMRA == 1) UnloadTexture(pbrMat.texMRA);
+ if(pbrMat.useTexEmissive == 1) UnloadTexture(pbrMat.texEmissive);
+}
+
+void PBRSetColor(PBRMaterial *pbrMat,PBRColorType pbrColorType,Color color){
+ if(pbrMat == NULL) return;
+ switch(pbrColorType){
+ case PBR_COLOR_ALBEDO:
+ pbrMat->albedo[0] = (float) color.r / 255;
+ pbrMat->albedo[1] = (float) color.g / 255;
+ pbrMat->albedo[2] = (float) color.b / 255;
+ pbrMat->albedo[3] = (float) color.a / 255;
+ SetShaderValue(pbrMat->pbrShader,pbrMat->albedoLoc,pbrMat->albedo,SHADER_UNIFORM_VEC4);
+ break;
+ case PBR_COLOR_EMISSIVE:
+ pbrMat->emissive[0] = (float) color.r / 255;
+ pbrMat->emissive[1] = (float) color.g / 255;
+ pbrMat->emissive[2] = (float) color.b / 255;
+ pbrMat->emissive[3] = (float) color.a / 255;
+ SetShaderValue(pbrMat->pbrShader, pbrMat->emissiveColorLoc, pbrMat->emissive, SHADER_UNIFORM_VEC4);
+ break;
+ }
+}
+
+void PBRSetFloat(PBRMaterial *pbrMat, PBRFloatType pbrParamType, float value){
+ if(pbrMat == NULL) return;
+ switch(pbrParamType){
+ case PBR_PARAM_METALLIC:
+ pbrMat->metallic = value;
+ SetShaderValue(pbrMat->pbrShader,pbrMat->metallicLoc,&pbrMat->metallic,SHADER_UNIFORM_FLOAT);
+ break;
+ case PBR_PARAM_ROUGHNESS:
+ pbrMat->roughness = value;
+ SetShaderValue(pbrMat->pbrShader,pbrMat->roughnessLoc,&pbrMat->roughness,SHADER_UNIFORM_FLOAT);
+ break;
+ case PBR_PARAM_NORMAL:
+ pbrMat->normal = value;
+ SetShaderValue(pbrMat->pbrShader,pbrMat->normalLoc,&pbrMat->normal,SHADER_UNIFORM_FLOAT);
+ break;
+ case PBR_PARAM_AO:
+ pbrMat->ao = value;
+ SetShaderValue(pbrMat->pbrShader,pbrMat->aoLoc,&pbrMat->ao,SHADER_UNIFORM_FLOAT);
+ break;
+ case PBR_PARAM_EMISSIVE:
+ pbrMat->emissivePower = value;
+ SetShaderValue(pbrMat->pbrShader,pbrMat->emissivePowerLoc,&pbrMat->emissivePower,SHADER_UNIFORM_FLOAT);
+ break;
+ }
+}
+
+
+void PBRSetVec2(PBRMaterial *pbrMat,PBRVec2Type type,Vector2 value){
+ switch(type){
+ case PBR_VEC2_TILING:
+ pbrMat->texTiling[0] = value.x;
+ pbrMat->texTiling[1] = value.y;
+ SetShaderValue(pbrMat->pbrShader,pbrMat->texTilingLoc,&pbrMat->texTiling,SHADER_UNIFORM_VEC2);
+ break;
+ case PBR_VEC2_OFFSET:
+ pbrMat->texOffset[0] = value.x;
+ pbrMat->texOffset[1] = value.y;
+ SetShaderValue(pbrMat->pbrShader,pbrMat->texOffsetLoc,&pbrMat->texOffset,SHADER_UNIFORM_VEC2);
+ break;
+ }
+}
+
+void PBRSetMaterial(PBRModel* model,PBRMaterial* pbrMat,int matIndex){
+
+
+ model->pbrMat = *pbrMat;
+ model->model.materials[matIndex].shader = model->pbrMat.pbrShader;
+ pbrMat->pbrShader.locs[SHADER_LOC_MAP_MRA] = GetShaderLocation(pbrMat->pbrShader, "mraMap");
+ pbrMat->pbrShader.locs[SHADER_LOC_MAP_EMISSIVE] = GetShaderLocation(pbrMat->pbrShader, "emissiveMap");
+ pbrMat->pbrShader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(pbrMat->pbrShader, "normalMap");
+
+ if(pbrMat->useTexAlbedo) {
+ model->model.materials[matIndex].maps[MATERIAL_MAP_ALBEDO].texture = pbrMat->texAlbedo;
+ }
+ if(pbrMat->useTexMRA) {
+ model->model.materials[matIndex].maps[MATERIAL_MAP_MRA].texture = pbrMat->texMRA;
+ }
+ if(pbrMat->useTexNormal) {
+ model->model.materials[matIndex].maps[MATERIAL_MAP_NORMAL].texture = pbrMat->texNormal;
+ }
+ if(pbrMat->useTexEmissive) {
+ model->model.materials[matIndex].maps[MATERIAL_MAP_EMISSIVE].texture = pbrMat->texEmissive;
+ }
+
+ SetShaderValue(pbrMat->pbrShader,pbrMat->useTexAlbedoLoc,&pbrMat->useTexAlbedo,SHADER_UNIFORM_INT);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->useTexNormalLoc,&pbrMat->useTexNormal,SHADER_UNIFORM_INT);
+ SetShaderValue(pbrMat->pbrShader, pbrMat->useTexMRAELoc, &pbrMat->useTexMRA, SHADER_UNIFORM_INT);
+ SetShaderValue(pbrMat->pbrShader, pbrMat->useTexEmissiveLoc, &pbrMat->useTexEmissive, SHADER_UNIFORM_INT);
+}
+
+void PBRDrawModel(PBRModel pbrModel, Vector3 position, float scale){
+ PBRMaterial *pbrMat = &pbrModel.pbrMat;
+ SetShaderValue(pbrMat->pbrShader,pbrMat->albedoLoc,pbrMat->albedo,SHADER_UNIFORM_VEC4);
+ SetShaderValue(pbrMat->pbrShader, pbrMat->emissiveColorLoc, pbrMat->emissive, SHADER_UNIFORM_VEC4);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->metallicLoc,&pbrMat->metallic,SHADER_UNIFORM_FLOAT);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->roughnessLoc,&pbrMat->roughness,SHADER_UNIFORM_FLOAT);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->aoLoc,&pbrMat->ao,SHADER_UNIFORM_FLOAT);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->normalLoc,&pbrMat->normal,SHADER_UNIFORM_FLOAT);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->texTilingLoc,pbrMat->texTiling,SHADER_UNIFORM_VEC2);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->texOffsetLoc,pbrMat->texOffset,SHADER_UNIFORM_VEC2);
+
+ SetShaderValue(pbrMat->pbrShader,pbrMat->useTexAlbedoLoc,&pbrMat->useTexAlbedo,SHADER_UNIFORM_INT);
+ SetShaderValue(pbrMat->pbrShader,pbrMat->useTexNormalLoc,&pbrMat->useTexNormal,SHADER_UNIFORM_INT);
+ SetShaderValue(pbrMat->pbrShader, pbrMat->useTexMRAELoc, &pbrMat->useTexMRA, SHADER_UNIFORM_INT);
+ SetShaderValue(pbrMat->pbrShader, pbrMat->useTexEmissiveLoc, &pbrMat->useTexEmissive, SHADER_UNIFORM_INT);
+
+ DrawModel(pbrModel.model,position,scale,WHITE);
+}
+
+PBRModel PBRModelLoad(const char *fileName){
+ PBRModel pbrModel = (PBRModel){0};
+ pbrModel.model = LoadModel(fileName);
+ return pbrModel;
+}
+
+PBRModel PBRModelLoadFromMesh(Mesh mesh){
+ PBRModel pbrModel = (PBRModel){0};
+ pbrModel.model = LoadModelFromMesh(mesh);
+ return pbrModel;
+}
+#endif // RPBR_IMPLEMENTATION