diff --git a/examples/shaders/rpbr.h b/examples/shaders/rpbr.h deleted file mode 100644 index a8b7e9394..000000000 --- a/examples/shaders/rpbr.h +++ /dev/null @@ -1,466 +0,0 @@ -/********************************************************************************************** -* -* 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 diff --git a/examples/shaders/shaders_basic_pbr.c b/examples/shaders/shaders_basic_pbr.c index 92a888811..11e423d6b 100644 --- a/examples/shaders/shaders_basic_pbr.c +++ b/examples/shaders/shaders_basic_pbr.c @@ -19,15 +19,45 @@ #include #endif -#define RPBR_IMPLEMENTATION -#include "rpbr.h" - #if defined(PLATFORM_DESKTOP) #define GLSL_VERSION 330 #else // PLATFORM_ANDROID, PLATFORM_WEB #define GLSL_VERSION 120 #endif +#include // Required for: NULL + +#define MAX_LIGHTS 4 // Max dynamic lights supported by shader +int lightsCount; // Current number of dynamic lights that have been created + +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; + +// 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 +// NOTE: Light shader locations should be available +void PBRLightUpdate(Shader shader, PBRLight light); //---------------------------------------------------------------------------------- // Main Entry Point @@ -53,44 +83,69 @@ int main() Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/pbr.vs",GLSL_VERSION), TextFormat("resources/shaders/glsl%i/pbr.fs",GLSL_VERSION)); - - - - PBRModel model = PBRModelLoad("resources/models/old_car_new.glb"); - //if we use obj file formator if model doesn't have tangents we have to calculate MeshTangents - //by using raylib function GenMeshTangents(mesh) for example: obj file doesn't support tangents - //GenMeshTangents(&model.model.meshes[0]); - - PBRMaterial model_mat = (PBRMaterial){0}; - PBRMaterialSetup(&model_mat, shader, NULL); //environment = NULL for now - PBRLoadTextures(&model_mat, PBR_TEXTURE_ALBEDO, "resources/old_car_d.png"); - PBRLoadTextures(&model_mat, PBR_TEXTURE_MRA, "resources/old_car_mra.png"); - PBRLoadTextures(&model_mat, PBR_TEXTURE_NORMAL, "resources/old_car_n.png"); - PBRLoadTextures(&model_mat, PBR_TEXTURE_EMISSIVE, "resources/old_car_e.png"); - PBRSetColor(&model_mat,PBR_COLOR_EMISSIVE, (Color){255,162,0,255}); - PBRSetVec2(&model_mat, PBR_VEC2_TILING,(Vector2){0.5,0.5}); - PBRSetMaterial(&model,&model_mat,0); - - PBRModel floor = PBRModelLoad("resources/models/plane.glb"); - - PBRMaterial floor_mat = (PBRMaterial){0}; - PBRMaterialSetup(&floor_mat, shader, NULL); - PBRLoadTextures(&floor_mat, PBR_TEXTURE_ALBEDO, "resources/road_a.png"); - PBRLoadTextures(&floor_mat, PBR_TEXTURE_MRA, "resources/road_mra.png"); - PBRLoadTextures(&floor_mat, PBR_TEXTURE_NORMAL, "resources/road_n.png"); - PBRSetVec2(&floor_mat, PBR_VEC2_TILING,(Vector2){0.5,0.5}); - PBRSetMaterial(&floor,&floor_mat,0); + shader.locs[SHADER_LOC_MAP_ALBEDO] = GetShaderLocation(shader, "albedoMap"); + // In reality, metalness, roughness, and ambient occlusion are all packed into the MRA texture + // We'll pass it in as the metalness map + shader.locs[SHADER_LOC_MAP_METALNESS] = GetShaderLocation(shader, "mraMap"); + shader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(shader, "normalMap"); + // Similarly to the MRA map, the emissive map packs different information into a single texture + // This map stores both height and emission in reality + shader.locs[SHADER_LOC_MAP_EMISSION] = GetShaderLocation(shader, "emissiveMap"); + shader.locs[SHADER_LOC_COLOR_DIFFUSE] = GetShaderLocation(shader, "albedoColor"); shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos"); int numOfLightsLoc = GetShaderLocation(shader, "numOfLights"); int numOfLights = 4; SetShaderValue(shader, numOfLightsLoc, &numOfLights, SHADER_UNIFORM_INT); - Color ambCol = (Color){26,32,135,255}; + Color ambCol = (Color){ 26,32,135,255 }; + Vector3 ambColNormalized = (Vector3){ ambCol.r / 255.0f, ambCol.g / 255.0f, ambCol.b / 255.0f }; float ambIntens = 0.02; int albedoLoc = GetShaderLocation(shader, "albedo"); - PBRSetAmbient(shader,ambCol,ambIntens); + int ambColLoc = GetShaderLocation(shader, "ambientColor"); + int ambLoc = GetShaderLocation(shader, "ambient"); + SetShaderValue(shader, ambColLoc, &ambColNormalized, SHADER_UNIFORM_VEC3); + SetShaderValue(shader, ambLoc, &ambIntens, SHADER_UNIFORM_FLOAT); + + int emissiveIntensityLoc = GetShaderLocation(shader, "emissivePower"); + int emissiveColorLoc = GetShaderLocation(shader, "emissiveColor"); + int textureTilingLoc = GetShaderLocation(shader, "tiling"); + + Model model = LoadModel("resources/models/old_car_new.glb"); + // If the OBJ file format is used, we will have to generate tangents manually: + // GenMeshTangents(&model.meshes[0]); + + model.materials[0].shader = shader; + + model.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE; + model.materials[0].maps[MATERIAL_MAP_METALNESS].value = 0.0f; + model.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value = 0.0f; + model.materials[0].maps[MATERIAL_MAP_OCCLUSION].value = 1.0f; + model.materials[0].maps[MATERIAL_MAP_EMISSION].color = (Color){ 255, 162, 0, 255 }; + + model.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = LoadTexture("resources/old_car_d.png"); + model.materials[0].maps[MATERIAL_MAP_METALNESS].texture = LoadTexture("resources/old_car_mra.png"); + model.materials[0].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture("resources/old_car_n.png"); + model.materials[0].maps[MATERIAL_MAP_EMISSION].texture = LoadTexture("resources/old_car_e.png"); + // We store tiling parameters in the generic parameter slots in the Material class + Vector2 modelTiling = (Vector2){ 0.5f, 0.5f }; + + Model floor = LoadModel("resources/models/plane.glb"); + + floor.materials[0].shader = shader; + + floor.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE; + floor.materials[0].maps[MATERIAL_MAP_METALNESS].value = 0.0f; + floor.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value = 0.0f; + floor.materials[0].maps[MATERIAL_MAP_OCCLUSION].value = 1.0f; + floor.materials[0].maps[MATERIAL_MAP_EMISSION].color = BLACK; + + floor.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = LoadTexture("resources/road_a.png"); + floor.materials[0].maps[MATERIAL_MAP_METALNESS].texture = LoadTexture("resources/road_mra.png"); + floor.materials[0].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture("resources/road_n.png"); + + Vector2 floorTiling = (Vector2){ 0.5f, 0.5f }; // Create lights PBRLight lights[MAX_LIGHTS] = { 0 }; @@ -98,7 +153,13 @@ int main() lights[1] = PBRLightCreate(LIGHT_POINT, (Vector3){ 2, 1, 1 }, (Vector3){0,0,0}, GREEN,3.3, shader); lights[2] = PBRLightCreate(LIGHT_POINT, (Vector3){ -2, 1, 1 }, (Vector3){0,0,0}, RED,8.3, shader); lights[3] = PBRLightCreate(LIGHT_POINT, (Vector3){ 1, 1, -2 }, (Vector3){0,0,0}, BLUE,2, shader); - SetShaderValueV(shader, GetShaderLocation(shader, "lights"), lights, SHADER_UNIFORM_FLOAT, numOfLights); + + // The textures are always used + int one = 1; + SetShaderValue(shader, GetShaderLocation(shader, "useTexAlbedo"), &one, SHADER_UNIFORM_INT); + SetShaderValue(shader, GetShaderLocation(shader, "useTexNormal"), &one, SHADER_UNIFORM_INT); + SetShaderValue(shader, GetShaderLocation(shader, "useTexMRA"), &one, SHADER_UNIFORM_INT); + SetShaderValue(shader, GetShaderLocation(shader, "useTexEmissive"), &one, SHADER_UNIFORM_INT); SetTargetFPS(60); // Set our game to run at 60 frames-per-second------------------------------------------------------------- @@ -122,32 +183,45 @@ int main() // Update light values (actually, only enable/disable them) for (int i = 0; i < MAX_LIGHTS; i++) PBRLightUpdate(shader, lights[i]); - emissiveCnt--; - if(emissiveCnt<=0){ - emissiveCnt = GetRandomValue(0,20); - PBRSetFloat(&model_mat,PBR_PARAM_EMISSIVE,(float)GetRandomValue(0,100)/100); - } //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); + ClearBackground(BLACK); + BeginMode3D(camera); + + SetShaderValue(shader, textureTilingLoc, &floorTiling, SHADER_UNIFORM_VEC2); + Vector4 floorEmission = ColorNormalize(floor.materials[0].maps[MATERIAL_MAP_EMISSION].color); + SetShaderValue(shader, emissiveColorLoc, &floorEmission, SHADER_UNIFORM_VEC4); + DrawModel(floor, (Vector3){0,0,0}, 5.0f, WHITE); - PBRDrawModel(floor, (Vector3){0,0,0}, 5.0f); - PBRDrawModel(model, (Vector3) {0, 0.0, 0}, 0.005); + emissiveCnt--; + if (emissiveCnt <= 0) + { + emissiveCnt = GetRandomValue(0, 20); + float intensity = (float)GetRandomValue(0, 100) / 100; + SetShaderValue(shader, emissiveIntensityLoc, &intensity, SHADER_UNIFORM_FLOAT); + } + SetShaderValue(shader, textureTilingLoc, &modelTiling, SHADER_UNIFORM_VEC2); + Vector4 modelEmission = ColorNormalize(model.materials[0].maps[MATERIAL_MAP_EMISSION].color); + SetShaderValue(shader, emissiveColorLoc, &modelEmission, SHADER_UNIFORM_VEC4); + DrawModel(model, (Vector3) {0, 0.0, 0}, 0.005, WHITE); // Draw spheres to show where the lights are - for (int i = 0; i < MAX_LIGHTS; i++) { + for (int i = 0; i < MAX_LIGHTS; i++) + { Color col = (Color) {lights[i].color[0] * 255, lights[i].color[1] * 255, lights[i].color[2] * 255, lights[i].color[3] * 255}; if (lights[i].enabled) DrawSphereEx(lights[i].position, 0.2f, 8, 8, col); else DrawSphereWires(lights[i].position, 0.2f, 8, 8, ColorAlpha(col, 0.3f)); } + EndMode3D(); - DrawText("(c) Old Rusty Car model by Renafox (https://skfb.ly/LxRy)", screenWidth - 320, screenHeight - 20, 10, GRAY); + DrawText("(c) Old Rusty Car model by Renafox (https://skfb.ly/LxRy)", screenWidth - 320, screenHeight - 20, 10, LIGHTGRAY); DrawFPS(10, 10); EndDrawing(); @@ -157,15 +231,65 @@ int main() //-------------------------------------------------------------------------------------- // De-Initialization //-------------------------------------------------------------------------------------- - - UnloadModel(floor.model); // Unload model - UnloadModel(model.model); // Unload model + model.materials[0].shader = (Shader){ 0 }; + floor.materials[0].shader = (Shader){ 0 }; + UnloadMaterial(model.materials[0]); + UnloadMaterial(floor.materials[0]); + model.materials[0].maps = NULL; + floor.materials[0].maps = NULL; + UnloadModel(floor); // Unload model + UnloadModel(model); // Unload model UnloadShader(shader); // Unload Shader - UnloadPBRMaterial(floor_mat); // Unload PBRMaterial - UnloadPBRMaterial(model_mat); // Unload PBRMaterial CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; +} + +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); +}