mirror of
				https://github.com/raysan5/raylib.git
				synced 2025-10-26 12:27:01 +00:00 
			
		
		
		
	Add shadowmapping example (#3653)
This commit is contained in:
		 TheManTheMythTheGameDev
					TheManTheMythTheGameDev
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							34a9163c52
						
					
				
				
					commit
					1fc3d9aeb2
				
			| @@ -560,6 +560,7 @@ SHADERS = \ | ||||
|     shaders/shaders_palette_switch \ | ||||
|     shaders/shaders_postprocessing \ | ||||
|     shaders/shaders_raymarching \ | ||||
|     shaders/shaders_shadowmap \ | ||||
|     shaders/shaders_shapes_textures \ | ||||
|     shaders/shaders_simple_mask \ | ||||
|     shaders/shaders_spotlight \ | ||||
|   | ||||
| @@ -466,6 +466,7 @@ SHADERS = \ | ||||
|     shaders/shaders_palette_switch \ | ||||
|     shaders/shaders_postprocessing \ | ||||
|     shaders/shaders_raymarching \ | ||||
|     shaders/shaders_shadowmap \ | ||||
|     shaders/shaders_shapes_textures \ | ||||
|     shaders/shaders_simple_mask \ | ||||
|     shaders/shaders_spotlight \ | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								examples/shaders/resources/models/robot.glb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								examples/shaders/resources/models/robot.glb
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										86
									
								
								examples/shaders/resources/shaders/glsl120/shadowmap.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								examples/shaders/resources/shaders/glsl120/shadowmap.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| #version 120 | ||||
|  | ||||
| precision mediump float; | ||||
|  | ||||
| // This shader is based on the basic lighting shader | ||||
| // This only supports one light, which is directional, and it (of course) supports shadows | ||||
|  | ||||
| // Input vertex attributes (from vertex shader) | ||||
| varying in vec3 fragPosition; | ||||
| varying in vec2 fragTexCoord; | ||||
| //varying in vec4 fragColor; | ||||
| varying in vec3 fragNormal; | ||||
|  | ||||
| // Input uniform values | ||||
| uniform sampler2D texture0; | ||||
| uniform vec4 colDiffuse; | ||||
|  | ||||
| // Input lighting values | ||||
| uniform vec3 lightDir; | ||||
| uniform vec4 lightColor; | ||||
| uniform vec4 ambient; | ||||
| uniform vec3 viewPos; | ||||
|  | ||||
| // Input shadowmapping values | ||||
| uniform mat4 lightVP; // Light source view-projection matrix | ||||
| uniform sampler2D shadowMap; | ||||
|  | ||||
| uniform int shadowMapResolution; | ||||
|  | ||||
| void main() | ||||
| { | ||||
|     // Texel color fetching from texture sampler | ||||
|     vec4 texelColor = texture2D(texture0, fragTexCoord); | ||||
|     vec3 lightDot = vec3(0.0); | ||||
|     vec3 normal = normalize(fragNormal); | ||||
|     vec3 viewD = normalize(viewPos - fragPosition); | ||||
|     vec3 specular = vec3(0.0); | ||||
|  | ||||
|     vec3 l = -lightDir; | ||||
|  | ||||
|     float NdotL = max(dot(normal, l), 0.0); | ||||
|     lightDot += lightColor.rgb*NdotL; | ||||
|  | ||||
|     float specCo = 0.0; | ||||
|     if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(l), normal))), 16.0); // 16 refers to shine | ||||
|     specular += specCo; | ||||
|  | ||||
|     vec4 finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0))); | ||||
|  | ||||
|     // Shadow calculations | ||||
|     vec4 fragPosLightSpace = lightVP * vec4(fragPosition, 1); | ||||
|     fragPosLightSpace.xyz /= fragPosLightSpace.w; // Perform the perspective division | ||||
|     fragPosLightSpace.xyz = (fragPosLightSpace.xyz + 1.0f) / 2.0f; // Transform from [-1, 1] range to [0, 1] range | ||||
|     vec2 sampleCoords = fragPosLightSpace.xy; | ||||
|     float curDepth = fragPosLightSpace.z; | ||||
|     // Slope-scale depth bias: depth biasing reduces "shadow acne" artifacts, where dark stripes appear all over the scene. | ||||
|     // The solution is adding a small bias to the depth | ||||
|     // In this case, the bias is proportional to the slope of the surface, relative to the light | ||||
|     float bias = max(0.0008 * (1.0 - dot(normal, l)), 0.00008); | ||||
|     int shadowCounter = 0; | ||||
|     const int numSamples = 9; | ||||
|     // PCF (percentage-closer filtering) algorithm: | ||||
|     // Instead of testing if just one point is closer to the current point, | ||||
|     // we test the surrounding points as well. | ||||
|     // This blurs shadow edges, hiding aliasing artifacts. | ||||
|     vec2 texelSize = vec2(1.0f / float(shadowMapResolution)); | ||||
|     for (int x = -1; x <= 1; x++) | ||||
|     { | ||||
|         for (int y = -1; y <= 1; y++) | ||||
|         { | ||||
|             float sampleDepth = texture2D(shadowMap, sampleCoords + texelSize * vec2(x, y)).r; | ||||
|             if (curDepth - bias > sampleDepth) | ||||
|             { | ||||
|                 shadowCounter++; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     finalColor = mix(finalColor, vec4(0, 0, 0, 1), float(shadowCounter) / float(numSamples)); | ||||
|  | ||||
|     // Add ambient lighting whether in shadow or not | ||||
|     finalColor += texelColor*(ambient/10.0)*colDiffuse; | ||||
|  | ||||
|     // Gamma correction | ||||
|     finalColor = pow(finalColor, vec4(1.0/2.2)); | ||||
|     gl_FragColor = finalColor; | ||||
| } | ||||
							
								
								
									
										32
									
								
								examples/shaders/resources/shaders/glsl120/shadowmap.vs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								examples/shaders/resources/shaders/glsl120/shadowmap.vs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| #version 120 | ||||
|  | ||||
| // Input vertex attributes | ||||
| attribute vec3 vertexPosition; | ||||
| attribute vec2 vertexTexCoord; | ||||
| attribute vec3 vertexNormal; | ||||
| attribute vec4 vertexColor; | ||||
|  | ||||
| // Input uniform values | ||||
| uniform mat4 mvp; | ||||
| uniform mat4 matModel; | ||||
| uniform mat4 matNormal; | ||||
|  | ||||
| // Output vertex attributes (to fragment shader) | ||||
| varying vec3 fragPosition; | ||||
| varying vec2 fragTexCoord; | ||||
| varying vec4 fragColor; | ||||
| varying vec3 fragNormal; | ||||
|  | ||||
| // NOTE: Add here your custom variables | ||||
|  | ||||
| void main() | ||||
| { | ||||
|     // Send vertex attributes to fragment shader | ||||
|     fragPosition = vec3(matModel*vec4(vertexPosition, 1.0)); | ||||
|     fragTexCoord = vertexTexCoord; | ||||
|     fragColor = vertexColor; | ||||
|     fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0))); | ||||
|  | ||||
|     // Calculate final vertex position | ||||
|     gl_Position = mvp*vec4(vertexPosition, 1.0); | ||||
| } | ||||
							
								
								
									
										86
									
								
								examples/shaders/resources/shaders/glsl330/shadowmap.fs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								examples/shaders/resources/shaders/glsl330/shadowmap.fs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| #version 330 | ||||
