|
@@ -0,0 +1,171 @@
|
|
|
|
|
+/*******************************************************************************************
|
|
|
|
|
+ *
|
|
|
|
|
+ * raylib [shaders] example - normalmap
|
|
|
|
|
+ *
|
|
|
|
|
+ * Example complexity rating: [★★★★] 4/4
|
|
|
|
|
+ *
|
|
|
|
|
+ * NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
|
|
|
|
|
+ * OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Example originally created with raylib 5.6, last time updated with raylib 5.6
|
|
|
|
|
+ *
|
|
|
|
|
+ * Example contributed by Jeremy Montgomery (@Sir_Irk) 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
|
|
|
|
|
+ *
|
|
|
|
|
+ * Copyright (c) 2025-2025 Jeremy Montgomery (@Sir_Irk) and Ramon Santamaria (@raysan5)
|
|
|
|
|
+ *k
|
|
|
|
|
+ ********************************************************************************************/
|
|
|
|
|
+
|
|
|
|
|
+#include <raylib.h>
|
|
|
|
|
+#include <raymath.h>
|
|
|
|
|
+
|
|
|
|
|
+#if defined(PLATFORM_DESKTOP)
|
|
|
|
|
+#define GLSL_VERSION 330
|
|
|
|
|
+#else // PLATFORM_ANDROID, PLATFORM_WEB
|
|
|
|
|
+#define GLSL_VERSION 100
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+//------------------------------------------------------------------------------------
|
|
|
|
|
+// Program main entry point
|
|
|
|
|
+//------------------------------------------------------------------------------------
|
|
|
|
|
+int
|
|
|
|
|
+main(void)
|
|
|
|
|
+{
|
|
|
|
|
+ // Initialization
|
|
|
|
|
+ //--------------------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ SetConfigFlags(FLAG_MSAA_4X_HINT);
|
|
|
|
|
+ InitWindow(800, 450, "Normal Map");
|
|
|
|
|
+
|
|
|
|
|
+ Camera camera = {0};
|
|
|
|
|
+ camera.position = (Vector3){0.0f, 2.0f, -4.0f};
|
|
|
|
|
+ camera.target = (Vector3){0.0f, 0.0f, 0.0f};
|
|
|
|
|
+ camera.up = (Vector3){0.0f, 1.0f, 0.0f};
|
|
|
|
|
+ camera.fovy = 45.0f;
|
|
|
|
|
+ camera.projection = CAMERA_PERSPECTIVE;
|
|
|
|
|
+
|
|
|
|
|
+ // Load basic normal map lighting shader
|
|
|
|
|
+ Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/normalmap.vs", GLSL_VERSION),
|
|
|
|
|
+ TextFormat("resources/shaders/glsl%i/normalmap.fs", GLSL_VERSION));
|
|
|
|
|
+
|
|
|
|
|
+ // Get some required shader locations
|
|
|
|
|
+ shader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(shader, "normalMap");
|
|
|
|
|
+ shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos");
|
|
|
|
|
+ // NOTE: "matModel" location name is automatically assigned on shader loading,
|
|
|
|
|
+ // no need to get the location again if using that uniform name
|
|
|
|
|
+ // shader.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocation(shader, "matModel");
|
|
|
|
|
+
|
|
|
|
|
+ // This example uses just 1 point light.
|
|
|
|
|
+ Vector3 lightPosition = {0.0f, 1.0f, 0.0f};
|
|
|
|
|
+ int lightPosLoc = GetShaderLocation(shader, "lightPos");
|
|
|
|
|
+
|
|
|
|
|
+ // Load a plane model that has proper normals and tangents
|
|
|
|
|
+ Model plane = LoadModel("resources/models/plane.glb");
|
|
|
|
|
+
|
|
|
|
|
+ // Set the plane model's shader and texture maps
|
|
|
|
|
+ plane.materials[0].shader = shader;
|
|
|
|
|
+ plane.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture("resources/tiles_diffuse.png");
|
|
|
|
|
+ plane.materials[0].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture("resources/tiles_normal.png");
|
|
|
|
|
+
|
|
|
|
|
+ // Generate Mipmaps and use TRILINEAR filtering to help with texture aliasing
|
|
|
|
|
+ GenTextureMipmaps(&plane.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture);
|
|
|
|
|
+ GenTextureMipmaps(&plane.materials[0].maps[MATERIAL_MAP_NORMAL].texture);
|
|
|
|
|
+
|
|
|
|
|
+ SetTextureFilter(plane.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture, TEXTURE_FILTER_TRILINEAR);
|
|
|
|
|
+ SetTextureFilter(plane.materials[0].maps[MATERIAL_MAP_NORMAL].texture, TEXTURE_FILTER_TRILINEAR);
|
|
|
|
|
+
|
|
|
|
|
+ // Specular exponent AKA shininess of the material.
|
|
|
|
|
+ float specularExponent = 8.0f;
|
|
|
|
|
+ int specularExponentLoc = GetShaderLocation(shader, "specularExponent");
|
|
|
|
|
+
|
|
|
|
|
+ // Allow toggling the normal map on and off for comparison purposes
|
|
|
|
|
+ int useNormalMap = 1;
|
|
|
|
|
+ int useNormalMapLoc = GetShaderLocation(shader, "useNormalMap");
|
|
|
|
|
+
|
|
|
|
|
+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
|
|
|
|
+ //--------------------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ // Main game loop
|
|
|
|
|
+ while (!WindowShouldClose()) // Detect window close button or ESC key
|
|
|
|
|
+ {
|
|
|
|
|
+ // Update
|
|
|
|
|
+ //----------------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ // Move the light around on the X and Z axis using WASD keys
|
|
|
|
|
+ Vector3 direction = {0};
|
|
|
|
|
+ if (IsKeyDown(KEY_W)) direction = Vector3Add(direction, (Vector3){0.0f, 0.0f, 1.0f});
|
|
|
|
|
+ if (IsKeyDown(KEY_S)) direction = Vector3Add(direction, (Vector3){0.0f, 0.0f, -1.0f});
|
|
|
|
|
+ if (IsKeyDown(KEY_D)) direction = Vector3Add(direction, (Vector3){-1.0f, 0.0f, 0.0f});
|
|
|
|
|
+ if (IsKeyDown(KEY_A)) direction = Vector3Add(direction, (Vector3){1.0f, 0.0f, 0.0f});
|
|
|
|
|
+
|
|
|
|
|
+ direction = Vector3Normalize(direction);
|
|
|
|
|
+ lightPosition = Vector3Add(lightPosition, Vector3Scale(direction, GetFrameTime() * 3.0f));
|
|
|
|
|
+
|
|
|
|
|
+ // Increase/Decrease the specular exponent(shininess)
|
|
|
|
|
+ if (IsKeyDown(KEY_UP)) specularExponent = Clamp(specularExponent + 40.0f * GetFrameTime(), 2.0f, 128.0f);
|
|
|
|
|
+ if (IsKeyDown(KEY_DOWN)) specularExponent = Clamp(specularExponent - 40.0f * GetFrameTime(), 2.0f, 128.0f);
|
|
|
|
|
+
|
|
|
|
|
+ // Toggle normal map on and off
|
|
|
|
|
+ if (IsKeyPressed(KEY_N)) useNormalMap = !useNormalMap;
|
|
|
|
|
+
|
|
|
|
|
+ // Spin plane model at a constant rate
|
|
|
|
|
+ plane.transform = MatrixRotateY(GetTime() * 0.5f);
|
|
|
|
|
+
|
|
|
|
|
+ // Update shader values
|
|
|
|
|
+ float lightPos[3] = {lightPosition.x, lightPosition.y, lightPosition.z};
|
|
|
|
|
+ SetShaderValue(shader, lightPosLoc, lightPos, SHADER_UNIFORM_VEC3);
|
|
|
|
|
+
|
|
|
|
|
+ float camPos[3] = {camera.position.x, camera.position.y, camera.position.z};
|
|
|
|
|
+ SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], camPos, SHADER_UNIFORM_VEC3);
|
|
|
|
|
+
|
|
|
|
|
+ SetShaderValue(shader, specularExponentLoc, &specularExponent, SHADER_UNIFORM_FLOAT);
|
|
|
|
|
+
|
|
|
|
|
+ SetShaderValue(shader, useNormalMapLoc, &useNormalMap, SHADER_UNIFORM_INT);
|
|
|
|
|
+ //--------------------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ // Draw
|
|
|
|
|
+ //----------------------------------------------------------------------------------
|
|
|
|
|
+ BeginDrawing();
|
|
|
|
|
+
|
|
|
|
|
+ ClearBackground(RAYWHITE);
|
|
|
|
|
+
|
|
|
|
|
+ BeginMode3D(camera);
|
|
|
|
|
+
|
|
|
|
|
+ BeginShaderMode(shader);
|
|
|
|
|
+
|
|
|
|
|
+ DrawModel(plane, Vector3Zero(), 2.0f, WHITE);
|
|
|
|
|
+
|
|
|
|
|
+ EndShaderMode();
|
|
|
|
|
+
|
|
|
|
|
+ //Draw sphere to show light position
|
|
|
|
|
+ DrawSphereWires(lightPosition, 0.2f, 8, 8, ORANGE);
|
|
|
|
|
+
|
|
|
|
|
+ EndMode3D();
|
|
|
|
|
+
|
|
|
|
|
+ Color textColor = (useNormalMap) ? DARKGREEN : RED;
|
|
|
|
|
+ const char *toggleStr = (useNormalMap) ? "On" : "Off";
|
|
|
|
|
+ DrawText(TextFormat("Use key [N] to toggle normal map: %s", toggleStr), 10, 30, 20, textColor);
|
|
|
|
|
+
|
|
|
|
|
+ int yOffset = 24;
|
|
|
|
|
+ DrawText("Use keys [W][A][S][D] to move the light", 10, 30 + yOffset * 1, 20, BLACK);
|
|
|
|
|
+ DrawText("Use kyes [Up][Down] to change specular exponent", 10, 30 + yOffset * 2, 20, BLACK);
|
|
|
|
|
+ DrawText(TextFormat("Specular Exponent: %.2f", specularExponent), 10, 30 + yOffset * 3, 20, BLUE);
|
|
|
|
|
+
|
|
|
|
|
+ DrawFPS(10, 10);
|
|
|
|
|
+
|
|
|
|
|
+ EndDrawing();
|
|
|
|
|
+ //--------------------------------------------------------------------------------------
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // De-Initialization
|
|
|
|
|
+ //--------------------------------------------------------------------------------------
|
|
|
|
|
+ UnloadShader(shader);
|
|
|
|
|
+ UnloadModel(plane);
|
|
|
|
|
+
|
|
|
|
|
+ CloseWindow(); // Close window and OpenGL context
|
|
|
|
|
+ //--------------------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|