diff --git a/examples/shaders/resources/models/old_car_new.glb b/examples/shaders/resources/models/old_car_new.glb new file mode 100644 index 000000000000..119995ca76a8 Binary files /dev/null and b/examples/shaders/resources/models/old_car_new.glb differ diff --git a/examples/shaders/resources/models/plane.glb b/examples/shaders/resources/models/plane.glb new file mode 100644 index 000000000000..452e1c5bf260 Binary files /dev/null and b/examples/shaders/resources/models/plane.glb differ diff --git a/examples/shaders/resources/old_car_d.png b/examples/shaders/resources/old_car_d.png new file mode 100644 index 000000000000..d8b3c833d1c0 Binary files /dev/null and b/examples/shaders/resources/old_car_d.png differ diff --git a/examples/shaders/resources/old_car_e.png b/examples/shaders/resources/old_car_e.png new file mode 100644 index 000000000000..23f01c0fe49d Binary files /dev/null and b/examples/shaders/resources/old_car_e.png differ diff --git a/examples/shaders/resources/old_car_mra.png b/examples/shaders/resources/old_car_mra.png new file mode 100644 index 000000000000..0fb46b336233 Binary files /dev/null and b/examples/shaders/resources/old_car_mra.png differ diff --git a/examples/shaders/resources/old_car_n.png b/examples/shaders/resources/old_car_n.png new file mode 100644 index 000000000000..11f689fe27a4 Binary files /dev/null and b/examples/shaders/resources/old_car_n.png differ diff --git a/examples/shaders/resources/road_a.png b/examples/shaders/resources/road_a.png new file mode 100644 index 000000000000..103777398699 Binary files /dev/null and b/examples/shaders/resources/road_a.png differ diff --git a/examples/shaders/resources/road_mra.png b/examples/shaders/resources/road_mra.png new file mode 100644 index 000000000000..988c839cc127 Binary files /dev/null and b/examples/shaders/resources/road_mra.png differ diff --git a/examples/shaders/resources/road_n.png b/examples/shaders/resources/road_n.png new file mode 100644 index 000000000000..a5f3548c1a44 Binary files /dev/null and b/examples/shaders/resources/road_n.png differ diff --git a/examples/shaders/resources/shaders/glsl100/pbr.fs b/examples/shaders/resources/shaders/glsl100/pbr.fs new file mode 100644 index 000000000000..1ada833175ef --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/pbr.fs @@ -0,0 +1,156 @@ +#version 100 + +precision mediump float; + +#define MAX_LIGHTS 4 +#define LIGHT_DIRECTIONAL 0 +#define LIGHT_POINT 1 +#define PI 3.14159265358979323846 + +struct Light { + int enabled; + int type; + vec3 position; + vec3 target; + vec4 color; + float intensity; +}; + +// Input vertex attributes (from vertex shader) +varying in vec3 fragPosition; +varying in vec2 fragTexCoord; +varying in vec4 fragColor; +varying in vec3 fragNormal; +varying in vec4 shadowPos; +varying in mat3 TBN; + + +// Input uniform values +uniform int numOfLights; +uniform sampler2D albedoMap; +uniform sampler2D mraMap; +uniform sampler2D normalMap; +uniform sampler2D emissiveMap; // r: Hight g:emissive + +uniform vec2 tiling; +uniform vec2 offset; + +uniform int useTexAlbedo; +uniform int useTexNormal; +uniform int useTexMRA; +uniform int useTexEmissive; + +uniform vec4 albedoColor; +uniform vec4 emissiveColor; +uniform float normalValue; +uniform float metallicValue; +uniform float roughnessValue; +uniform float aoValue; +uniform float emissivePower; + +// Input lighting values +uniform Light lights[MAX_LIGHTS]; +uniform vec3 viewPos; + +uniform vec3 ambientColor; +uniform float ambient; + +// refl in range 0 to 1 +// returns base reflectivity to 1 +// incrase reflectivity when surface view at larger angle +vec3 schlickFresnel(float hDotV,vec3 refl) +{ + return refl + (1.0 - refl) * pow(1.0 - hDotV,5.0); +} + +float ggxDistribution(float nDotH,float roughness) +{ + float a = roughness * roughness * roughness * roughness; + float d = nDotH * nDotH * (a - 1.0) + 1.0; + d = PI * d * d; + return a / max(d,0.0000001); +} + +float geomSmith(float nDotV,float nDotL,float roughness) +{ + float r = roughness + 1.0; + float k = r * r / 8.0; + float ik = 1.0 - k; + float ggx1 = nDotV / (nDotV * ik + k); + float ggx2 = nDotL / (nDotL * ik + k); + return ggx1 * ggx2; +} + +vec3 pbr(){ + vec3 albedo = texture2D(albedoMap,vec2(fragTexCoord.x*tiling.x+offset.x,fragTexCoord.y*tiling.y+offset.y)).rgb; + albedo = vec3(albedoColor.x*albedo.x,albedoColor.y*albedo.y,albedoColor.z*albedo.z); + float metallic = clamp(metallicValue,0.0,1.0); + float roughness = clamp(roughnessValue,0.0,1.0); + float ao = clamp(aoValue,0.0,1.0); + if(useTexMRA == 1) { + vec4 mra = texture2D(mraMap, vec2(fragTexCoord.x * tiling.x + offset.x, fragTexCoord.y * tiling.y + offset.y)); + metallic = clamp(mra.r+metallicValue,0.04,1.0); + roughness = clamp(mra.g+roughnessValue,0.04,1.0); + ao = (mra.b+aoValue)*0.5; + } + + + + vec3 N = normalize(fragNormal); + if(useTexNormal == 1) { + N = texture2D(normalMap, vec2(fragTexCoord.x * tiling.x + offset.y, fragTexCoord.y * tiling.y + offset.y)).rgb; + N = normalize(N * 2.0 - 1.0); + N = normalize(N * TBN); + } + + vec3 V = normalize(viewPos - fragPosition); + + vec3 e = vec3(0); + e = (texture2D(emissiveMap, vec2(fragTexCoord.x*tiling.x+offset.x, fragTexCoord.y*tiling.y+offset.y)).rgb).g * emissiveColor.rgb*emissivePower * float(useTexEmissive); + + //return N;//vec3(metallic,metallic,metallic); + //if dia-electric use base reflectivity of 0.04 otherwise ut is a metal use albedo as base reflectivity + vec3 baseRefl = mix(vec3(0.04),albedo.rgb,metallic); + vec3 Lo = vec3(0.0); // acumulate lighting lum + + for(int i=0;ipbrShader = 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 new file mode 100644 index 000000000000..92a888811550 --- /dev/null +++ b/examples/shaders/shaders_basic_pbr.c @@ -0,0 +1,171 @@ +/******************************************************************************************* +* +* raylib [core] example - Model Defuse Normal Shader (adapted for HTML5 platform) +* +* This example is prepared to compile for PLATFORM_WEB and PLATFORM_DESKTOP +* As you will notice, code structure is slightly different to the other examples... +* To compile it for PLATFORM_WEB just uncomment #define PLATFORM_WEB at beginning +* +* This example has been created using raylib 5.0 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2023-2024 Afan OLOVCIC (@_DevDad) 2015 Ramon Santamaria (@raysan5) +* Model: "Old Rusty Car" (https://skfb.ly/LxRy) by Renafox is licensed under Creative Commons Attribution-NonCommercial (http://creativecommons.org/licenses/by-nc/4.0/). +********************************************************************************************/ + +#include "raylib.h" + +#if defined(PLATFORM_WEB) +#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 + + +//---------------------------------------------------------------------------------- +// Main Entry Point +//---------------------------------------------------------------------------------- +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + SetConfigFlags(FLAG_MSAA_4X_HINT); + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic pbr"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 2.0f, 2.0f, 6.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.5f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.projection = CAMERA_PERSPECTIVE; // Camera projection type + + + 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_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}; + float ambIntens = 0.02; + + int albedoLoc = GetShaderLocation(shader, "albedo"); + PBRSetAmbient(shader,ambCol,ambIntens); + + // Create lights + PBRLight lights[MAX_LIGHTS] = { 0 }; + lights[0] = PBRLightCreate(LIGHT_POINT, (Vector3){ -1, 1, -2 }, (Vector3){0,0,0}, YELLOW,4, shader); + 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); + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second------------------------------------------------------------- + + int emissiveCnt = 0; + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&camera, CAMERA_ORBITAL); + + // Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f }) + float cameraPos[3] = {camera.position.x, camera.position.y, camera.position.z}; + SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], cameraPos, SHADER_UNIFORM_VEC3); + + // Check key inputs to enable/disable lights + if (IsKeyPressed(KEY_Y)) { lights[0].enabled = !lights[0].enabled; } + if (IsKeyPressed(KEY_G)) { lights[1].enabled = !lights[1].enabled; } + if (IsKeyPressed(KEY_R)) { lights[2].enabled = !lights[2].enabled; } + if (IsKeyPressed(KEY_B)) { lights[3].enabled = !lights[3].enabled; } + + // 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); + + PBRDrawModel(floor, (Vector3){0,0,0}, 5.0f); + PBRDrawModel(model, (Vector3) {0, 0.0, 0}, 0.005); + + // Draw spheres to show where the lights are + 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); + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + //-------------------------------------------------------------------------------------- + // De-Initialization + //-------------------------------------------------------------------------------------- + + UnloadModel(floor.model); // Unload model + UnloadModel(model.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; + }