diff --git a/examples/shaders/resources/shaders/glsl100/deferred_shading.fs b/examples/shaders/resources/shaders/glsl100/deferred_shading.fs index d782792b940e..369316c774f3 100644 --- a/examples/shaders/resources/shaders/glsl100/deferred_shading.fs +++ b/examples/shaders/resources/shaders/glsl100/deferred_shading.fs @@ -1,12 +1,11 @@ -#version 100 +#version 300 es + +precision highp float; -precision mediump float; +out vec4 finalColor; -// Input vertex attributes (from vertex shader) -varying vec2 fragTexCoord; -varying vec4 fragColor; +in vec2 texCoord; -// Input uniform values uniform sampler2D gPosition; uniform sampler2D gNormal; uniform sampler2D gAlbedoSpec; @@ -26,34 +25,32 @@ uniform vec3 viewPosition; const float QUADRATIC = 0.032; const float LINEAR = 0.09; -void main() -{ - vec3 fragPosition = texture2D(gPosition, fragTexCoord).rgb; - vec3 normal = texture2D(gNormal, fragTexCoord).rgb; - vec3 albedo = texture2D(gAlbedoSpec, fragTexCoord).rgb; - float specular = texture2D(gAlbedoSpec, fragTexCoord).a; +void main() { + vec3 fragPosition = texture(gPosition, texCoord).rgb; + vec3 normal = texture(gNormal, texCoord).rgb; + vec3 albedo = texture(gAlbedoSpec, texCoord).rgb; + float specular = pow(texture(gAlbedoSpec, texCoord).a,8.0); - vec3 ambient = albedo*vec3(0.1); + vec3 ambient = albedo * vec3(0.03f); vec3 viewDirection = normalize(viewPosition - fragPosition); - for (int i = 0; i < NR_LIGHTS; ++i) + for(int i = 0; i < NR_LIGHTS; ++i) { if(lights[i].enabled == 0) continue; vec3 lightDirection = lights[i].position - fragPosition; - vec3 diffuse = max(dot(normal, lightDirection), 0.0)*albedo*lights[i].color.xyz; + vec3 diffuse = max(dot(normal, lightDirection), 0.0) * albedo * lights[i].color.xyz; vec3 halfwayDirection = normalize(lightDirection + viewDirection); - float spec = pow(max(dot(normal, halfwayDirection), 0.0), 32.0); - vec3 specular = specular*spec*lights[i].color.xyz; + float spec = pow(max(dot(normal, halfwayDirection), 0.0), 16.0); + vec3 specular = specular * spec * lights[i].color.xyz; // Attenuation float distance = length(lights[i].position - fragPosition); - float attenuation = 1.0/(1.0 + LINEAR * distance + QUADRATIC*distance*distance); + float attenuation = 1.0 / (1.0 + LINEAR * distance + QUADRATIC * distance * distance); diffuse *= attenuation; specular *= attenuation; ambient += diffuse + specular; } - gl_FragColor = vec4(ambient, 1.0); + finalColor = vec4(ambient, 1.0); } - diff --git a/examples/shaders/resources/shaders/glsl100/deferred_shading.vs b/examples/shaders/resources/shaders/glsl100/deferred_shading.vs index bb108ce09aba..3b55bc41e1fd 100644 --- a/examples/shaders/resources/shaders/glsl100/deferred_shading.vs +++ b/examples/shaders/resources/shaders/glsl100/deferred_shading.vs @@ -1,16 +1,13 @@ -#version 100 +#version 300 es -// Input vertex attributes -attribute vec3 vertexPosition; -attribute vec2 vertexTexCoord; +precision highp float; -// Output vertex attributes (to fragment shader) -varying vec2 fragTexCoord; +in vec3 vertexPosition; +in vec2 vertexTexCoord; -void main() -{ - fragTexCoord = vertexTexCoord; +out vec2 texCoord; - // Calculate final vertex position - gl_Position = vec4(vertexPosition, 1.0); +void main() { + gl_Position = vec4(vertexPosition, 1.0); + texCoord = vertexTexCoord; } diff --git a/examples/shaders/resources/shaders/glsl100/gbuffer.fs b/examples/shaders/resources/shaders/glsl100/gbuffer.fs index 2945c5ddd379..f18c965618f4 100644 --- a/examples/shaders/resources/shaders/glsl100/gbuffer.fs +++ b/examples/shaders/resources/shaders/glsl100/gbuffer.fs @@ -1,36 +1,28 @@ -#version 100 +#version 300 es -precision mediump float; +precision highp float; -// Input vertex attributes (from vertex shader) -varying vec3 fragPosition; -varying vec2 fragTexCoord; -varying vec3 fragNormal; -varying vec4 fragColor; +layout (location = 0) out vec4 gPosition; +layout (location = 1) out vec4 gNormal; +layout (location = 2) out vec4 gAlbedoSpec; -// TODO: Is there some alternative for GLSL100 -//layout (location = 0) out vec3 gPosition; -//layout (location = 1) out vec3 gNormal; -//layout (location = 2) out vec4 gAlbedoSpec; -//uniform vec3 gPosition; -//uniform vec3 gNormal; -//uniform vec4 gAlbedoSpec; +in vec3 fragPosition; +in vec2 fragTexCoord; +in vec3 fragNormal; +in vec4 fragColor; -// Input uniform values -uniform sampler2D texture0; // Diffuse texture -uniform sampler2D specularTexture; +uniform vec4 colDiffuse; -void main() -{ - // Store the fragment position vector in the first gbuffer texture - //gPosition = fragPosition; - - // Store the per-fragment normals into the gbuffer - //gNormal = normalize(fragNormal); - - // Store the diffuse per-fragment color - gl_FragColor.rgb = texture2D(texture0, fragTexCoord).rgb; - - // Store specular intensity in gAlbedoSpec's alpha component - gl_FragColor.a = texture2D(specularTexture, fragTexCoord).r; +uniform sampler2D texture0; +uniform sampler2D texture1; + +void main() { + // store the fragment position vector in the first gbuffer texture + gPosition = vec4(fragPosition,1.0); + // also store the per-fragment normals into the gbuffer + gNormal = vec4(normalize(fragNormal),1.0); + // and the diffuse per-fragment color + gAlbedoSpec.rgb = texture(texture0, fragTexCoord).rgb * colDiffuse.rgb; + // store specular intensity in gAlbedoSpec's alpha component + gAlbedoSpec.a = pow(texture(texture1, fragTexCoord).r*1.6,16.0); } diff --git a/examples/shaders/resources/shaders/glsl100/gbuffer.vs b/examples/shaders/resources/shaders/glsl100/gbuffer.vs index 2791ce5ee127..d9484f273589 100644 --- a/examples/shaders/resources/shaders/glsl100/gbuffer.vs +++ b/examples/shaders/resources/shaders/glsl100/gbuffer.vs @@ -1,60 +1,30 @@ -#version 100 +#version 300 es -// Input vertex attributes -attribute vec3 vertexPosition; -attribute vec2 vertexTexCoord; -attribute vec3 vertexNormal; -attribute vec4 vertexColor; +precision highp float; + +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec3 vertexNormal; +in vec4 vertexColor; + +out vec3 fragPosition; +out vec2 fragTexCoord; +out vec3 fragNormal; +out vec4 fragColor; -// Input uniform values uniform mat4 matModel; uniform mat4 matView; uniform mat4 matProjection; -// Output vertex attributes (to fragment shader) -varying vec3 fragPosition; -varying vec2 fragTexCoord; -varying vec3 fragNormal; -varying vec4 fragColor; - - -// https://github.com/glslify/glsl-inverse -mat3 inverse(mat3 m) -{ - float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2]; - float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2]; - float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2]; - - float b01 = a22*a11 - a12*a21; - float b11 = -a22*a10 + a12*a20; - float b21 = a21*a10 - a11*a20; - - float det = a00*b01 + a01*b11 + a02*b21; - - return mat3(b01, (-a22*a01 + a02*a21), (a12*a01 - a02*a11), - b11, (a22*a00 - a02*a20), (-a12*a00 + a02*a10), - b21, (-a21*a00 + a01*a20), (a11*a00 - a01*a10))/det; -} - -// https://github.com/glslify/glsl-transpose -mat3 transpose(mat3 m) -{ - return mat3(m[0][0], m[1][0], m[2][0], - m[0][1], m[1][1], m[2][1], - m[0][2], m[1][2], m[2][2]); -} - void main() { - // Calculate vertex attributes for fragment shader - vec4 worldPos = matModel*vec4(vertexPosition, 1.0); + vec4 worldPos = matModel * vec4(vertexPosition, 1.0); fragPosition = worldPos.xyz; fragTexCoord = vertexTexCoord; fragColor = vertexColor; mat3 normalMatrix = transpose(inverse(mat3(matModel))); - fragNormal = normalMatrix*vertexNormal; + fragNormal = normalMatrix * vertexNormal; - // Calculate final vertex position - gl_Position = matProjection*matView*worldPos; + gl_Position = matProjection * matView * worldPos; } diff --git a/examples/shaders/shaders_deferred_render.c b/examples/shaders/shaders_deferred_render.c index 13600bc09513..e40418c06170 100644 --- a/examples/shaders/shaders_deferred_render.c +++ b/examples/shaders/shaders_deferred_render.c @@ -6,7 +6,7 @@ * * NOTE: This example requires raylib OpenGL 3.3 or OpenGL ES 3.0 * -* Example originally created with raylib 4.5, last time updated with raylib 4.5 +* Example originally created with raylib 4.5, last time updated for raylib 5.6 * * Example contributed by Justin Andreas Lacoste (@27justin) and reviewed by Ramon Santamaria (@raysan5) * @@ -16,6 +16,23 @@ * Copyright (c) 2023 Justin Andreas Lacoste (@27justin) * ********************************************************************************************/ +// the following #define of GLSL_VERSION is used only for file access +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 + #define GRAPHICS_API_OPENGL_33 +#else // PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 + #define GRAPHICS_API_OPENGL_ES3 +#endif + + +#include // Required for: NULL + +#ifdef PLATFORM_WEB + #include +#else + #include +#endif #include "raylib.h" @@ -25,13 +42,6 @@ #define RLIGHTS_IMPLEMENTATION #include "rlights.h" -#if defined(PLATFORM_DESKTOP) - #define GLSL_VERSION 330 -#else // PLATFORM_ANDROID, PLATFORM_WEB - #define GLSL_VERSION 100 -#endif - -#include // Required for: NULL #define MAX_CUBES 30 @@ -54,6 +64,32 @@ typedef enum { DEFERRED_SHADING } DeferredMode; +// Load depth texture/renderbuffer (to be attached to fbo) +unsigned int custom_LoadRenderbufferDepth(int width, int height) +{ + unsigned int id = 0; + // GL_DEPTH24_STENCIL8 is the default for GLFW OpenGL context and raylib uses it, you might need to change this for + // different raylib's backends like SDL, RGFW, ... + // Possible formats: GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT32F and GL_DEPTH32F_STENCIL8 (the list might vary depending on the platform the code is run on) + unsigned int glInternalFormat = GL_DEPTH24_STENCIL8; + glGenRenderbuffers(1, &id); + glBindRenderbuffer(GL_RENDERBUFFER, id); + glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + return id; +} + +unsigned int custom_LoadTexture(int w,int h, unsigned int opengl_format) +{ +unsigned int texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, opengl_format, w, h, 0, GL_RGBA, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +return texture; +} + //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ @@ -98,17 +134,23 @@ int main(void) rlEnableFramebuffer(gBuffer.framebuffer); // NOTE: Vertex positions are stored in a texture for simplicity. A better approach would use a depth texture - // (instead of a detph renderbuffer) to reconstruct world positions in the final render shader via clip-space position, + // (instead of a depth renderbuffer) to reconstruct world positions in the final render shader via clip-space position, // depth, and the inverse view/projection matrices. - // 16-bit precision ensures OpenGL ES 3 compatibility, though it may lack precision for real scenarios. - // But as mentioned above, the positions could be reconstructed instead of stored. If not targeting OpenGL ES - // and you wish to maintain this approach, consider using `RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32`. - gBuffer.positionTexture = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16, 1); - - // Similarly, 16-bit precision is used for normals ensures OpenGL ES 3 compatibility. - // This is generally sufficient, but a 16-bit fixed-point format offer a better uniform precision in all orientations. - gBuffer.normalTexture = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16, 1); + // 32-bit precision used on desktop as well as for OpenGL ES 3. + #ifdef PLATFORM_WEB + gBuffer.positionTexture = custom_LoadTexture(screenWidth,screenHeight,GL_RGBA32F); + #else + // But as mentioned above, the positions could be reconstructed instead of stored. + gBuffer.positionTexture = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32, 1); + #endif + + // Similarly, 32-bit precision is used for normals on desktop as well as OpenGL ES 3. + #ifdef PLATFORM_WEB + gBuffer.normalTexture = custom_LoadTexture(screenWidth,screenHeight,GL_RGBA32F); + #else + gBuffer.normalTexture = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32, 1); + #endif // Albedo (diffuse color) and specular strength can be combined into one texture. // The color in RGB, and the specular strength in the alpha channel. @@ -123,7 +165,7 @@ int main(void) rlFramebufferAttach(gBuffer.framebuffer, gBuffer.albedoSpecTexture, RL_ATTACHMENT_COLOR_CHANNEL2, RL_ATTACHMENT_TEXTURE2D, 0); // Finally we attach the depth buffer. - gBuffer.depthRenderbuffer = rlLoadTextureDepth(screenWidth, screenHeight, true); + gBuffer.depthRenderbuffer = custom_LoadRenderbufferDepth(screenWidth, screenHeight); rlFramebufferAttach(gBuffer.framebuffer, gBuffer.depthRenderbuffer, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0); // Make sure our framebuffer is complete. @@ -132,23 +174,33 @@ int main(void) if (!rlFramebufferComplete(gBuffer.framebuffer)) { TraceLog(LOG_WARNING, "Framebuffer is not complete"); + exit(1); } // Now we initialize the sampler2D uniform's in the deferred shader. // We do this by setting the uniform's values to the texture units that // we later bind our g-buffer textures to. rlEnableShader(deferredShader.id); - int texUnitPosition = 0; - int texUnitNormal = 1; - int texUnitAlbedoSpec = 2; - SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gPosition"), &texUnitPosition, RL_SHADER_UNIFORM_SAMPLER2D); - SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gNormal"), &texUnitNormal, RL_SHADER_UNIFORM_SAMPLER2D); - SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gAlbedoSpec"), &texUnitAlbedoSpec, RL_SHADER_UNIFORM_SAMPLER2D); + int texUnitPosition = 0; + int texUnitNormal = 1; + int texUnitAlbedoSpec = 2; + SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gPosition"), &texUnitPosition, RL_SHADER_UNIFORM_SAMPLER2D); + SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gNormal"), &texUnitNormal, RL_SHADER_UNIFORM_SAMPLER2D); + SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gAlbedoSpec"), &texUnitAlbedoSpec, RL_SHADER_UNIFORM_SAMPLER2D); rlDisableShader(); // Assign out lighting shader to model model.materials[0].shader = gbufferShader; cube.materials[0].shader = gbufferShader; + + // add some specular noise to the material + Image tmp_img2=GenImagePerlinNoise(256,256,0,0,8.0); + Texture texture_specular=LoadTextureFromImage(tmp_img2); + UnloadImage(tmp_img2); + + cube.materials[0].maps[MATERIAL_MAP_METALNESS].texture=texture_specular; + + model.materials[0].maps[MATERIAL_MAP_METALNESS].texture=texture_specular; // Create lights //-------------------------------------------------------------------------------------- @@ -161,6 +213,7 @@ int main(void) const float CUBE_SCALE = 0.25; Vector3 cubePositions[MAX_CUBES] = { 0 }; float cubeRotations[MAX_CUBES] = { 0 }; + Color cubeColors[MAX_CUBES] = { 0 }; for (int i = 0; i < MAX_CUBES; i++) { @@ -171,6 +224,9 @@ int main(void) }; cubeRotations[i] = (float)(rand()%360); + + cubeColors[i] = (Color){GetRandomValue(0,128),GetRandomValue(0,128),GetRandomValue(0,128),255}; + } DeferredMode mode = DEFERRED_SHADING; @@ -229,7 +285,7 @@ int main(void) for (int i = 0; i < MAX_CUBES; i++) { Vector3 position = cubePositions[i]; - DrawModelEx(cube, position, (Vector3) { 1, 1, 1 }, cubeRotations[i], (Vector3) { CUBE_SCALE, CUBE_SCALE, CUBE_SCALE }, WHITE); + DrawModelEx(cube, position, (Vector3) { 1, 1, 1 }, cubeRotations[i], (Vector3) { CUBE_SCALE, CUBE_SCALE, CUBE_SCALE }, cubeColors[i]); } rlDisableShader(); @@ -265,11 +321,12 @@ int main(void) EndMode3D(); // As a last step, we now copy over the depth buffer from our g-buffer to the default framebuffer. + // This step is only needed if you plan to continue drawing in the deffer-rendered scene rlBindFramebuffer(RL_READ_FRAMEBUFFER, gBuffer.framebuffer); rlBindFramebuffer(RL_DRAW_FRAMEBUFFER, 0); rlBlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, 0x00000100); // GL_DEPTH_BUFFER_BIT - rlDisableFramebuffer(); + rlDisableFramebuffer(); // Since our shader is now done and disabled, we can draw spheres // that represent light positions in default forward rendering BeginMode3D(camera); @@ -280,8 +337,7 @@ int main(void) else DrawSphereWires(lights[i].position, 0.2f, 8, 8, ColorAlpha(lights[i].color, 0.3f)); } rlDisableShader(); - EndMode3D(); - + EndMode3D(); DrawText("FINAL RESULT", 10, screenHeight - 30, 20, DARKGREEN); } break; case DEFERRED_POSITION: @@ -312,7 +368,7 @@ int main(void) .height = screenHeight, }, (Rectangle) { 0, 0, (float)screenWidth, (float)-screenHeight }, Vector2Zero(), RAYWHITE); - DrawText("ALBEDO TEXTURE", 10, screenHeight - 30, 20, DARKGREEN); + DrawText("ALBEDO*SPECULAR TEXTURE", 10, screenHeight - 30, 20, DARKGREEN); } break; default: break; } @@ -331,6 +387,8 @@ int main(void) UnloadModel(model); // Unload the models UnloadModel(cube); + UnloadTexture(texture_specular); + UnloadShader(deferredShader); // Unload shaders UnloadShader(gbufferShader);