diff --git a/examples/models/models_material_pbr.c b/examples/models/models_material_pbr.c index ed82d397..f0420d30 100644 --- a/examples/models/models_material_pbr.c +++ b/examples/models/models_material_pbr.c @@ -243,10 +243,10 @@ static Material LoadMaterialPBR(Color albedo, float metalness, float roughness) // Texture maps generation (PBR) //------------------------------------------------------------------------------------------- // Generate cubemap texture from HDR texture -TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size, int format) +static TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size, int format) { TextureCubemap cubemap = { 0 }; -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube // STEP 1: Setup framebuffer @@ -281,11 +281,6 @@ TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size, in MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }) }; -#if !defined(GENTEXTURECUBEMAP_USE_BATCH_SYSTEM) - rlActiveTextureSlot(0); - rlEnableTexture(panorama.id); -#endif - rlViewport(0, 0, size, size); // Set viewport to current fbo dimensions for (int i = 0; i < 6; i++) @@ -294,18 +289,11 @@ TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size, in rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i, 0); rlEnableFramebuffer(fbo); -#if defined(GENTEXTURECUBEMAP_USE_BATCH_SYSTEM) rlSetTexture(panorama.id); // WARNING: It must be called after enabling current framebuffer if using internal batch system! -#endif - rlClearScreenBuffers(); - rlLoadDrawCube(); -#if defined(GENTEXTURECUBEMAP_USE_BATCH_SYSTEM) - // Using internal batch system instead of raw OpenGL cube creating+drawing - // NOTE: DrawCubeV() is actually provided by models.c! -> GenTextureCubemap() should be moved to user code! + rlClearScreenBuffers(); DrawCubeV(Vector3Zero(), Vector3One(), WHITE); rlDrawRenderBatch(RLGL.currentBatch); -#endif } //------------------------------------------------------------------------------------------ @@ -325,16 +313,15 @@ TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size, in cubemap.height = size; cubemap.mipmaps = 1; cubemap.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32; -#endif + return cubemap; } // Generate irradiance texture using cubemap data -TextureCubemap GenTextureIrradiance(Shader shader, TextureCubemap cubemap, int size) +static TextureCubemap GenTextureIrradiance(Shader shader, TextureCubemap cubemap, int size) { TextureCubemap irradiance = { 0 }; -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube // STEP 1: Setup framebuffer @@ -398,16 +385,15 @@ TextureCubemap GenTextureIrradiance(Shader shader, TextureCubemap cubemap, int s irradiance.height = size; irradiance.mipmaps = 1; irradiance.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32; -#endif + return irradiance; } // Generate prefilter texture using cubemap data -TextureCubemap GenTexturePrefilter(Shader shader, TextureCubemap cubemap, int size) +static TextureCubemap GenTexturePrefilter(Shader shader, TextureCubemap cubemap, int size) { TextureCubemap prefilter = { 0 }; -#if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2) rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube // STEP 1: Setup framebuffer @@ -494,16 +480,16 @@ TextureCubemap GenTexturePrefilter(Shader shader, TextureCubemap cubemap, int si prefilter.height = size; prefilter.mipmaps = MAX_MIPMAP_LEVELS; prefilter.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32; -#endif + return prefilter; } // Generate BRDF texture using cubemap data // TODO: Review implementation: https://github.com/HectorMF/BRDFGenerator -Texture2D GenTextureBRDF(Shader shader, int size) +static Texture2D GenTextureBRDF(Shader shader, int size) { Texture2D brdf = { 0 }; -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // STEP 1: Setup framebuffer //------------------------------------------------------------------------------------------ unsigned int rbo = rlLoadTextureDepth(size, size, true); @@ -542,6 +528,6 @@ Texture2D GenTextureBRDF(Shader shader, int size) brdf.height = size; brdf.mipmaps = 1; brdf.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32; -#endif + return brdf; } diff --git a/examples/models/models_skybox.c b/examples/models/models_skybox.c index e03aaab0..cef34611 100644 --- a/examples/models/models_skybox.c +++ b/examples/models/models_skybox.c @@ -12,7 +12,8 @@ #include "raylib.h" #include "rlgl.h" -bool useHDR = false; +// Generate cubemap (6 faces) from equirectangular (panorama) texture +static TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size, int format); int main(void) { @@ -29,6 +30,8 @@ int main(void) // Load skybox model Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f); Model skybox = LoadModelFromMesh(cube); + + bool useHDR = false; // Load skybox shader and set required locations // NOTE: Some locations are automatically set at shader loading @@ -62,7 +65,7 @@ int main(void) // NOTE 1: New texture is generated rendering to texture, shader calculates the sphere->cube coordinates mapping // NOTE 2: It seems on some Android devices WebGL, fbo does not properly support a FLOAT-based attachment, // despite texture can be successfully created.. so using PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 instead of PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 - skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = rlGenTextureCubemap(shdrCubemap, panorama, 1024, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); + skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = GenTextureCubemap(shdrCubemap, panorama, 1024, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); UnloadTexture(panorama); // Texture not required anymore, cubemap already generated } @@ -102,7 +105,7 @@ int main(void) Texture2D panorama = LoadTexture(droppedFiles[0]); // Generate cubemap from panorama texture - skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = rlGenTextureCubemap(shdrCubemap, panorama, 1024, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); + skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = GenTextureCubemap(shdrCubemap, panorama, 1024, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); UnloadTexture(panorama); } else @@ -162,3 +165,78 @@ int main(void) return 0; } + +// Generate cubemap texture from HDR texture +static TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size, int format) +{ + TextureCubemap cubemap = { 0 }; + + rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube + + // STEP 1: Setup framebuffer + //------------------------------------------------------------------------------------------ + unsigned int rbo = rlLoadTextureDepth(size, size, true); + cubemap.id = rlLoadTextureCubemap(0, size, format); + + unsigned int fbo = rlLoadFramebuffer(size, size); + rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0); + rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X, 0); + + // Check if framebuffer is complete with attachments (valid) + if (rlFramebufferComplete(fbo)) TraceLog(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", fbo); + //------------------------------------------------------------------------------------------ + + // STEP 2: Draw to framebuffer + //------------------------------------------------------------------------------------------ + // NOTE: Shader is used to convert HDR equirectangular environment map to cubemap equivalent (6 faces) + rlEnableShader(shader.id); + + // Define projection matrix and send it to shader + Matrix matFboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); + rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_PROJECTION], matFboProjection); + + // Define view matrix for every side of the cubemap + Matrix fboViews[6] = { + MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), + MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), + MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }), + MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }), + MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }), + MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, -1.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }) + }; + + rlViewport(0, 0, size, size); // Set viewport to current fbo dimensions + + for (int i = 0; i < 6; i++) + { + rlSetUniformMatrix(shader.locs[SHADER_LOC_MATRIX_VIEW], fboViews[i]); + rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i, 0); + + rlEnableFramebuffer(fbo); + rlSetTexture(panorama.id); // WARNING: It must be called after enabling current framebuffer if using internal batch system! + + rlClearScreenBuffers(); + DrawCubeV(Vector3Zero(), Vector3One(), WHITE); + rlDrawRenderBatchActive(); + } + //------------------------------------------------------------------------------------------ + + // STEP 3: Unload framebuffer and reset state + //------------------------------------------------------------------------------------------ + rlDisableShader(); // Unbind shader + rlDisableTexture(); // Unbind texture + rlDisableFramebuffer(); // Unbind framebuffer + rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer) + + // Reset viewport dimensions to default + rlViewport(0, 0, rlGetFramebufferWidth(), rlGetFramebufferHeight()); + rlEnableBackfaceCulling(); + //------------------------------------------------------------------------------------------ + + cubemap.width = size; + cubemap.height = size; + cubemap.mipmaps = 1; + cubemap.format = PIXELFORMAT_UNCOMPRESSED_R32G32B32; + + return cubemap; +}