|  | ||||
| // This shader is based on the basic lighting shader | ||||
| // This only supports one light, which is directional, and it (of course) supports shadows | ||||
|  | ||||
| // Input vertex attributes (from vertex shader) | ||||
| in vec3 fragPosition; | ||||
| in vec2 fragTexCoord; | ||||
| //in vec4 fragColor; | ||||
| in vec3 fragNormal; | ||||
|  | ||||
| // Input uniform values | ||||
| uniform sampler2D texture0; | ||||
| uniform vec4 colDiffuse; | ||||
|  | ||||
| // Output fragment color | ||||
| out vec4 finalColor; | ||||
|  | ||||
| // Input lighting values | ||||
| uniform vec3 lightDir; | ||||
| uniform vec4 lightColor; | ||||
| uniform vec4 ambient; | ||||
| uniform vec3 viewPos; | ||||
|  | ||||
| // Input shadowmapping values | ||||
| uniform mat4 lightVP; // Light source view-projection matrix | ||||
| uniform sampler2D shadowMap; | ||||
|  | ||||
| uniform int shadowMapResolution; | ||||
|  | ||||
| void main() | ||||
| { | ||||
|     // Texel color fetching from texture sampler | ||||
|     vec4 texelColor = texture(texture0, fragTexCoord); | ||||
|     vec3 lightDot = vec3(0.0); | ||||
|     vec3 normal = normalize(fragNormal); | ||||
|     vec3 viewD = normalize(viewPos - fragPosition); | ||||
|     vec3 specular = vec3(0.0); | ||||
|  | ||||
|     vec3 l = -lightDir; | ||||
|  | ||||
|     float NdotL = max(dot(normal, l), 0.0); | ||||
|     lightDot += lightColor.rgb*NdotL; | ||||
|  | ||||
|     float specCo = 0.0; | ||||
|     if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(l), normal))), 16.0); // 16 refers to shine | ||||
|     specular += specCo; | ||||
|  | ||||
|     finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0))); | ||||
|  | ||||
|     // Shadow calculations | ||||
|     vec4 fragPosLightSpace = lightVP * vec4(fragPosition, 1); | ||||
|     fragPosLightSpace.xyz /= fragPosLightSpace.w; // Perform the perspective division | ||||
|     fragPosLightSpace.xyz = (fragPosLightSpace.xyz + 1.0f) / 2.0f; // Transform from [-1, 1] range to [0, 1] range | ||||
|     vec2 sampleCoords = fragPosLightSpace.xy; | ||||
|     float curDepth = fragPosLightSpace.z; | ||||
|     // Slope-scale depth bias: depth biasing reduces "shadow acne" artifacts, where dark stripes appear all over the scene. | ||||
|     // The solution is adding a small bias to the depth | ||||
|     // In this case, the bias is proportional to the slope of the surface, relative to the light | ||||
|     float bias = max(0.0002 * (1.0 - dot(normal, l)), 0.00002) + 0.00001; | ||||
|     int shadowCounter = 0; | ||||
|     const int numSamples = 9; | ||||
|     // PCF (percentage-closer filtering) algorithm: | ||||
|     // Instead of testing if just one point is closer to the current point, | ||||
|     // we test the surrounding points as well. | ||||
|     // This blurs shadow edges, hiding aliasing artifacts. | ||||
|     vec2 texelSize = vec2(1.0f / float(shadowMapResolution)); | ||||
|     for (int x = -1; x <= 1; x++) | ||||
|     { | ||||
|         for (int y = -1; y <= 1; y++) | ||||
|         { | ||||
|             float sampleDepth = texture(shadowMap, sampleCoords + texelSize * vec2(x, y)).r; | ||||
|             if (curDepth - bias > sampleDepth) | ||||
|             { | ||||
|                 shadowCounter++; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     finalColor = mix(finalColor, vec4(0, 0, 0, 1), float(shadowCounter) / float(numSamples)); | ||||
|  | ||||
|     // Add ambient lighting whether in shadow or not | ||||
|     finalColor += texelColor*(ambient/10.0)*colDiffuse; | ||||
|  | ||||
|     // Gamma correction | ||||
|     finalColor = pow(finalColor, vec4(1.0/2.2)); | ||||
| } | ||||
							
								
								
									
										32
									
								
								examples/shaders/resources/shaders/glsl330/shadowmap.vs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								examples/shaders/resources/shaders/glsl330/shadowmap.vs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| #version 330 | ||||
|  | ||||
| // Input vertex attributes | ||||
| in vec3 vertexPosition; | ||||
| in vec2 vertexTexCoord; | ||||
| in vec3 vertexNormal; | ||||
| in vec4 vertexColor; | ||||
|  | ||||
| // Input uniform values | ||||
| uniform mat4 mvp; | ||||
| uniform mat4 matModel; | ||||
| uniform mat4 matNormal; | ||||
|  | ||||
| // Output vertex attributes (to fragment shader) | ||||
| out vec3 fragPosition; | ||||
| out vec2 fragTexCoord; | ||||
| out vec4 fragColor; | ||||
| out vec3 fragNormal; | ||||
|  | ||||
| // NOTE: Add here your custom variables | ||||
|  | ||||
| void main() | ||||
| { | ||||
|     // Send vertex attributes to fragment shader | ||||
|     fragPosition = vec3(matModel*vec4(vertexPosition, 1.0)); | ||||
|     fragTexCoord = vertexTexCoord; | ||||
|     fragColor = vertexColor; | ||||
|     fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0))); | ||||
|  | ||||
|     // Calculate final vertex position | ||||
|     gl_Position = mvp*vec4(vertexPosition, 1.0); | ||||
| } | ||||
							
								
								
									
										251
									
								
								examples/shaders/shaders_shadowmap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								examples/shaders/shaders_shadowmap.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,251 @@ | ||||
