shaders_normalmap_rendering.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*******************************************************************************************
  2. *
  3. * raylib [shaders] example - normalmap rendering
  4. *
  5. * Example complexity rating: [★★★★] 4/4
  6. *
  7. * NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
  8. * OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
  9. *
  10. * Example originally created with raylib 5.6, last time updated with raylib 5.6
  11. *
  12. * Example contributed by Jeremy Montgomery (@Sir_Irk) and reviewed by Ramon Santamaria (@raysan5)
  13. *
  14. * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  15. * BSD-like license that allows static linking with closed source software
  16. *
  17. * Copyright (c) 2025 Jeremy Montgomery (@Sir_Irk) and Ramon Santamaria (@raysan5)
  18. *
  19. ********************************************************************************************/
  20. #include "raylib.h"
  21. #include "raymath.h"
  22. #if defined(PLATFORM_DESKTOP)
  23. #define GLSL_VERSION 330
  24. #else // PLATFORM_ANDROID, PLATFORM_WEB
  25. #define GLSL_VERSION 100
  26. #endif
  27. //------------------------------------------------------------------------------------
  28. // Program main entry point
  29. //------------------------------------------------------------------------------------
  30. int main(void)
  31. {
  32. // Initialization
  33. //--------------------------------------------------------------------------------------
  34. const int screenWidth = 800;
  35. const int screenHeight = 450;
  36. SetConfigFlags(FLAG_MSAA_4X_HINT);
  37. InitWindow(screenWidth, screenHeight, "raylib [shaders] example - normalmap rendering");
  38. Camera camera = { 0 };
  39. camera.position = (Vector3){ 0.0f, 2.0f, -4.0f };
  40. camera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
  41. camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
  42. camera.fovy = 45.0f;
  43. camera.projection = CAMERA_PERSPECTIVE;
  44. // Load basic normal map lighting shader
  45. Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/normalmap.vs", GLSL_VERSION),
  46. TextFormat("resources/shaders/glsl%i/normalmap.fs", GLSL_VERSION));
  47. // Get some required shader locations
  48. shader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(shader, "normalMap");
  49. shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos");
  50. // NOTE: "matModel" location name is automatically assigned on shader loading,
  51. // no need to get the location again if using that uniform name
  52. // shader.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocation(shader, "matModel");
  53. // This example uses just 1 point light
  54. Vector3 lightPosition = { 0.0f, 1.0f, 0.0f };
  55. int lightPosLoc = GetShaderLocation(shader, "lightPos");
  56. // Load a plane model that has proper normals and tangents
  57. Model plane = LoadModel("resources/models/plane.glb");
  58. // Set the plane model's shader and texture maps
  59. plane.materials[0].shader = shader;
  60. plane.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture("resources/tiles_diffuse.png");
  61. plane.materials[0].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture("resources/tiles_normal.png");
  62. // Generate Mipmaps and use TRILINEAR filtering to help with texture aliasing
  63. GenTextureMipmaps(&plane.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture);
  64. GenTextureMipmaps(&plane.materials[0].maps[MATERIAL_MAP_NORMAL].texture);
  65. SetTextureFilter(plane.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture, TEXTURE_FILTER_TRILINEAR);
  66. SetTextureFilter(plane.materials[0].maps[MATERIAL_MAP_NORMAL].texture, TEXTURE_FILTER_TRILINEAR);
  67. // Specular exponent AKA shininess of the material
  68. float specularExponent = 8.0f;
  69. int specularExponentLoc = GetShaderLocation(shader, "specularExponent");
  70. // Allow toggling the normal map on and off for comparison purposes
  71. int useNormalMap = 1;
  72. int useNormalMapLoc = GetShaderLocation(shader, "useNormalMap");
  73. SetTargetFPS(60); // Set our game to run at 60 frames-per-second
  74. //--------------------------------------------------------------------------------------
  75. // Main game loop
  76. while (!WindowShouldClose()) // Detect window close button or ESC key
  77. {
  78. // Update
  79. //----------------------------------------------------------------------------------
  80. // Move the light around on the X and Z axis using WASD keys
  81. Vector3 direction = { 0 };
  82. if (IsKeyDown(KEY_W)) direction = Vector3Add(direction, (Vector3){ 0.0f, 0.0f, 1.0f });
  83. if (IsKeyDown(KEY_S)) direction = Vector3Add(direction, (Vector3){ 0.0f, 0.0f, -1.0f });
  84. if (IsKeyDown(KEY_D)) direction = Vector3Add(direction, (Vector3){ -1.0f, 0.0f, 0.0f });
  85. if (IsKeyDown(KEY_A)) direction = Vector3Add(direction, (Vector3){ 1.0f, 0.0f, 0.0f });
  86. direction = Vector3Normalize(direction);
  87. lightPosition = Vector3Add(lightPosition, Vector3Scale(direction, GetFrameTime()*3.0f));
  88. // Increase/Decrease the specular exponent(shininess)
  89. if (IsKeyDown(KEY_UP)) specularExponent = Clamp(specularExponent + 40.0f*GetFrameTime(), 2.0f, 128.0f);
  90. if (IsKeyDown(KEY_DOWN)) specularExponent = Clamp(specularExponent - 40.0f*GetFrameTime(), 2.0f, 128.0f);
  91. // Toggle normal map on and off
  92. if (IsKeyPressed(KEY_N)) useNormalMap = !useNormalMap;
  93. // Spin plane model at a constant rate
  94. plane.transform = MatrixRotateY((float)GetTime()*0.5f);
  95. // Update shader values
  96. float lightPos[3] = {lightPosition.x, lightPosition.y, lightPosition.z};
  97. SetShaderValue(shader, lightPosLoc, lightPos, SHADER_UNIFORM_VEC3);
  98. float camPos[3] = {camera.position.x, camera.position.y, camera.position.z};
  99. SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], camPos, SHADER_UNIFORM_VEC3);
  100. SetShaderValue(shader, specularExponentLoc, &specularExponent, SHADER_UNIFORM_FLOAT);
  101. SetShaderValue(shader, useNormalMapLoc, &useNormalMap, SHADER_UNIFORM_INT);
  102. //--------------------------------------------------------------------------------------
  103. // Draw
  104. //----------------------------------------------------------------------------------
  105. BeginDrawing();
  106. ClearBackground(RAYWHITE);
  107. BeginMode3D(camera);
  108. BeginShaderMode(shader);
  109. DrawModel(plane, Vector3Zero(), 2.0f, WHITE);
  110. EndShaderMode();
  111. // Draw sphere to show light position
  112. DrawSphereWires(lightPosition, 0.2f, 8, 8, ORANGE);
  113. EndMode3D();
  114. Color textColor = (useNormalMap) ? DARKGREEN : RED;
  115. const char *toggleStr = (useNormalMap) ? "On" : "Off";
  116. DrawText(TextFormat("Use key [N] to toggle normal map: %s", toggleStr), 10, 10, 10, textColor);
  117. int yOffset = 24;
  118. DrawText("Use keys [W][A][S][D] to move the light", 10, 10 + yOffset*1, 10, BLACK);
  119. DrawText("Use keys [Up][Down] to change specular exponent", 10, 10 + yOffset*2, 10, BLACK);
  120. DrawText(TextFormat("Specular Exponent: %.2f", specularExponent), 10, 10 + yOffset*3, 10, BLUE);
  121. DrawFPS(screenWidth - 90, 10);
  122. EndDrawing();
  123. //--------------------------------------------------------------------------------------
  124. }
  125. // De-Initialization
  126. //--------------------------------------------------------------------------------------
  127. UnloadShader(shader);
  128. UnloadModel(plane);
  129. CloseWindow(); // Close window and OpenGL context
  130. //--------------------------------------------------------------------------------------
  131. return 0;
  132. }