REDESIGNED: GenTexture*() #721

Functions have been redesigned to use rlgl and allow to externalize them (aka removing them from rlgl because they use custom shaders...).
This commit is contained in:
raysan5 2020-09-18 13:50:51 +02:00
parent b7867fb10d
commit 152665ff48
2 changed files with 187 additions and 206 deletions

View file

@ -1382,9 +1382,9 @@ RLAPI Matrix GetMatrixProjection(void); // Get
// Texture maps generation (PBR) // Texture maps generation (PBR)
// NOTE: Required shaders should be provided // NOTE: Required shaders should be provided
RLAPI Texture2D GenTextureCubemap(Shader shader, Texture2D map, int size); // Generate cubemap texture from 2D texture RLAPI TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size); // Generate cubemap texture from 2D panorama texture
RLAPI Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size); // Generate irradiance texture using cubemap data RLAPI TextureCubemap GenTextureIrradiance(Shader shader, TextureCubemap cubemap, int size); // Generate irradiance texture using cubemap data
RLAPI Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size); // Generate prefilter texture using cubemap data RLAPI TextureCubemap GenTexturePrefilter(Shader shader, TextureCubemap cubemap, int size); // Generate prefilter texture using cubemap data
RLAPI Texture2D GenTextureBRDF(Shader shader, int size); // Generate BRDF texture RLAPI Texture2D GenTextureBRDF(Shader shader, int size); // Generate BRDF texture
// Shading begin/end functions // Shading begin/end functions

View file