| /******************************************************************************************* | ||||
| * | ||||
| *   raylib [shaders] example - Shadowmap | ||||
| * | ||||
| *   Example originally created with raylib 5.0, last time updated with raylib 5.0 | ||||
| * | ||||
| *   Example contributed by @TheManTheMythTheGameDev and reviewed by Ramon Santamaria (@raysan5) | ||||
| * | ||||
| *   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, | ||||
| *   BSD-like license that allows static linking with closed source software | ||||
| * | ||||
| ********************************************************************************************/ | ||||
|  | ||||
| #include "raylib.h" | ||||
| #include "raymath.h" | ||||
| #include "rlgl.h" | ||||
|  | ||||
| #if defined(PLATFORM_DESKTOP) | ||||
| #define GLSL_VERSION            330 | ||||
| #else   // PLATFORM_ANDROID, PLATFORM_WEB | ||||
| #define GLSL_VERSION            120 | ||||
| #endif | ||||
|  | ||||
| #define SHADOWMAP_RESOLUTION 1024 | ||||
|  | ||||
| RenderTexture2D LoadShadowmapRenderTexture(int width, int height); | ||||
| void UnloadShadowmapRenderTexture(RenderTexture2D target); | ||||
| void DrawScene(Model cube, Model robot); | ||||
|  | ||||
| //------------------------------------------------------------------------------------ | ||||
| // Program main entry point | ||||
| //------------------------------------------------------------------------------------ | ||||
| int main(void) | ||||
| { | ||||
|     // Initialization | ||||
|     //-------------------------------------------------------------------------------------- | ||||
|     const int screenWidth = 800; | ||||
|     const int screenHeight = 450; | ||||
|  | ||||
|     SetConfigFlags(FLAG_MSAA_4X_HINT); | ||||
|     // Shadows are a HUGE topic, and this example shows an extremely simple implementation of the shadowmapping algorithm, | ||||
|     // which is the industry standard for shadows. This algorithm can be extended in a ridiculous number of ways to improve | ||||
|     // realism and also adapt it for different scenes. This is pretty much the simplest possible implementation. | ||||
|     InitWindow(screenWidth, screenHeight, "raylib [shaders] example - shadowmap"); | ||||
|  | ||||
|     Camera3D cam = (Camera3D){ 0 }; | ||||
|     cam.position = (Vector3){ 10.0f, 10.0f, 10.0f }; | ||||
|     cam.target = Vector3Zero(); | ||||
|     cam.projection = CAMERA_PERSPECTIVE; | ||||
|     cam.up = (Vector3){ 0.0f, 1.0f, 0.0f }; | ||||
|     cam.fovy = 45.0f; | ||||
|  | ||||
|     Shader shadowShader = LoadShader(TextFormat("resources/shaders/glsl%i/shadowmap.vs", GLSL_VERSION), | ||||
|                                      TextFormat("resources/shaders/glsl%i/shadowmap.fs", GLSL_VERSION)); | ||||
|     shadowShader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shadowShader, "viewPos"); | ||||
|     Vector3 lightDir = Vector3Normalize((Vector3){ 0.35f, -1.0f, -0.35f }); | ||||
|     Color lightColor = WHITE; | ||||
|     Vector4 lightColorNormalized = ColorNormalize(lightColor); | ||||
|     int lightDirLoc = GetShaderLocation(shadowShader, "lightDir"); | ||||
|     int lightColLoc = GetShaderLocation(shadowShader, "lightColor"); | ||||
|     SetShaderValue(shadowShader, lightDirLoc, &lightDir, SHADER_UNIFORM_VEC3); | ||||
|     SetShaderValue(shadowShader, lightColLoc, &lightColorNormalized, SHADER_UNIFORM_VEC4); | ||||
|     int ambientLoc = GetShaderLocation(shadowShader, "ambient"); | ||||
|     float ambient[4] = {0.1f, 0.1f, 0.1f, 1.0f}; | ||||
|     SetShaderValue(shadowShader, ambientLoc, ambient, SHADER_UNIFORM_VEC4); | ||||
|     int lightVPLoc = GetShaderLocation(shadowShader, "lightVP"); | ||||
|     int shadowMapLoc = GetShaderLocation(shadowShader, "shadowMap"); | ||||
|     int shadowMapResolution = SHADOWMAP_RESOLUTION; | ||||
|     SetShaderValue(shadowShader, GetShaderLocation(shadowShader, "shadowMapResolution"), &shadowMapResolution, SHADER_UNIFORM_INT); | ||||
|  | ||||
|     Model cube = LoadModelFromMesh(GenMeshCube(1.0f, 1.0f, 1.0f)); | ||||
|     cube.materials[0].shader = shadowShader; | ||||
|     Model robot = LoadModel("resources/models/robot.glb"); | ||||
|     for (int i = 0; i < robot.materialCount; i++) | ||||
|     { | ||||
|         robot.materials[i].shader = shadowShader; | ||||
|     } | ||||
|     int animCount = 0; | ||||
|     ModelAnimation* robotAnimations = LoadModelAnimations("resources/models/robot.glb", &animCount); | ||||
|  | ||||
|     RenderTexture2D shadowMap = LoadShadowmapRenderTexture(SHADOWMAP_RESOLUTION, SHADOWMAP_RESOLUTION); | ||||
|     // For the shadowmapping algorithm, we will be rendering everything from the light's point of view | ||||
|     Camera3D lightCam = (Camera3D){ 0 }; | ||||
|     lightCam.position = Vector3Scale(lightDir, -15.0f); | ||||
|     lightCam.target = Vector3Zero(); | ||||
|     // Use an orthographic projection for directional lights | ||||
|     lightCam.projection = CAMERA_ORTHOGRAPHIC; | ||||
|     lightCam.up = (Vector3){ 0.0f, 1.0f, 0.0f }; | ||||
|     lightCam.fovy = 20.0f; | ||||
|  | ||||
|     SetTargetFPS(60); | ||||
|     //-------------------------------------------------------------------------------------- | ||||
|     int fc = 0; | ||||
|  | ||||
|     // Main game loop | ||||
|     while (!WindowShouldClose())    // Detect window close button or ESC key | ||||
|     { | ||||
|         // Update | ||||
|         //---------------------------------------------------------------------------------- | ||||
|         float dt = GetFrameTime(); | ||||
|  | ||||
|         Vector3 cameraPos = cam.position; | ||||
|         SetShaderValue(shadowShader, shadowShader.locs[SHADER_LOC_VECTOR_VIEW], &cameraPos, SHADER_UNIFORM_VEC3); | ||||
|         UpdateCamera(&cam, CAMERA_ORBITAL); | ||||
|  | ||||
|         fc++; | ||||
|         fc %= (robotAnimations[0].frameCount); | ||||
|         UpdateModelAnimation(robot, robotAnimations[0], fc); | ||||
|  | ||||
|         const float cameraSpeed = 0.05f; | ||||
|         if (IsKeyDown(KEY_LEFT)) | ||||
|         { | ||||
|             if (lightDir.x < 0.6f) | ||||
|                 lightDir.x += cameraSpeed * 60.0f * dt; | ||||
|         } | ||||
|         if (IsKeyDown(KEY_RIGHT)) | ||||
|         { | ||||
|             if (lightDir.x > -0.6f) | ||||
|                 lightDir.x -= cameraSpeed * 60.0f * dt; | ||||
|         } | ||||
|         if (IsKeyDown(KEY_UP)) | ||||
|         { | ||||
|             if (lightDir.z < 0.6f) | ||||
|                 lightDir.z += cameraSpeed * 60.0f * dt; | ||||
|         } | ||||
|         if (IsKeyDown(KEY_DOWN)) | ||||
|         { | ||||
|             if (lightDir.z > -0.6f) | ||||
|                 lightDir.z -= cameraSpeed * 60.0f * dt; | ||||
|         } | ||||
|         lightDir = Vector3Normalize(lightDir); | ||||
|         lightCam.position = Vector3Scale(lightDir, -15.0f); | ||||
|         SetShaderValue(shadowShader, lightDirLoc, &lightDir, SHADER_UNIFORM_VEC3); | ||||
|  | ||||
|         // Draw | ||||
|         //---------------------------------------------------------------------------------- | ||||
|         BeginDrawing(); | ||||
|  | ||||
|         // First, render all objects into the shadowmap | ||||
|         // The idea is, we record all the objects' depths (as rendered from the light source's point of view) in a buffer | ||||
|         // Anything that is "visible" to the light is in light, anything that isn't is in shadow | ||||
|         // We can later use the depth buffer when rendering everything from the player's point of view | ||||
|         // to determine whether a given point is "visible" to the light | ||||
|  | ||||
|         // Record the light matrices for future use! | ||||
|         Matrix lightView; | ||||
|         Matrix lightProj; | ||||
|         BeginTextureMode(shadowMap); | ||||
|         ClearBackground(WHITE); | ||||
|         BeginMode3D(lightCam); | ||||
|             lightView = rlGetMatrixModelview(); | ||||
|             lightProj = rlGetMatrixProjection(); | ||||
|             DrawScene(cube, robot); | ||||
|         EndMode3D(); | ||||
|         EndTextureMode(); | ||||
|         Matrix lightViewProj = MatrixMultiply(lightView, lightProj); | ||||
|  | ||||
|         ClearBackground(RAYWHITE); | ||||
|  | ||||
|         SetShaderValueMatrix(shadowShader, lightVPLoc, lightViewProj); | ||||
|  | ||||
|         rlEnableShader(shadowShader.id); | ||||
|         int slot = 10; // Can be anything 0 to 15, but 0 will probably be taken up | ||||
|         rlActiveTextureSlot(10); | ||||
|         rlEnableTexture(shadowMap.depth.id); | ||||
|         rlSetUniform(shadowMapLoc, &slot, SHADER_UNIFORM_INT, 1); | ||||
|  | ||||
|         BeginMode3D(cam); | ||||
|  | ||||
|             // Draw the same exact things as we drew in the shadowmap! | ||||
|             DrawScene(cube, robot); | ||||
|          | ||||
|         EndMode3D(); | ||||
|  | ||||
|         DrawText("Shadows in raylib using the shadowmapping algorithm!", screenWidth - 320, screenHeight - 20, 10, GRAY); | ||||
|         DrawText("Use the arrow keys to rotate the light!", 10, 10, 30, RED); | ||||
|  | ||||
|         EndDrawing(); | ||||
|  | ||||
|         if (IsKeyPressed(KEY_F)) | ||||
|         { | ||||
|             TakeScreenshot("shaders_shadowmap.png"); | ||||
|         } | ||||
|         //---------------------------------------------------------------------------------- | ||||
|     } | ||||
|  | ||||
|     // De-Initialization | ||||
|     //-------------------------------------------------------------------------------------- | ||||
|  | ||||
|     UnloadShader(shadowShader); | ||||
|     UnloadModel(cube); | ||||
|     UnloadModel(robot); | ||||
|     UnloadModelAnimations(robotAnimations, animCount); | ||||
|     UnloadShadowmapRenderTexture(shadowMap); | ||||
|  | ||||
|     CloseWindow();        // Close window and OpenGL context | ||||
|     //-------------------------------------------------------------------------------------- | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| RenderTexture2D LoadShadowmapRenderTexture(int width, int height) | ||||
| { | ||||
|     RenderTexture2D target = { 0 }; | ||||
|  | ||||
|     target.id = rlLoadFramebuffer(width, height);   // Load an empty framebuffer | ||||
|     target.texture.width = width; | ||||
|     target.texture.height = height; | ||||
|  | ||||
|     if (target.id > 0) | ||||
|     { | ||||
|         rlEnableFramebuffer(target.id); | ||||
|  | ||||
|         // Create depth texture | ||||
|         // We don't need a color texture for the shadowmap | ||||
|         target.depth.id = rlLoadTextureDepth(width, height, false); | ||||
|         target.depth.width = width; | ||||
|         target.depth.height = height; | ||||
|         target.depth.format = 19;       //DEPTH_COMPONENT_24BIT? | ||||
|         target.depth.mipmaps = 1; | ||||
|  | ||||
|         // Attach depth texture to FBO | ||||
|         rlFramebufferAttach(target.id, target.depth.id, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_TEXTURE2D, 0); | ||||
|  | ||||
|         // Check if fbo is complete with attachments (valid) | ||||
|         if (rlFramebufferComplete(target.id)) TRACELOG(LOG_INFO, "FBO: [ID %i] Framebuffer object created successfully", target.id); | ||||
|  | ||||
|         rlDisableFramebuffer(); | ||||
|     } | ||||
|     else TRACELOG(LOG_WARNING, "FBO: Framebuffer object can not be created"); | ||||
|  | ||||
|     return target; | ||||
| } | ||||
|  | ||||
| // Unload shadowmap render texture from GPU memory (VRAM) | ||||
| void UnloadShadowmapRenderTexture(RenderTexture2D target) | ||||
| { | ||||
|     if (target.id > 0) | ||||
|     { | ||||
|         // NOTE: Depth texture/renderbuffer is automatically | ||||
|         // queried and deleted before deleting framebuffer | ||||
|         rlUnloadFramebuffer(target.id); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void DrawScene(Model cube, Model robot) | ||||
| { | ||||
|     DrawModelEx(cube, Vector3Zero(), (Vector3) { 0.0f, 1.0f, 0.0f }, 0.0f, (Vector3) { 10.0f, 1.0f, 10.0f }, BLUE); | ||||
|     DrawModelEx(cube, (Vector3) { 1.5f, 1.0f, -1.5f }, (Vector3) { 0.0f, 1.0f, 0.0f }, 0.0f, Vector3One(), WHITE); | ||||
|     DrawModelEx(robot, (Vector3) { 0.0f, 0.5f, 0.0f }, (Vector3) { 0.0f, 1.0f, 0.0f }, 0.0f, (Vector3) { 1.0f, 1.0f, 1.0f }, RED); | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								examples/shaders/shaders_shadowmap.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								examples/shaders/shaders_shadowmap.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 37 KiB | 
		Reference in New Issue
	
	Block a user