@ -504,6 +504,8 @@ RLAPI void rlColor4f(float x, float y, float z, float w); // Define one vertex (
RLAPI void rlEnableTexture(unsigned int id); // Enable texture usage RLAPI void rlEnableTexture(unsigned int id); // Enable texture usage
RLAPI void rlDisableTexture(void); // Disable texture usage RLAPI void rlDisableTexture(void); // Disable texture usage
RLAPI void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap) RLAPI void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap)
RLAPI void rlEnableShader(unsigned int id); // Enable shader program usage
RLAPI void rlDisableShader(void); // Disable shader program usage
RLAPI void rlEnableFramebuffer(unsigned int id); // Enable render texture (fbo) RLAPI void rlEnableFramebuffer(unsigned int id); // Enable render texture (fbo)
RLAPI void rlDisableFramebuffer(void); // Disable render texture (fbo), return to default framebuffer RLAPI void rlDisableFramebuffer(void); // Disable render texture (fbo), return to default framebuffer
RLAPI void rlEnableDepthTest(void); // Enable depth test RLAPI void rlEnableDepthTest(void); // Enable depth test
@ -589,9 +591,9 @@ RLAPI Matrix GetMatrixModelview(void); // Get
// Texture maps generation (PBR) // Texture maps generation (PBR)
// NOTE: Required shaders should be provided // NOTE: Required shaders should be provided
RLAPI TextureCubemap GenTextureCubemap(Shader shader, Texture2D map, int size); // Generate cubemap texture from HDR texture RLAPI TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size); // Generate cubemap texture from HDR texture
RLAPI Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size); // Generate irradiance texture using cubemap data RLAPI TextureCubemap GenTextureIrradiance(Shader shader, TextureCubemap cubemap, int size); // Generate irradiance texture using cubemap data
RLAPI Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size); // Generate prefilter texture using cubemap data RLAPI TextureCubemap GenTexturePrefilter(Shader shader, TextureCubemap cubemap, int size); // Generate prefilter texture using cubemap data
RLAPI Texture2D GenTextureBRDF(Shader shader, int size); // Generate BRDF texture using cubemap data RLAPI Texture2D GenTextureBRDF(Shader shader, int size); // Generate BRDF texture using cubemap data
// Shading begin/end functions // Shading begin/end functions
@ -1393,14 +1395,27 @@ void rlTextureParameters(unsigned int id, int param, int value)
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
} }
// Enable shader program usage
void rlEnableShader(unsigned int id)
{
#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
glUseProgram(id);
#endif
}
// Disable shader program usage
void rlDisableShader(void)
{
#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
glUseProgram(0);
#endif
}
// Enable rendering to texture (fbo) // Enable rendering to texture (fbo)
void rlEnableFramebuffer(unsigned int id) void rlEnableFramebuffer(unsigned int id)
{ {
#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT) #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT)
glBindFramebuffer(GL_FRAMEBUFFER, id); glBindFramebuffer(GL_FRAMEBUFFER, id);
//glDisable(GL_CULL_FACE); // Allow double side drawing for texture flipping
//glCullFace(GL_FRONT);
#endif #endif
} }
@ -1409,9 +1424,6 @@ void rlDisableFramebuffer(void)
{ {
#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT) #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(SUPPORT_RENDER_TEXTURES_HINT)
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
//glEnable(GL_CULL_FACE);
//glCullFace(GL_BACK);
#endif #endif
} }
@ -3268,91 +3280,69 @@ Matrix GetMatrixModelview(void)
} }
// Generate cubemap texture from HDR texture // Generate cubemap texture from HDR texture
// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24 TextureCubemap GenTextureCubemap(Shader shader, Texture2D panorama, int size)
Texture2D GenTextureCubemap(Shader shader, Texture2D map, int size)
{ {
Texture2D cubemap = { 0 }; TextureCubemap cubemap = { 0 };
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube
// Other locations should be setup externally in shader before calling the function
// Set up depth face culling and cubemap seamless // STEP 1: Setup framebuffer
glDisable(GL_CULL_FACE); //------------------------------------------------------------------------------------------
#if defined(GRAPHICS_API_OPENGL_33) unsigned int rbo = rlLoadTextureDepth(size, size, true);
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Flag not supported on OpenGL ES 2.0 cubemap.id = rlLoadTextureCubemap(NULL, size, UNCOMPRESSED_R32G32B32);
#endif
unsigned int fbo = rlLoadFramebuffer(size, size);
rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER);
rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X);
//------------------------------------------------------------------------------------------
// Setup framebuffer // STEP 2: Draw to framebuffer
unsigned int fbo, rbo; //------------------------------------------------------------------------------------------
glGenFramebuffers(1, &fbo); // NOTE: Shader is used to convert HDR equirectangular environment map to cubemap equivalent (6 faces)
glGenRenderbuffers(1, &rbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
#if defined(GRAPHICS_API_OPENGL_33)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size);
#elif defined(GRAPHICS_API_OPENGL_ES2)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
#endif
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
// Set up cubemap to render and attach to framebuffer // Define projection matrix and send it to shader
// NOTE: Faces are stored as 32 bit floating point values
glGenTextures(1, &cubemap.id);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id);
for (unsigned int i = 0; i < 6; i++)
{
#if defined(GRAPHICS_API_OPENGL_33)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB32F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
#elif defined(GRAPHICS_API_OPENGL_ES2)
if (RLGL.ExtSupported.texFloat32) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, NULL);
#endif
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#if defined(GRAPHICS_API_OPENGL_33)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // Flag not supported on OpenGL ES 2.0
#endif
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Create projection and different views for each face
Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR);
SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection);
// Define view matrix for every side of the cubemap
Matrix fboViews[6] = { 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){ -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, -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 }),
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 })
}; };
// Convert HDR equirectangular environment map to cubemap equivalent rlEnableShader(shader.id);
glUseProgram(shader.id);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, map.id); glBindTexture(GL_TEXTURE_2D, panorama.id);
SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection);
// Note: don't forget to configure the viewport to the capture dimensions rlViewport(0, 0, size, size); // Set viewport to current fbo dimensions
glViewport(0, 0, size, size);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]); SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemap.id, 0); rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
rlEnableFramebuffer(fbo);
rlClearScreenBuffers();
GenDrawCube(); GenDrawCube();
} }
//------------------------------------------------------------------------------------------
// Unbind framebuffer and textures // STEP 3: Unload framebuffer and reset state
glBindFramebuffer(GL_FRAMEBUFFER, 0); //------------------------------------------------------------------------------------------
rlDisableShader(); // Unbind shader
rlDisableTexture(); // Unbind texture
rlDisableFramebuffer(); // Unbind framebuffer
rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer)
// Reset viewport dimensions to default // Reset viewport dimensions to default
glViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight); rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight);
//glEnable(GL_CULL_FACE); //rlEnableBackfaceCulling();
//------------------------------------------------------------------------------------------
// NOTE: Texture2D is a GL_TEXTURE_CUBE_MAP, not a GL_TEXTURE_2D!
cubemap.width = size; cubemap.width = size;
cubemap.height = size; cubemap.height = size;
cubemap.mipmaps = 1; cubemap.mipmaps = 1;
@ -3362,137 +3352,126 @@ Texture2D GenTextureCubemap(Shader shader, Texture2D map, int size)
} }
// Generate irradiance texture using cubemap data // Generate irradiance texture using cubemap data
// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24 TextureCubemap GenTextureIrradiance(Shader shader, TextureCubemap cubemap, int size)
Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size)
{ {
Texture2D irradiance = { 0 }; TextureCubemap irradiance = { 0 };
#if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube
// Other locations should be setup externally in shader before calling the function
// Setup framebuffer // STEP 1: Setup framebuffer
unsigned int fbo, rbo; //------------------------------------------------------------------------------------------
glGenFramebuffers(1, &fbo); unsigned int rbo = rlLoadTextureDepth(size, size, true);
glGenRenderbuffers(1, &rbo); irradiance.id = rlLoadTextureCubemap(NULL, size, UNCOMPRESSED_R32G32B32);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo); unsigned int fbo = rlLoadFramebuffer(size, size);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size); rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo); rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X);
//------------------------------------------------------------------------------------------
// Create an irradiance cubemap, and re-scale capture FBO to irradiance scale // STEP 2: Draw to framebuffer
glGenTextures(1, &irradiance.id); //------------------------------------------------------------------------------------------
glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance.id); // NOTE: Shader is used to solve diffuse integral by convolution to create an irradiance cubemap
for (unsigned int i = 0; i < 6; i++)
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // Define projection matrix and send it to shader
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Create projection (transposed) and different views for each face
Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR);
SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection);
// Define view matrix for every side of the cubemap
Matrix fboViews[6] = { 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){ -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, -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 }),
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 })
}; };
// Solve diffuse integral by convolution to create an irradiance cubemap rlEnableShader(shader.id);
glUseProgram(shader.id);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id); glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id);
SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection);
// Note: don't forget to configure the viewport to the capture dimensions rlViewport(0, 0, size, size); // Set viewport to current fbo dimensions
glViewport(0, 0, size, size);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]); SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradiance.id, 0); rlFramebufferAttach(fbo, irradiance.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
rlEnableFramebuffer(fbo);
rlClearScreenBuffers();
GenDrawCube(); GenDrawCube();
} }
//------------------------------------------------------------------------------------------
// Unbind framebuffer and textures // STEP 3: Unload framebuffer and reset state
glBindFramebuffer(GL_FRAMEBUFFER, 0); //------------------------------------------------------------------------------------------
rlDisableShader(); // Unbind shader
rlDisableTexture(); // Unbind texture
rlDisableFramebuffer(); // Unbind framebuffer
rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer)
// Reset viewport dimensions to default // Reset viewport dimensions to default
glViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight); rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight);
//rlEnableBackfaceCulling();
//------------------------------------------------------------------------------------------
irradiance.width = size; irradiance.width = size;
irradiance.height = size; irradiance.height = size;
irradiance.mipmaps = 1; irradiance.mipmaps = 1;
//irradiance.format = UNCOMPRESSED_R16G16B16; irradiance.format = UNCOMPRESSED_R32G32B32;
#endif #endif
return irradiance; return irradiance;
} }
// Generate prefilter texture using cubemap data // Generate prefilter texture using cubemap data
// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24 TextureCubemap GenTexturePrefilter(Shader shader, TextureCubemap cubemap, int size)
Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size)
{ {
Texture2D prefilter = { 0 }; TextureCubemap prefilter = { 0 };
#if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader rlDisableBackfaceCulling(); // Disable backface culling to render inside the cube
// Other locations should be setup externally in shader before calling the function
// TODO: Locations should be taken out of this function... too shader dependant...
int roughnessLoc = GetShaderLocation(shader, "roughness");
// Setup framebuffer // STEP 1: Setup framebuffer
unsigned int fbo, rbo; //------------------------------------------------------------------------------------------
glGenFramebuffers(1, &fbo); unsigned int rbo = rlLoadTextureDepth(size, size, true);
glGenRenderbuffers(1, &rbo); prefilter.id = rlLoadTextureCubemap(NULL, size, UNCOMPRESSED_R32G32B32);
glBindFramebuffer(GL_FRAMEBUFFER, fbo); rlTextureParameters(prefilter.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_LINEAR);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size); unsigned int fbo = rlLoadFramebuffer(size, size);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo); rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER);
rlFramebufferAttach(fbo, cubemap.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X);
// Create a prefiltered HDR environment map //------------------------------------------------------------------------------------------
glGenTextures(1, &prefilter.id);
glBindTexture(GL_TEXTURE_CUBE_MAP, prefilter.id);
for (unsigned int i = 0; i < 6; i++)
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Generate mipmaps for the prefiltered HDR texture // Generate mipmaps for the prefiltered HDR texture
glGenerateMipmap(GL_TEXTURE_CUBE_MAP); glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
// Create projection (transposed) and different views for each face // STEP 2: Draw to framebuffer
//------------------------------------------------------------------------------------------
// NOTE: Shader is used to prefilter HDR and store data into mipmap levels
// Define projection matrix and send it to shader
Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR); Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, RL_CULL_DISTANCE_NEAR, RL_CULL_DISTANCE_FAR);
SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection);
// Define view matrix for every side of the cubemap
Matrix fboViews[6] = { 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){ -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, -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 }),
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 })
}; };
// Prefilter HDR and store data into mipmap levels rlEnableShader(shader.id);
glUseProgram(shader.id);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id); glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id);
SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection);
glBindFramebuffer(GL_FRAMEBUFFER, fbo); // TODO: Locations should be taken out of this function... too shader dependant...
int roughnessLoc = GetShaderLocation(shader, "roughness");
rlEnableFramebuffer(fbo);
#define MAX_MIPMAP_LEVELS 5 // Max number of prefilter texture mipmaps #define MAX_MIPMAP_LEVELS 5 // Max number of prefilter texture mipmaps
@ -3501,11 +3480,12 @@ Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size)
// Resize framebuffer according to mip-level size. // Resize framebuffer according to mip-level size.
unsigned int mipWidth = size*(int)powf(0.5f, (float)mip); unsigned int mipWidth = size*(int)powf(0.5f, (float)mip);
unsigned int mipHeight = size*(int)powf(0.5f, (float)mip); unsigned int mipHeight = size*(int)powf(0.5f, (float)mip);
rlViewport(0, 0, mipWidth, mipHeight);
glBindRenderbuffer(GL_RENDERBUFFER, rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight);
glViewport(0, 0, mipWidth, mipHeight);
float roughness = (float)mip/(float)(MAX_MIPMAP_LEVELS - 1); float roughness = (float)mip/(float)(MAX_MIPMAP_LEVELS - 1);
glUniform1f(roughnessLoc, roughness); glUniform1f(roughnessLoc, roughness);
@ -3513,73 +3493,74 @@ Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size)
{ {
SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]); SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilter.id, mip); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilter.id, mip);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //rlFramebufferAttach(fbo, irradiance.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_CUBEMAP_POSITIVE_X + i); // TODO: Support mip levels?
rlEnableFramebuffer(fbo);
rlClearScreenBuffers();
GenDrawCube(); GenDrawCube();
} }
} }
//------------------------------------------------------------------------------------------
// Unbind framebuffer and textures // STEP 3: Unload framebuffer and reset state
glBindFramebuffer(GL_FRAMEBUFFER, 0); //------------------------------------------------------------------------------------------
rlDisableShader(); // Unbind shader
rlDisableTexture(); // Unbind texture
rlDisableFramebuffer(); // Unbind framebuffer
rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer)
// Reset viewport dimensions to default // Reset viewport dimensions to default
glViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight); rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight);
//rlEnableBackfaceCulling();
//------------------------------------------------------------------------------------------
prefilter.width = size; prefilter.width = size;
prefilter.height = size; prefilter.height = size;
//prefilter.mipmaps = 1 + (int)floor(log(size)/log(2)); //prefilter.mipmaps = 1 + (int)floor(log(size)/log(2)); // MAX_MIPMAP_LEVELS
//prefilter.format = UNCOMPRESSED_R16G16B16; //prefilter.format = UNCOMPRESSED_R32G32B32;
#endif #endif
return prefilter; return prefilter;
} }
// Generate BRDF texture using cubemap data // Generate BRDF texture using cubemap data
// NOTE: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24
// TODO: Review implementation: https://github.com/HectorMF/BRDFGenerator // TODO: Review implementation: https://github.com/HectorMF/BRDFGenerator
Texture2D GenTextureBRDF(Shader shader, int size) Texture2D GenTextureBRDF(Shader shader, int size)
{ {
Texture2D brdf = { 0 }; Texture2D brdf = { 0 };
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Generate BRDF convolution texture // STEP 1: Setup framebuffer
glGenTextures(1, &brdf.id); //------------------------------------------------------------------------------------------
glBindTexture(GL_TEXTURE_2D, brdf.id); unsigned int rbo = rlLoadTextureDepth(size, size, true);
#if defined(GRAPHICS_API_OPENGL_33) brdf.id = rlLoadTexture(NULL, size, size, UNCOMPRESSED_R32G32B32, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
#elif defined(GRAPHICS_API_OPENGL_ES2)
if (RLGL.ExtSupported.texFloat32) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, NULL);
#endif
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); unsigned int fbo = rlLoadFramebuffer(size, size);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); rlFramebufferAttach(fbo, rbo, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); rlFramebufferAttach(fbo, brdf.id, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //------------------------------------------------------------------------------------------
// Render BRDF LUT into a quad using FBO // STEP 2: Draw to framebuffer
unsigned int fbo, rbo; //------------------------------------------------------------------------------------------
glGenFramebuffers(1, &fbo); // NOTE: Render BRDF LUT into a quad using FBO
glGenRenderbuffers(1, &rbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
#if defined(GRAPHICS_API_OPENGL_33)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size);
#elif defined(GRAPHICS_API_OPENGL_ES2)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
#endif
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, brdf.id, 0);
glViewport(0, 0, size, size); rlEnableShader(shader.id);
glUseProgram(shader.id);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); rlViewport(0, 0, size, size);
rlEnableFramebuffer(fbo);
rlClearScreenBuffers();
GenDrawQuad(); GenDrawQuad();
//------------------------------------------------------------------------------------------
// Unbind framebuffer and textures // STEP 3: Unload framebuffer and reset state
glBindFramebuffer(GL_FRAMEBUFFER, 0); //------------------------------------------------------------------------------------------
rlDisableShader(); // Unbind shader
// Unload framebuffer but keep color texture rlDisableTexture(); // Unbind texture
glDeleteRenderbuffers(1, &rbo); rlDisableFramebuffer(); // Unbind framebuffer
glDeleteFramebuffers(1, &fbo); rlUnloadFramebuffer(fbo); // Unload framebuffer (and automatically attached depth texture/renderbuffer)
// Reset viewport dimensions to default // Reset viewport dimensions to default
glViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight); rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight);
//------------------------------------------------------------------------------------------
brdf.width = size; brdf.width = size;
brdf.height = size; brdf.height = size;