diff options
| author | DarkElvenAngel <jb_rotavele@yahoo.com> | 2019-06-10 16:12:06 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-06-10 16:12:06 -0400 |
| commit | d7f4be071579e6f00974c0940f021272f22fbc54 (patch) | |
| tree | 6ee389e6617c494d272e9bc82415fbc3618e7a28 /examples/models | |
| parent | 8a21830b77eaa76ffe0c31df5f96aecd6bd2eecc (diff) | |
| parent | baf7d7d19ad8d6bfbfc201169e4ed4f49a9576a6 (diff) | |
| download | raylib-d7f4be071579e6f00974c0940f021272f22fbc54.tar.gz raylib-d7f4be071579e6f00974c0940f021272f22fbc54.zip | |
Merge pull request #1 from raysan5/master
Update
Diffstat (limited to 'examples/models')
50 files changed, 1459 insertions, 292 deletions
diff --git a/examples/models/models_animation.c b/examples/models/models_animation.c new file mode 100644 index 00000000..7f38b7f5 --- /dev/null +++ b/examples/models/models_animation.c @@ -0,0 +1,103 @@ +/******************************************************************************************* +* +* raylib [models] example - Load 3d model with animations and play them +* +* This example has been created using raylib 2.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Example contributed by Culacant (@culacant) and reviewed by Ramon Santamaria (@raysan5) +* +* Copyright (c) 2019 Culacant (@culacant) and Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - model animation"); + + // Define the camera to look into our 3d world + Camera camera = { 0 }; + camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.type = CAMERA_PERSPECTIVE; // Camera mode type + + + Model model = LoadModel("resources/guy/guy.iqm"); // Load the animated model mesh and basic data + Texture2D texture = LoadTexture("resources/guy/guytex.png"); // Load model texture and set material + SetMaterialTexture(&model.materials[0], MAP_DIFFUSE, texture); // Set model material map texture + + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position + + // Load animation data + int animsCount = 0; + ModelAnimation *anims = LoadModelAnimations("resources/guy/guyanim.iqm", &animsCount); + int animFrameCounter = 0; + + SetCameraMode(camera, CAMERA_FREE); // Set free camera mode + + 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 + //---------------------------------------------------------------------------------- + UpdateCamera(&camera); + + // Play animation when spacebar is held down + if (IsKeyDown(KEY_SPACE)) + { + animFrameCounter++; + UpdateModelAnimation(model, anims[0], animFrameCounter); + if (animFrameCounter >= anims[0].frameCount) animFrameCounter = 0; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + DrawModelEx(model, position, (Vector3){ 1.0f, 0.0f, 0.0f }, -90.0f, (Vector3){ 1.0f, 1.0f, 1.0f }, WHITE); + + for (int i = 0; i < model.boneCount; i++) + { + DrawCube(anims[0].framePoses[animFrameCounter][i].translation, 0.2f, 0.2f, 0.2f, RED); + } + + DrawGrid(10, 1.0f); // Draw a grid + + EndMode3D(); + + DrawText("PRESS SPACE to PLAY MODEL ANIMATION", 10, 10, 20, MAROON); + DrawText("(c) Guy IQM 3D model by @culacant", screenWidth - 200, screenHeight - 20, 10, GRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + // Unload model animations data + for (int i = 0; i < animsCount; i++) UnloadModelAnimation(anims[i]); + + UnloadModel(model); // Unload model + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/models/models_animation.png b/examples/models/models_animation.png Binary files differnew file mode 100644 index 00000000..57e39dd3 --- /dev/null +++ b/examples/models/models_animation.png diff --git a/examples/models/models_billboard.c b/examples/models/models_billboard.c index 59655714..597e9a60 100644 --- a/examples/models/models_billboard.c +++ b/examples/models/models_billboard.c @@ -11,12 +11,12 @@ #include "raylib.h" -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; + const int screenWidth = 800; + const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [models] example - drawing billboards"); @@ -27,10 +27,10 @@ int main() camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; camera.fovy = 45.0f; camera.type = CAMERA_PERSPECTIVE; - + Texture2D bill = LoadTexture("resources/billboard.png"); // Our texture billboard Vector3 billPosition = { 0.0f, 2.0f, 0.0f }; // Position where draw billboard - + SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode SetTargetFPS(60); // Set our game to run at 60 frames-per-second @@ -51,11 +51,11 @@ int main() ClearBackground(RAYWHITE); BeginMode3D(camera); - + DrawGrid(10, 1.0f); // Draw a grid - + DrawBillboard(camera, bill, billPosition, 2.0f, WHITE); - + EndMode3D(); DrawFPS(10, 10); diff --git a/examples/models/models_box_collisions.c b/examples/models/models_box_collisions.c index 41f6056c..7a937ea7 100644 --- a/examples/models/models_box_collisions.c +++ b/examples/models/models_box_collisions.c @@ -11,31 +11,31 @@ #include "raylib.h" -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; + const int screenWidth = 800; + const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [models] example - box collisions"); // Define the camera to look into our 3d world - Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; - + Camera camera = { { 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + Vector3 playerPosition = { 0.0f, 1.0f, 2.0f }; Vector3 playerSize = { 1.0f, 2.0f, 1.0f }; Color playerColor = GREEN; - + Vector3 enemyBoxPos = { -4.0f, 1.0f, 0.0f }; Vector3 enemyBoxSize = { 2.0f, 2.0f, 2.0f }; - + Vector3 enemySpherePos = { 4.0f, 0.0f, 0.0f }; float enemySphereSize = 1.5f; - + bool collision = false; - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop @@ -43,40 +43,40 @@ int main() { // Update //---------------------------------------------------------------------------------- - + // Move player if (IsKeyDown(KEY_RIGHT)) playerPosition.x += 0.2f; else if (IsKeyDown(KEY_LEFT)) playerPosition.x -= 0.2f; else if (IsKeyDown(KEY_DOWN)) playerPosition.z += 0.2f; else if (IsKeyDown(KEY_UP)) playerPosition.z -= 0.2f; - + collision = false; - + // Check collisions player vs enemy-box if (CheckCollisionBoxes( - (BoundingBox){(Vector3){ playerPosition.x - playerSize.x/2, - playerPosition.y - playerSize.y/2, - playerPosition.z - playerSize.z/2 }, + (BoundingBox){(Vector3){ playerPosition.x - playerSize.x/2, + playerPosition.y - playerSize.y/2, + playerPosition.z - playerSize.z/2 }, (Vector3){ playerPosition.x + playerSize.x/2, - playerPosition.y + playerSize.y/2, + playerPosition.y + playerSize.y/2, playerPosition.z + playerSize.z/2 }}, - (BoundingBox){(Vector3){ enemyBoxPos.x - enemyBoxSize.x/2, - enemyBoxPos.y - enemyBoxSize.y/2, - enemyBoxPos.z - enemyBoxSize.z/2 }, + (BoundingBox){(Vector3){ enemyBoxPos.x - enemyBoxSize.x/2, + enemyBoxPos.y - enemyBoxSize.y/2, + enemyBoxPos.z - enemyBoxSize.z/2 }, (Vector3){ enemyBoxPos.x + enemyBoxSize.x/2, - enemyBoxPos.y + enemyBoxSize.y/2, + enemyBoxPos.y + enemyBoxSize.y/2, enemyBoxPos.z + enemyBoxSize.z/2 }})) collision = true; - + // Check collisions player vs enemy-sphere if (CheckCollisionBoxSphere( - (BoundingBox){(Vector3){ playerPosition.x - playerSize.x/2, - playerPosition.y - playerSize.y/2, - playerPosition.z - playerSize.z/2 }, + (BoundingBox){(Vector3){ playerPosition.x - playerSize.x/2, + playerPosition.y - playerSize.y/2, + playerPosition.z - playerSize.z/2 }, (Vector3){ playerPosition.x + playerSize.x/2, - playerPosition.y + playerSize.y/2, - playerPosition.z + playerSize.z/2 }}, + playerPosition.y + playerSize.y/2, + playerPosition.z + playerSize.z/2 }}, enemySpherePos, enemySphereSize)) collision = true; - + if (collision) playerColor = RED; else playerColor = GREEN; //---------------------------------------------------------------------------------- @@ -92,18 +92,18 @@ int main() // Draw enemy-box DrawCube(enemyBoxPos, enemyBoxSize.x, enemyBoxSize.y, enemyBoxSize.z, GRAY); DrawCubeWires(enemyBoxPos, enemyBoxSize.x, enemyBoxSize.y, enemyBoxSize.z, DARKGRAY); - + // Draw enemy-sphere DrawSphere(enemySpherePos, enemySphereSize, GRAY); DrawSphereWires(enemySpherePos, enemySphereSize, 16, 16, DARKGRAY); - + // Draw player DrawCubeV(playerPosition, playerSize, playerColor); DrawGrid(10, 1.0f); // Draw a grid EndMode3D(); - + DrawText("Move player with cursors to collide", 220, 40, 20, GRAY); DrawFPS(10, 10); diff --git a/examples/models/models_cubicmap.c b/examples/models/models_cubicmap.c index c8d62c46..f5087845 100644 --- a/examples/models/models_cubicmap.c +++ b/examples/models/models_cubicmap.c @@ -11,32 +11,32 @@ #include "raylib.h" -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; + const int screenWidth = 800; + const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [models] example - cubesmap loading and drawing"); // Define the camera to look into our 3d world - Camera camera = {{ 16.0f, 14.0f, 16.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + Camera camera = { { 16.0f, 14.0f, 16.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; Image image = LoadImage("resources/cubicmap.png"); // Load cubicmap image (RAM) Texture2D cubicmap = LoadTextureFromImage(image); // Convert image to texture to display (VRAM) - + Mesh mesh = GenMeshCubicmap(image, (Vector3){ 1.0f, 1.0f, 1.0f }); Model model = LoadModelFromMesh(mesh); - + // NOTE: By default each cube is mapped to one part of texture atlas Texture2D texture = LoadTexture("resources/cubicmap_atlas.png"); // Load map texture - model.material.maps[MAP_DIFFUSE].texture = texture; // Set map diffuse texture - + model.materials[0].maps[MAP_DIFFUSE].texture = texture; // Set map diffuse texture + Vector3 mapPosition = { -16.0f, 0.0f, -8.0f }; // Set model position UnloadImage(image); // Unload cubesmap image from RAM, already uploaded to VRAM - + SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode SetTargetFPS(60); // Set our game to run at 60 frames-per-second @@ -61,10 +61,10 @@ int main() DrawModel(model, mapPosition, 1.0f, WHITE); EndMode3D(); - + DrawTextureEx(cubicmap, (Vector2){ screenWidth - cubicmap.width*4 - 20, 20 }, 0.0f, 4.0f, WHITE); DrawRectangleLines(screenWidth - cubicmap.width*4 - 20, 20, cubicmap.width*4, cubicmap.height*4, GREEN); - + DrawText("cubicmap image used to", 658, 90, 10, GRAY); DrawText("generate map 3d model", 658, 104, 10, GRAY); diff --git a/examples/models/models_first_person_maze.c b/examples/models/models_first_person_maze.c new file mode 100644 index 00000000..07c51b9a --- /dev/null +++ b/examples/models/models_first_person_maze.c @@ -0,0 +1,126 @@ +/******************************************************************************************* +* +* raylib [models] example - first person maze +* +* This example has been created using raylib 2.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2019 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include <stdlib.h> // Required for: free() + +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - first person maze"); + + // Define the camera to look into our 3d world + Camera camera = { { 0.2f, 0.4f, 0.2f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + + Image imMap = LoadImage("resources/cubicmap.png"); // Load cubicmap image (RAM) + Texture2D cubicmap = LoadTextureFromImage(imMap); // Convert image to texture to display (VRAM) + Mesh mesh = GenMeshCubicmap(imMap, (Vector3){ 1.0f, 1.0f, 1.0f }); + Model model = LoadModelFromMesh(mesh); + + // NOTE: By default each cube is mapped to one part of texture atlas + Texture2D texture = LoadTexture("resources/cubicmap_atlas.png"); // Load map texture + model.materials[0].maps[MAP_DIFFUSE].texture = texture; // Set map diffuse texture + + // Get map image data to be used for collision detection + Color *mapPixels = GetImageData(imMap); + UnloadImage(imMap); // Unload image from RAM + + Vector3 mapPosition = { -16.0f, 0.0f, -8.0f }; // Set model position + Vector3 playerPosition = camera.position; // Set player position + + SetCameraMode(camera, CAMERA_FIRST_PERSON); // Set camera mode + + 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 + //---------------------------------------------------------------------------------- + Vector3 oldCamPos = camera.position; // Store old camera position + + UpdateCamera(&camera); // Update camera + + // Check player collision (we simplify to 2D collision detection) + Vector2 playerPos = { camera.position.x, camera.position.z }; + float playerRadius = 0.1f; // Collision radius (player is modelled as a cilinder for collision) + + int playerCellX = (int)(playerPos.x - mapPosition.x + 0.5f); + int playerCellY = (int)(playerPos.y - mapPosition.z + 0.5f); + + // Out-of-limits security check + if (playerCellX < 0) playerCellX = 0; + else if (playerCellX >= cubicmap.width) playerCellX = cubicmap.width - 1; + + if (playerCellY < 0) playerCellY = 0; + else if (playerCellY >= cubicmap.height) playerCellY = cubicmap.height - 1; + + // Check map collisions using image data and player position + // TODO: Improvement: Just check player surrounding cells for collision + for (int y = 0; y < cubicmap.height; y++) + { + for (int x = 0; x < cubicmap.width; x++) + { + if ((mapPixels[y*cubicmap.width + x].r == 255) && // Collision: white pixel, only check R channel + (CheckCollisionCircleRec(playerPos, playerRadius, + (Rectangle){ mapPosition.x - 0.5f + x*1.0f, mapPosition.z - 0.5f + y*1.0f, 1.0f, 1.0f }))) + { + // Collision detected, reset camera position + camera.position = oldCamPos; + } + } + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + DrawModel(model, mapPosition, 1.0f, WHITE); // Draw maze map + //DrawCubeV(playerPosition, (Vector3){ 0.2f, 0.4f, 0.2f }, RED); // Draw player + + EndMode3D(); + + DrawTextureEx(cubicmap, (Vector2){ GetScreenWidth() - cubicmap.width*4 - 20, 20 }, 0.0f, 4.0f, WHITE); + DrawRectangleLines(GetScreenWidth() - cubicmap.width*4 - 20, 20, cubicmap.width*4, cubicmap.height*4, GREEN); + + // Draw player position radar + DrawRectangle(GetScreenWidth() - cubicmap.width*4 - 20 + playerCellX*4, 20 + playerCellY*4, 4, 4, RED); + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + free(mapPixels); // Unload color array + + UnloadTexture(cubicmap); // Unload cubicmap texture + UnloadTexture(texture); // Unload map texture + UnloadModel(model); // Unload map model + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/models/models_first_person_maze.png b/examples/models/models_first_person_maze.png Binary files differnew file mode 100644 index 00000000..ed6047e1 --- /dev/null +++ b/examples/models/models_first_person_maze.png diff --git a/examples/models/models_geometric_shapes.c b/examples/models/models_geometric_shapes.c index 82ca4c60..39477927 100644 --- a/examples/models/models_geometric_shapes.c +++ b/examples/models/models_geometric_shapes.c @@ -11,12 +11,12 @@ #include "raylib.h" -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; + const int screenWidth = 800; + const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes"); @@ -28,7 +28,7 @@ int main() camera.fovy = 45.0f; camera.type = CAMERA_PERSPECTIVE; - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop diff --git a/examples/models/models_heightmap.c b/examples/models/models_heightmap.c index d131b127..a2c2e310 100644 --- a/examples/models/models_heightmap.c +++ b/examples/models/models_heightmap.c @@ -11,29 +11,29 @@ #include "raylib.h" -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; + const int screenWidth = 800; + const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [models] example - heightmap loading and drawing"); // Define our custom camera to look into our 3d world - Camera camera = {{ 18.0f, 16.0f, 18.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + Camera camera = { { 18.0f, 16.0f, 18.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; Image image = LoadImage("resources/heightmap.png"); // Load heightmap image (RAM) Texture2D texture = LoadTextureFromImage(image); // Convert image to texture (VRAM) - + Mesh mesh = GenMeshHeightmap(image, (Vector3){ 16, 8, 16 }); // Generate heightmap mesh (RAM and VRAM) Model model = LoadModelFromMesh(mesh); // Load model from generated mesh - model.material.maps[MAP_DIFFUSE].texture = texture; // Set map diffuse texture + model.materials[0].maps[MAP_DIFFUSE].texture = texture; // Set map diffuse texture Vector3 mapPosition = { -8.0f, 0.0f, -8.0f }; // Define model position UnloadImage(image); // Unload heightmap image from RAM, already uploaded to VRAM - + SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode SetTargetFPS(60); // Set our game to run at 60 frames-per-second @@ -60,7 +60,7 @@ int main() DrawGrid(20, 1.0f); EndMode3D(); - + DrawTexture(texture, screenWidth - texture.width - 20, 20, WHITE); DrawRectangleLines(screenWidth - texture.width - 20, 20, texture.width, texture.height, GREEN); diff --git a/examples/models/models_material_pbr.c b/examples/models/models_material_pbr.c index f93c7a68..8d51eefd 100644 --- a/examples/models/models_material_pbr.c +++ b/examples/models/models_material_pbr.c @@ -12,6 +12,8 @@ #include "raylib.h" #include "raymath.h" +#include <stdio.h> + #define RLIGHTS_IMPLEMENTATION #include "rlights.h" @@ -23,33 +25,42 @@ // PBR material loading static Material LoadMaterialPBR(Color albedo, float metalness, float roughness); -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; + const int screenWidth = 800; + const int screenHeight = 450; SetConfigFlags(FLAG_MSAA_4X_HINT); // Enable Multi Sampling Anti Aliasing 4x (if available) InitWindow(screenWidth, screenHeight, "raylib [models] example - pbr material"); // Define the camera to look into our 3d world - Camera camera = {{ 4.0f, 4.0f, 4.0f }, { 0.0f, 0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + Camera camera = { 0 }; + camera.position = (Vector3){ 4.0f, 4.0f, 4.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.5f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + camera.type = CAMERA_PERSPECTIVE; // Camera mode type // Load model and PBR material Model model = LoadModel("resources/pbr/trooper.obj"); - MeshTangents(&model.mesh); - model.material = LoadMaterialPBR((Color){ 255, 255, 255, 255 }, 1.0f, 1.0f); + + // Mesh tangents are generated... and uploaded to GPU + // NOTE: New VBO for tangents is generated at default location and also binded to mesh VAO + MeshTangents(&model.meshes[0]); + + model.materials[0] = LoadMaterialPBR((Color){ 255, 255, 255, 255 }, 1.0f, 1.0f); // Define lights attributes // NOTE: Shader is passed to every light on creation to define shader bindings internally - Light lights[MAX_LIGHTS] = { - CreateLight(LIGHT_POINT, (Vector3){ LIGHT_DISTANCE, LIGHT_HEIGHT, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 255, 0, 0, 255 }, model.material.shader), - CreateLight(LIGHT_POINT, (Vector3){ 0.0f, LIGHT_HEIGHT, LIGHT_DISTANCE }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 0, 255, 0, 255 }, model.material.shader), - CreateLight(LIGHT_POINT, (Vector3){ -LIGHT_DISTANCE, LIGHT_HEIGHT, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 0, 0, 255, 255 }, model.material.shader), - CreateLight(LIGHT_DIRECTIONAL, (Vector3){ 0.0f, LIGHT_HEIGHT*2.0f, -LIGHT_DISTANCE }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 255, 0, 255, 255 }, model.material.shader) + Light lights[MAX_LIGHTS] = { + CreateLight(LIGHT_POINT, (Vector3){ LIGHT_DISTANCE, LIGHT_HEIGHT, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 255, 0, 0, 255 }, model.materials[0].shader), + CreateLight(LIGHT_POINT, (Vector3){ 0.0f, LIGHT_HEIGHT, LIGHT_DISTANCE }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 0, 255, 0, 255 }, model.materials[0].shader), + CreateLight(LIGHT_POINT, (Vector3){ -LIGHT_DISTANCE, LIGHT_HEIGHT, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 0, 0, 255, 255 }, model.materials[0].shader), + CreateLight(LIGHT_DIRECTIONAL, (Vector3){ 0.0f, LIGHT_HEIGHT*2.0f, -LIGHT_DISTANCE }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 255, 0, 255, 255 }, model.materials[0].shader) }; - + SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode SetTargetFPS(60); // Set our game to run at 60 frames-per-second @@ -61,10 +72,10 @@ int main() // Update //---------------------------------------------------------------------------------- UpdateCamera(&camera); // Update camera - + // Send to material PBR shader camera view position float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z }; - SetShaderValue(model.material.shader, model.material.shader.locs[LOC_VECTOR_VIEW], cameraPos, UNIFORM_VEC3); + SetShaderValue(model.materials[0].shader, model.materials[0].shader.locs[LOC_VECTOR_VIEW], cameraPos, UNIFORM_VEC3); //---------------------------------------------------------------------------------- // Draw @@ -76,7 +87,7 @@ int main() BeginMode3D(camera); DrawModel(model, Vector3Zero(), 1.0f, WHITE); - + DrawGrid(10, 1.0f); EndMode3D(); @@ -103,11 +114,12 @@ static Material LoadMaterialPBR(Color albedo, float metalness, float roughness) { Material mat = { 0 }; // NOTE: All maps textures are set to { 0 } - #define PATH_PBR_VS "resources/shaders/pbr.vs" // Path to physically based rendering vertex shader - #define PATH_PBR_FS "resources/shaders/pbr.fs" // Path to physically based rendering fragment shader - - mat.shader = LoadShader(PATH_PBR_VS, PATH_PBR_FS); - +#if defined(PLATFORM_DESKTOP) + mat.shader = LoadShader("resources/shaders/glsl330/pbr.vs", "resources/shaders/glsl330/pbr.fs"); +#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB + mat.shader = LoadShader("resources/shaders/glsl100/pbr.vs", "resources/shaders/glsl100/pbr.fs"); +#endif + // Get required locations points for PBR material // NOTE: Those location names must be available and used in the shader code mat.shader.locs[LOC_MAP_ALBEDO] = GetShaderLocation(mat.shader, "albedo.sampler"); @@ -125,7 +137,7 @@ static Material LoadMaterialPBR(Color albedo, float metalness, float roughness) mat.shader.locs[LOC_MATRIX_MODEL] = GetShaderLocation(mat.shader, "matModel"); mat.shader.locs[LOC_MATRIX_VIEW] = GetShaderLocation(mat.shader, "view"); mat.shader.locs[LOC_VECTOR_VIEW] = GetShaderLocation(mat.shader, "viewPos"); - + // Set PBR standard maps mat.maps[MAP_ALBEDO].texture = LoadTexture("resources/pbr/trooper_albedo.png"); mat.maps[MAP_NORMAL].texture = LoadTexture("resources/pbr/trooper_normals.png"); @@ -133,19 +145,33 @@ static Material LoadMaterialPBR(Color albedo, float metalness, float roughness) mat.maps[MAP_ROUGHNESS].texture = LoadTexture("resources/pbr/trooper_roughness.png"); mat.maps[MAP_OCCLUSION].texture = LoadTexture("resources/pbr/trooper_ao.png"); - // Set environment maps - #define PATH_CUBEMAP_VS "resources/shaders/cubemap.vs" // Path to equirectangular to cubemap vertex shader - #define PATH_CUBEMAP_FS "resources/shaders/cubemap.fs" // Path to equirectangular to cubemap fragment shader - #define PATH_SKYBOX_VS "resources/shaders/skybox.vs" // Path to skybox vertex shader - #define PATH_IRRADIANCE_FS "resources/shaders/irradiance.fs" // Path to irradiance (GI) calculation fragment shader - #define PATH_PREFILTER_FS "resources/shaders/prefilter.fs" // Path to reflection prefilter calculation fragment shader - #define PATH_BRDF_VS "resources/shaders/brdf.vs" // Path to bidirectional reflectance distribution function vertex shader - #define PATH_BRDF_FS "resources/shaders/brdf.fs" // Path to bidirectional reflectance distribution function fragment shader - - Shader shdrCubemap = LoadShader(PATH_CUBEMAP_VS, PATH_CUBEMAP_FS); - Shader shdrIrradiance = LoadShader(PATH_SKYBOX_VS, PATH_IRRADIANCE_FS); - Shader shdrPrefilter = LoadShader(PATH_SKYBOX_VS, PATH_PREFILTER_FS); - Shader shdrBRDF = LoadShader(PATH_BRDF_VS, PATH_BRDF_FS); + // Load equirectangular to cubemap shader +#if defined(PLATFORM_DESKTOP) + Shader shdrCubemap = LoadShader("resources/shaders/glsl330/cubemap.vs", "resources/shaders/glsl330/cubemap.fs"); +#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB + Shader shdrCubemap = LoadShader("resources/shaders/glsl100/cubemap.vs", "resources/shaders/glsl100/cubemap.fs"); +#endif + + // Load irradiance (GI) calculation shader +#if defined(PLATFORM_DESKTOP) + Shader shdrIrradiance = LoadShader("resources/shaders/glsl330/skybox.vs", "resources/shaders/glsl330/irradiance.fs"); +#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB + Shader shdrIrradiance = LoadShader("resources/shaders/glsl100/skybox.vs", "resources/shaders/glsl100/irradiance.fs"); +#endif + + // Load reflection prefilter calculation shader +#if defined(PLATFORM_DESKTOP) + Shader shdrPrefilter = LoadShader("resources/shaders/glsl330/skybox.vs", "resources/shaders/glsl330/prefilter.fs"); +#else + Shader shdrPrefilter = LoadShader("resources/shaders/glsl100/skybox.vs", "resources/shaders/glsl100/prefilter.fs"); +#endif + + // Load bidirectional reflectance distribution function shader +#if defined(PLATFORM_DESKTOP) + Shader shdrBRDF = LoadShader("resources/shaders/glsl330/brdf.vs", "resources/shaders/glsl330/brdf.fs"); +#else + Shader shdrBRDF = LoadShader("resources/shaders/glsl100/brdf.vs", "resources/shaders/glsl100/brdf.fs"); +#endif // Setup required shader locations SetShaderValue(shdrCubemap, GetShaderLocation(shdrCubemap, "equirectangularMap"), (int[1]){ 0 }, UNIFORM_INT); @@ -159,27 +185,27 @@ static Material LoadMaterialPBR(Color albedo, float metalness, float roughness) mat.maps[MAP_BRDF].texture = GenTextureBRDF(shdrBRDF, BRDF_SIZE); UnloadTexture(cubemap); UnloadTexture(texHDR); - + // Unload already used shaders (to create specific textures) UnloadShader(shdrCubemap); UnloadShader(shdrIrradiance); UnloadShader(shdrPrefilter); UnloadShader(shdrBRDF); - + // Set textures filtering for better quality SetTextureFilter(mat.maps[MAP_ALBEDO].texture, FILTER_BILINEAR); SetTextureFilter(mat.maps[MAP_NORMAL].texture, FILTER_BILINEAR); SetTextureFilter(mat.maps[MAP_METALNESS].texture, FILTER_BILINEAR); SetTextureFilter(mat.maps[MAP_ROUGHNESS].texture, FILTER_BILINEAR); SetTextureFilter(mat.maps[MAP_OCCLUSION].texture, FILTER_BILINEAR); - + // Enable sample usage in shader for assigned textures SetShaderValue(mat.shader, GetShaderLocation(mat.shader, "albedo.useSampler"), (int[1]){ 1 }, UNIFORM_INT); SetShaderValue(mat.shader, GetShaderLocation(mat.shader, "normals.useSampler"), (int[1]){ 1 }, UNIFORM_INT); SetShaderValue(mat.shader, GetShaderLocation(mat.shader, "metalness.useSampler"), (int[1]){ 1 }, UNIFORM_INT); SetShaderValue(mat.shader, GetShaderLocation(mat.shader, "roughness.useSampler"), (int[1]){ 1 }, UNIFORM_INT); SetShaderValue(mat.shader, GetShaderLocation(mat.shader, "occlusion.useSampler"), (int[1]){ 1 }, UNIFORM_INT); - + int renderModeLoc = GetShaderLocation(mat.shader, "renderMode"); SetShaderValue(mat.shader, renderModeLoc, (int[1]){ 0 }, UNIFORM_INT); diff --git a/examples/models/models_mesh_generation.c b/examples/models/models_mesh_generation.c index d64889bd..6c0ae653 100644 --- a/examples/models/models_mesh_generation.c +++ b/examples/models/models_mesh_generation.c @@ -11,24 +11,24 @@ #include "raylib.h" -#define NUM_MODELS 8 // We generate 8 parametric 3d shapes +#define NUM_MODELS 8 // Parametric 3d shapes to generate -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; + const int screenWidth = 800; + const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh generation"); - + // We generate a checked image for texturing Image checked = GenImageChecked(2, 2, 1, 1, RED, GREEN); Texture2D texture = LoadTextureFromImage(checked); UnloadImage(checked); - - Model models[NUM_MODELS]; - + + Model models[NUM_MODELS] = { 0 }; + models[0] = LoadModelFromMesh(GenMeshPlane(2, 2, 5, 5)); models[1] = LoadModelFromMesh(GenMeshCube(2.0f, 1.0f, 2.0f)); models[2] = LoadModelFromMesh(GenMeshSphere(2, 32, 32)); @@ -37,21 +37,21 @@ int main() models[5] = LoadModelFromMesh(GenMeshTorus(0.25f, 4.0f, 16, 32)); models[6] = LoadModelFromMesh(GenMeshKnot(1.0f, 2.0f, 16, 128)); models[7] = LoadModelFromMesh(GenMeshPoly(5, 2.0f)); - + // Set checked texture as default diffuse component for all models material - for (int i = 0; i < NUM_MODELS; i++) models[i].material.maps[MAP_DIFFUSE].texture = texture; + for (int i = 0; i < NUM_MODELS; i++) models[i].materials[0].maps[MAP_DIFFUSE].texture = texture; // Define the camera to look into our 3d world - Camera camera = {{ 5.0f, 5.0f, 5.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + Camera camera = { { 5.0f, 5.0f, 5.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; // Model drawing position Vector3 position = { 0.0f, 0.0f, 0.0f }; - + int currentModel = 0; - + SetCameraMode(camera, CAMERA_ORBITAL); // Set a orbital camera mode - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop @@ -60,11 +60,22 @@ int main() // Update //---------------------------------------------------------------------------------- UpdateCamera(&camera); // Update internal camera and our camera - + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { currentModel = (currentModel + 1)%NUM_MODELS; // Cycle between the textures } + + if (IsKeyPressed(KEY_RIGHT)) + { + currentModel++; + if (currentModel >= NUM_MODELS) currentModel = 0; + } + else if (IsKeyPressed(KEY_LEFT)) + { + currentModel--; + if (currentModel < 0) currentModel = NUM_MODELS - 1; + } //---------------------------------------------------------------------------------- // Draw @@ -80,11 +91,11 @@ int main() DrawGrid(10, 1.0); EndMode3D(); - + DrawRectangle(30, 400, 310, 30, Fade(SKYBLUE, 0.5f)); DrawRectangleLines(30, 400, 310, 30, Fade(DARKBLUE, 0.5f)); DrawText("MOUSE LEFT BUTTON to CYCLE PROCEDURAL MODELS", 40, 410, 10, BLUE); - + switch(currentModel) { case 0: DrawText("PLANE", 680, 10, 20, DARKBLUE); break; @@ -104,10 +115,10 @@ int main() // De-Initialization //-------------------------------------------------------------------------------------- - + // Unload models data (GPU VRAM) for (int i = 0; i < NUM_MODELS; i++) UnloadModel(models[i]); - + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_mesh_picking.c b/examples/models/models_mesh_picking.c index 9b12e98c..0bf95dd1 100644 --- a/examples/models/models_mesh_picking.c +++ b/examples/models/models_mesh_picking.c @@ -5,8 +5,9 @@ * This example has been created using raylib 1.7 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2015 Ramon Santamaria (@raysan5) -* Example contributed by Joel Davis (@joeld42) +* Example contributed by Joel Davis (@joeld42) and reviewed by Ramon Santamaria (@raysan5) +* +* Copyright (c) 2017 Joel Davis (@joeld42) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ @@ -15,40 +16,40 @@ #define FLT_MAX 340282346638528859811704183484516925440.0f // Maximum value of a float, from bit pattern 01111111011111111111111111111111 -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; + const int screenWidth = 800; + const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh picking"); // Define the camera to look into our 3d world Camera camera = { 0 }; - camera.position = (Vector3){ 20.0f, 20.0f, 20.0f }; // Camera position + camera.position = (Vector3){ 20.0f, 20.0f, 20.0f }; // Camera position camera.target = (Vector3){ 0.0f, 8.0f, 0.0f }; // Camera looking at point camera.up = (Vector3){ 0.0f, 1.6f, 0.0f }; // Camera up vector (rotation towards target) camera.fovy = 45.0f; // Camera field-of-view Y camera.type = CAMERA_PERSPECTIVE; // Camera mode type Ray ray = { 0 }; // Picking ray - + Model tower = LoadModel("resources/models/turret.obj"); // Load OBJ model Texture2D texture = LoadTexture("resources/models/turret_diffuse.png"); // Load model texture - tower.material.maps[MAP_DIFFUSE].texture = texture; // Set model diffuse texture - + tower.materials[0].maps[MAP_DIFFUSE].texture = texture; // Set model diffuse texture + Vector3 towerPos = { 0.0f, 0.0f, 0.0f }; // Set model position - BoundingBox towerBBox = MeshBoundingBox(tower.mesh); // Get mesh bounding box + BoundingBox towerBBox = MeshBoundingBox(tower.meshes[0]); // Get mesh bounding box bool hitMeshBBox = false; bool hitTriangle = false; // Test triangle - Vector3 ta = (Vector3){ -25.0, 0.5, 0.0 }; + Vector3 ta = (Vector3){ -25.0, 0.5, 0.0 }; Vector3 tb = (Vector3){ -4.0, 2.5, 1.0 }; Vector3 tc = (Vector3){ -8.0, 6.5, 0.0 }; - Vector3 bary = { 0.0f, 0.0f, 0.0f }; + Vector3 bary = { 0.0f, 0.0f, 0.0f }; SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode @@ -60,7 +61,7 @@ int main() // Update //---------------------------------------------------------------------------------- UpdateCamera(&camera); // Update camera - + // Display information about closest hit RayHitInfo nearestHit = { 0 }; char *hitObjectName = "None"; @@ -70,10 +71,10 @@ int main() // Get ray and test against ground, triangle, and mesh ray = GetMouseRay(GetMousePosition(), camera); - + // Check ray collision aginst ground plane RayHitInfo groundHitInfo = GetCollisionRayGround(ray, 0.0f); - + if ((groundHitInfo.hit) && (groundHitInfo.distance < nearestHit.distance)) { nearestHit = groundHitInfo; @@ -83,8 +84,8 @@ int main() // Check ray collision against test triangle RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, ta, tb, tc); - - if ((triHitInfo.hit) && (triHitInfo.distance < nearestHit.distance)) + + if ((triHitInfo.hit) && (triHitInfo.distance < nearestHit.distance)) { nearestHit = triHitInfo; cursorColor = PURPLE; @@ -92,32 +93,31 @@ int main() bary = Vector3Barycenter(nearestHit.position, ta, tb, tc); hitTriangle = true; - } + } else hitTriangle = false; RayHitInfo meshHitInfo = { 0 }; // Check ray collision against bounding box first, before trying the full ray-mesh test - if (CheckCollisionRayBox(ray, towerBBox)) + if (CheckCollisionRayBox(ray, towerBBox)) { hitMeshBBox = true; - + // Check ray collision against model // NOTE: It considers model.transform matrix! - meshHitInfo = GetCollisionRayModel(ray, &tower); - - if ((meshHitInfo.hit) && (meshHitInfo.distance < nearestHit.distance)) + meshHitInfo = GetCollisionRayModel(ray, &tower); + + if ((meshHitInfo.hit) && (meshHitInfo.distance < nearestHit.distance)) { nearestHit = meshHitInfo; cursorColor = ORANGE; hitObjectName = "Mesh"; } - - } - - hitMeshBBox = false; + } + + hitMeshBBox = false; //---------------------------------------------------------------------------------- - + // Draw //---------------------------------------------------------------------------------- BeginDrawing(); @@ -127,10 +127,10 @@ int main() BeginMode3D(camera); // Draw the tower - // WARNING: If scale is different than 1.0f, + // WARNING: If scale is different than 1.0f, // not considered by GetCollisionRayModel() DrawModel(tower, towerPos, 1.0f, WHITE); - + // Draw the test triangle DrawLine3D(ta, tb, PURPLE); DrawLine3D(tb, tc, PURPLE); @@ -140,7 +140,7 @@ int main() if (hitMeshBBox) DrawBoundingBox(towerBBox, LIME); // If we hit something, draw the cursor at the hit point - if (nearestHit.hit) + if (nearestHit.hit) { DrawCube(nearestHit.position, 0.3, 0.3, 0.3, cursorColor); DrawCubeWires(nearestHit.position, 0.3, 0.3, 0.3, RED); @@ -149,40 +149,40 @@ int main() normalEnd.x = nearestHit.position.x + nearestHit.normal.x; normalEnd.y = nearestHit.position.y + nearestHit.normal.y; normalEnd.z = nearestHit.position.z + nearestHit.normal.z; - + DrawLine3D(nearestHit.position, normalEnd, RED); } DrawRay(ray, MAROON); - + DrawGrid(10, 10.0f); EndMode3D(); - + // Draw some debug GUI text DrawText(FormatText("Hit Object: %s", hitObjectName), 10, 50, 10, BLACK); - if (nearestHit.hit) + if (nearestHit.hit) { int ypos = 70; DrawText(FormatText("Distance: %3.2f", nearestHit.distance), 10, ypos, 10, BLACK); - - DrawText(FormatText("Hit Pos: %3.2f %3.2f %3.2f", - nearestHit.position.x, - nearestHit.position.y, + + DrawText(FormatText("Hit Pos: %3.2f %3.2f %3.2f", + nearestHit.position.x, + nearestHit.position.y, nearestHit.position.z), 10, ypos + 15, 10, BLACK); - - DrawText(FormatText("Hit Norm: %3.2f %3.2f %3.2f", - nearestHit.normal.x, - nearestHit.normal.y, + + DrawText(FormatText("Hit Norm: %3.2f %3.2f %3.2f", + nearestHit.normal.x, + nearestHit.normal.y, nearestHit.normal.z), 10, ypos + 30, 10, BLACK); if (hitTriangle) DrawText(FormatText("Barycenter: %3.2f %3.2f %3.2f", bary.x, bary.y, bary.z), 10, ypos + 45, 10, BLACK); } DrawText("Use Mouse to Move Camera", 10, 430, 10, GRAY); - + DrawText("(c) Turret 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, GRAY); DrawFPS(10, 10); @@ -195,7 +195,7 @@ int main() //-------------------------------------------------------------------------------------- UnloadModel(tower); // Unload model UnloadTexture(texture); // Unload texture - + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_obj_loading.c b/examples/models/models_obj_loading.c index 7ec2d3f0..51578bc1 100644 --- a/examples/models/models_obj_loading.c +++ b/examples/models/models_obj_loading.c @@ -11,12 +11,12 @@ #include "raylib.h" -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; + const int screenWidth = 800; + const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [models] example - obj model loading"); @@ -30,10 +30,10 @@ int main() Model model = LoadModel("resources/models/castle.obj"); // Load OBJ model Texture2D texture = LoadTexture("resources/models/castle_diffuse.png"); // Load model texture - model.material.maps[MAP_DIFFUSE].texture = texture; // Set map diffuse texture + model.materials[0].maps[MAP_DIFFUSE].texture = texture; // Set map diffuse texture Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop @@ -59,7 +59,7 @@ int main() DrawGizmo(position); // Draw gizmo EndMode3D(); - + DrawText("(c) Castle 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, GRAY); DrawFPS(10, 10); diff --git a/examples/models/models_obj_viewer.c b/examples/models/models_obj_viewer.c index 15f79549..83c8f2f1 100644 --- a/examples/models/models_obj_viewer.c +++ b/examples/models/models_obj_viewer.c @@ -5,7 +5,7 @@ * This example has been created using raylib 2.0 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) * ********************************************************************************************/ @@ -13,31 +13,31 @@ #include <string.h> // Required for: strcpy() -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; + const int screenWidth = 800; + const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib example - obj viewer"); // Define the camera to look into our 3d world - Camera camera = {{ 30.0f, 30.0f, 30.0f }, { 0.0f, 10.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + Camera camera = { { 30.0f, 30.0f, 30.0f }, { 0.0f, 10.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; Model model = LoadModel("resources/models/turret.obj"); // Load default model obj Texture2D texture = LoadTexture("resources/models/turret_diffuse.png"); // Load default model texture - model.material.maps[MAP_DIFFUSE].texture = texture; // Bind texture to model - - Vector3 position = { 0.0, 0.0, 0.0 }; // Set model position - BoundingBox bounds = MeshBoundingBox(model.mesh); // Set model bounds - bool selected = false; // Selected object flag - - SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode + model.materials[0].maps[MAP_DIFFUSE].texture = texture; // Bind texture to model + + Vector3 position = { 0.0, 0.0, 0.0 }; // Set model position + BoundingBox bounds = MeshBoundingBox(model.meshes[0]); // Set model bounds + bool selected = false; // Selected object flag + + SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode char objFilename[64] = "turret.obj"; - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop @@ -49,30 +49,30 @@ int main() { int count = 0; char **droppedFiles = GetDroppedFiles(&count); - + if (count == 1) { if (IsFileExtension(droppedFiles[0], ".obj")) { - UnloadMesh(&model.mesh); - model.mesh = LoadMesh(droppedFiles[0]); - bounds = MeshBoundingBox(model.mesh); + for (int i = 0; i < model.meshCount; i++) UnloadMesh(&model.meshes[i]); + model.meshes = LoadMeshes(droppedFiles[0], &model.meshCount); + bounds = MeshBoundingBox(model.meshes[0]); } else if (IsFileExtension(droppedFiles[0], ".png")) { UnloadTexture(texture); texture = LoadTexture(droppedFiles[0]); - model.material.maps[MAP_DIFFUSE].texture = texture; + model.materials[0].maps[MAP_DIFFUSE].texture = texture; } strcpy(objFilename, GetFileName(droppedFiles[0])); } - + ClearDroppedFiles(); // Clear internal buffers } - + UpdateCamera(&camera); - + // Select model on mouse click if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { @@ -93,21 +93,21 @@ int main() DrawModel(model, position, 1.0f, WHITE); // Draw 3d model with texture DrawGrid(20.0, 10.0); // Draw a grid - + if (selected) DrawBoundingBox(bounds, GREEN); - + EndMode3D(); - + DrawText("Free camera default controls:", 10, 20, 10, DARKGRAY); DrawText("- Mouse Wheel to Zoom in-out", 20, 40, 10, GRAY); DrawText("- Mouse Wheel Pressed to Pan", 20, 60, 10, GRAY); DrawText("- Alt + Mouse Wheel Pressed to Rotate", 20, 80, 10, GRAY); DrawText("- Alt + Ctrl + Mouse Wheel Pressed for Smooth Zoom", 20, 100, 10, GRAY); - + DrawText("Drag & drop .obj/.png to load mesh/texture.", 10, GetScreenHeight() - 20, 10, DARKGRAY); DrawText(FormatText("Current file: %s", objFilename), 250, GetScreenHeight() - 20, 10, GRAY); if (selected) DrawText("MODEL SELECTED", GetScreenWidth() - 110, 10, 10, GREEN); - + DrawText("(c) Turret 3D model by Alberto Cano", screenWidth - 200, screenHeight - 20, 10, GRAY); EndDrawing(); @@ -119,7 +119,7 @@ int main() UnloadModel(model); // Unload model ClearDroppedFiles(); // Clear internal buffers - + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/models/models_orthographic_projection.c b/examples/models/models_orthographic_projection.c index f9b54b6d..8c9b5b1c 100644 --- a/examples/models/models_orthographic_projection.c +++ b/examples/models/models_orthographic_projection.c @@ -1,13 +1,15 @@ /******************************************************************************************* * -* raylib [models] example - Show the difference between perspective and orthographic projection +* raylib [models] example - Show the difference between perspective and orthographic projection * * This program is heavily based on the geometric objects example * -* This example has been created using raylib 1.9.7 (www.raylib.com) +* This example has been created using raylib 2.0 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2018 Max Danielsson & Ramon Santamaria (@raysan5) +* Example contributed by Max Danielsson (@autious) and reviewed by Ramon Santamaria (@raysan5) +* +* Copyright (c) 2018 Max Danielsson (@autious) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ @@ -16,19 +18,19 @@ #define FOVY_PERSPECTIVE 45.0f #define WIDTH_ORTHOGRAPHIC 10.0f -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; + const int screenWidth = 800; + const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes"); // Define the camera to look into our 3d world - Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, FOVY_PERSPECTIVE, CAMERA_PERSPECTIVE }; + Camera camera = { { 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, FOVY_PERSPECTIVE, CAMERA_PERSPECTIVE }; - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop @@ -36,14 +38,14 @@ int main() { // Update //---------------------------------------------------------------------------------- - if (IsKeyPressed(KEY_SPACE)) + if (IsKeyPressed(KEY_SPACE)) { - if (camera.type == CAMERA_PERSPECTIVE) + if (camera.type == CAMERA_PERSPECTIVE) { camera.fovy = WIDTH_ORTHOGRAPHIC; camera.type = CAMERA_ORTHOGRAPHIC; - } - else + } + else { camera.fovy = FOVY_PERSPECTIVE; camera.type = CAMERA_PERSPECTIVE; diff --git a/examples/models/models_rlgl_solar_system.c b/examples/models/models_rlgl_solar_system.c index 7193d6f8..cb9289ad 100644 --- a/examples/models/models_rlgl_solar_system.c +++ b/examples/models/models_rlgl_solar_system.c @@ -22,13 +22,13 @@ void DrawSphereBasic(Color color); // Draw sphere without any matrix transf //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- const int screenWidth = 800; const int screenHeight = 450; - + const float sunRadius = 4.0f; const float earthRadius = 0.6f; const float earthOrbitRadius = 8.0f; @@ -44,26 +44,26 @@ int main() camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; camera.fovy = 45.0f; camera.type = CAMERA_PERSPECTIVE; - + SetCameraMode(camera, CAMERA_FREE); - + float rotationSpeed = 0.2f; // General system rotation speed - + float earthRotation = 0.0f; // Rotation of earth around itself (days) in degrees float earthOrbitRotation = 0.0f; // Rotation of earth around the Sun (years) in degrees float moonRotation = 0.0f; // Rotation of moon around itself float moonOrbitRotation = 0.0f; // Rotation of moon around earth in degrees - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- UpdateCamera(&camera); - + earthRotation += (5.0f*rotationSpeed); earthOrbitRotation += (365/360.0f*(5.0f*rotationSpeed)*rotationSpeed); moonRotation += (2.0f*rotationSpeed); @@ -77,12 +77,12 @@ int main() ClearBackground(RAYWHITE); BeginMode3D(camera); - + rlPushMatrix(); rlScalef(sunRadius, sunRadius, sunRadius); // Scale Sun DrawSphereBasic(GOLD); // Draw the Sun rlPopMatrix(); - + rlPushMatrix(); rlRotatef(earthOrbitRotation, 0.0f, 1.0f, 0.0f); // Rotation for Earth orbit around Sun rlTranslatef(earthOrbitRadius, 0.0f, 0.0f); // Translation for Earth orbit @@ -91,19 +91,19 @@ int main() rlPushMatrix(); rlRotatef(earthRotation, 0.25, 1.0, 0.0); // Rotation for Earth itself rlScalef(earthRadius, earthRadius, earthRadius);// Scale Earth - + DrawSphereBasic(BLUE); // Draw the Earth rlPopMatrix(); - + rlRotatef(moonOrbitRotation, 0.0f, 1.0f, 0.0f); // Rotation for Moon orbit around Earth rlTranslatef(moonOrbitRadius, 0.0f, 0.0f); // Translation for Moon orbit rlRotatef(-moonOrbitRotation, 0.0f, 1.0f, 0.0f); // Rotation for Moon orbit around Earth inverted rlRotatef(moonRotation, 0.0f, 1.0f, 0.0f); // Rotation for Moon itself rlScalef(moonRadius, moonRadius, moonRadius); // Scale Moon - + DrawSphereBasic(LIGHTGRAY); // Draw the Moon rlPopMatrix(); - + // Some reference elements (not affected by previous matrix transformations) DrawCircle3D((Vector3){ 0.0f, 0.0f, 0.0f }, earthOrbitRadius, (Vector3){ 1, 0, 0 }, 90.0f, Fade(RED, 0.5f)); DrawGrid(20, 1.0f); @@ -135,7 +135,7 @@ void DrawSphereBasic(Color color) { int rings = 16; int slices = 16; - + rlBegin(RL_TRIANGLES); rlColor4ub(color.r, color.g, color.b, color.a); diff --git a/examples/models/models_skybox.c b/examples/models/models_skybox.c index c7f76ecf..bad29b96 100644 --- a/examples/models/models_skybox.c +++ b/examples/models/models_skybox.c @@ -11,41 +11,49 @@ #include "raylib.h" -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; + const int screenWidth = 800; + const int screenHeight = 450; InitWindow(screenWidth, screenHeight, "raylib [models] example - skybox loading and drawing"); // Define the camera to look into our 3d world - Camera camera = {{ 1.0f, 1.0f, 1.0f }, { 4.0f, 1.0f, 4.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; + Camera camera = { { 1.0f, 1.0f, 1.0f }, { 4.0f, 1.0f, 4.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 }; - // Load skybox model + // Load skybox model Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f); Model skybox = LoadModelFromMesh(cube); - + // Load skybox shader and set required locations // NOTE: Some locations are automatically set at shader loading - skybox.material.shader = LoadShader("resources/shaders/skybox.vs", "resources/shaders/skybox.fs"); - SetShaderValue(skybox.material.shader, GetShaderLocation(skybox.material.shader, "environmentMap"), (int[1]){ MAP_CUBEMAP }, UNIFORM_INT); +#if defined(PLATFORM_DESKTOP) + skybox.materials[0].shader = LoadShader("resources/shaders/glsl330/skybox.vs", "resources/shaders/glsl330/skybox.fs"); +#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB + skybox.materials[0].shader = LoadShader("resources/shaders/glsl100/skybox.vs", "resources/shaders/glsl100/skybox.fs"); +#endif + SetShaderValue(skybox.materials[0].shader, GetShaderLocation(skybox.materials[0].shader, "environmentMap"), (int[1]){ MAP_CUBEMAP }, UNIFORM_INT); // Load cubemap shader and setup required shader locations - Shader shdrCubemap = LoadShader("resources/shaders/cubemap.vs", "resources/shaders/cubemap.fs"); +#if defined(PLATFORM_DESKTOP) + Shader shdrCubemap = LoadShader("resources/shaders/glsl330/cubemap.vs", "resources/shaders/glsl330/cubemap.fs"); +#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB + Shader shdrCubemap = LoadShader("resources/shaders/glsl100/cubemap.vs", "resources/shaders/glsl100/cubemap.fs"); +#endif SetShaderValue(shdrCubemap, GetShaderLocation(shdrCubemap, "equirectangularMap"), (int[1]){ 0 }, UNIFORM_INT); - + // Load HDR panorama (sphere) texture Texture2D texHDR = LoadTexture("resources/dresden_square.hdr"); - + // Generate cubemap (texture with 6 quads-cube-mapping) from panorama HDR texture // NOTE: New texture is generated rendering to texture, shader computes the sphre->cube coordinates mapping - skybox.material.maps[MAP_CUBEMAP].texture = GenTextureCubemap(shdrCubemap, texHDR, 512); - + skybox.materials[0].maps[MAP_CUBEMAP].texture = GenTextureCubemap(shdrCubemap, texHDR, 512); + UnloadTexture(texHDR); // Texture not required anymore, cubemap already generated UnloadShader(shdrCubemap); // Unload cubemap generation shader, not required anymore - + SetCameraMode(camera, CAMERA_FIRST_PERSON); // Set a first person camera mode SetTargetFPS(60); // Set our game to run at 60 frames-per-second @@ -68,7 +76,7 @@ int main() BeginMode3D(camera); DrawModel(skybox, (Vector3){0, 0, 0}, 1.0f, WHITE); - + DrawGrid(10, 1.0f); EndMode3D(); diff --git a/examples/models/models_waving_cubes.c b/examples/models/models_waving_cubes.c new file mode 100644 index 00000000..f6309bd6 --- /dev/null +++ b/examples/models/models_waving_cubes.c @@ -0,0 +1,112 @@ +/******************************************************************************************* +* +* raylib [models] example - Waving cubes +* +* This example has been created using raylib 2.5 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Example contributed by Codecat (@codecat) and reviewed by Ramon Santamaria (@raysan5) +* +* Copyright (c) 2019 Codecat (@codecat) and Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include <math.h> + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - waving cubes"); + + // Initialize the camera + Camera3D camera = { 0 }; + camera.position = (Vector3){ 30.0f, 20.0f, 30.0f }; + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; + camera.fovy = 70.0f; + camera.type = CAMERA_PERSPECTIVE; + + // Specify the amount of blocks in each direction + const int numBlocks = 15; + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + double time = GetTime(); + + // Calculate time scale for cube position and size + float scale = (2.0f + (float)sin(time))*0.7f; + + // Move camera around the scene + double cameraTime = time*0.3; + camera.position.x = (float)cos(cameraTime)*40.0f; + camera.position.z = (float)sin(cameraTime)*40.0f; + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + BeginMode3D(camera); + + DrawGrid(10, 5.0f); + + for (int x = 0; x < numBlocks; x++) + { + for (int y = 0; y < numBlocks; y++) + { + for (int z = 0; z < numBlocks; z++) + { + // Scale of the blocks depends on x/y/z positions + float blockScale = (x + y + z)/30.0f; + + // Scatter makes the waving effect by adding blockScale over time + float scatter = sinf(blockScale*20.0f + (float)(time*4.0f)); + + // Calculate the cube position + Vector3 cubePos = { + (float)(x - numBlocks/2)*(scale*3.0f) + scatter, + (float)(y - numBlocks/2)*(scale*2.0f) + scatter, + (float)(z - numBlocks/2)*(scale*3.0f) + scatter + }; + + // Pick a color with a hue depending on cube position for the rainbow color effect + Color cubeColor = ColorFromHSV((Vector3){ (float)(((x + y + z)*18)%360), 0.75f, 0.9f }); + + // Calculate cube size + float cubeSize = (2.4f - scale)*blockScale; + + // And finally, draw the cube! + DrawCube(cubePos, cubeSize, cubeSize, cubeSize, cubeColor); + } + } + } + + EndMode3D(); + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/models/models_waving_cubes.png b/examples/models/models_waving_cubes.png Binary files differnew file mode 100644 index 00000000..37a1761e --- /dev/null +++ b/examples/models/models_waving_cubes.png diff --git a/examples/models/models_yaw_pitch_roll.c b/examples/models/models_yaw_pitch_roll.c index 88b0a610..0931c00e 100644 --- a/examples/models/models_yaw_pitch_roll.c +++ b/examples/models/models_yaw_pitch_roll.c @@ -5,9 +5,9 @@ * This example has been created using raylib 1.8 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Example based on Berni work on Raspberry Pi. +* Example contributed by Berni (@Berni8k) and reviewed by Ramon Santamaria (@raysan5) * -* Copyright (c) 2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2017 Berni (@Berni8k) and Ramon Santamaria (@raysan5) * ********************************************************************************************/ @@ -17,10 +17,7 @@ // Draw angle gauge controls void DrawAngleGauge(Texture2D angleGauge, int x, int y, float angle, char title[], Color color); -//---------------------------------------------------------------------------------- -// Main entry point -//---------------------------------------------------------------------------------- -int main() +int main(void) { // Initialization //-------------------------------------------------------------------------------------- @@ -37,10 +34,10 @@ int main() RenderTexture2D framebuffer = LoadRenderTexture(192, 192); // Model loading - Model model = LoadModel("resources/plane.obj"); // Load OBJ model - model.material.maps[MAP_DIFFUSE].texture = LoadTexture("resources/plane_diffuse.png"); // Set map diffuse texture + Model model = LoadModel("resources/plane.obj"); // Load OBJ model + model.materials[0].maps[MAP_DIFFUSE].texture = LoadTexture("resources/plane_diffuse.png"); // Set map diffuse texture - GenTextureMipmaps(&model.material.maps[MAP_DIFFUSE].texture); + GenTextureMipmaps(&model.materials[0].maps[MAP_DIFFUSE].texture); Camera camera = { 0 }; camera.position = (Vector3){ 0.0f, 60.0f, -120.0f };// Camera position perspective @@ -53,10 +50,10 @@ int main() float roll = 0.0f; float yaw = 0.0f; - SetTargetFPS(60); + 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 diff --git a/examples/models/resources/guy/guy.blend b/examples/models/resources/guy/guy.blend Binary files differnew file mode 100644 index 00000000..3880467d --- /dev/null +++ b/examples/models/resources/guy/guy.blend diff --git a/examples/models/resources/guy/guy.iqm b/examples/models/resources/guy/guy.iqm Binary files differnew file mode 100644 index 00000000..36bed5e0 --- /dev/null +++ b/examples/models/resources/guy/guy.iqm diff --git a/examples/models/resources/guy/guyanim.iqm b/examples/models/resources/guy/guyanim.iqm Binary files differnew file mode 100644 index 00000000..824a68a3 --- /dev/null +++ b/examples/models/resources/guy/guyanim.iqm diff --git a/examples/models/resources/guy/guytex.png b/examples/models/resources/guy/guytex.png Binary files differnew file mode 100644 index 00000000..7f813552 --- /dev/null +++ b/examples/models/resources/guy/guytex.png diff --git a/examples/models/resources/models/castle_diffuse.png b/examples/models/resources/models/castle_diffuse.png Binary files differindex b616e1dd..361144e9 100644 --- a/examples/models/resources/models/castle_diffuse.png +++ b/examples/models/resources/models/castle_diffuse.png diff --git a/examples/models/resources/models/cube.obj b/examples/models/resources/models/cube.obj index 0e9d6597..bf7e3bee 100644 --- a/examples/models/resources/models/cube.obj +++ b/examples/models/resources/models/cube.obj @@ -1,7 +1,7 @@ # reference material -mtllib myCube.mtl +#mtllib cube.mtl -# object Pau_Box +# object box # vertex (XZY) v 5.5 0 1.5 @@ -14,85 +14,55 @@ v 5.5 3 -1.5 v 8.5 3 -1.5 # normals (XYZ) -# red vn 0 -1 0 -#blue vn 0 1 0 -#top vn 0 0 1 -#yellow vn 1 0 0 -#bottom vn 0 0 -1 -#green vn -1 0 0 - # UVs (XY) -# yellow (1234) vt 0.5 0 0 vt 1 0 0 vt 1 0.5 0 vt 0.5 0.5 0 -# red (5678) vt 0.5 0.5 0 vt 1 0.5 0 vt 0.5 1 0 vt 1 1 0 -#bottom (9101112) vt 0 0.5 0 vt 1 0.5 0 vt 1 0 0 vt 0 0 0 -#top (13141516) vt 0 0.5 0 vt 1 0.5 0 vt 1 1 0 vt 0 1 0 -#green (17181920) vt 0.5 0 0 vt 0 0 0 vt 0 0.5 0 vt 0.5 0.5 0 -#blue (21222324) vt 0 0.5 0 vt 0.5 0.5 0 vt 0.5 1 0 vt 0 1 0 # merger -g Pau_Box +g box # reference material -usemtl Material_1 - -# bottom -f 1/9/1 3/10/1 4/11/1 -f 4/11/1 2/12/1 1/9/1 +#usemtl mat01 -# top +# faces +f 1/9/1 3/10/1 4/11/1 +f 4/11/1 2/12/1 1/9/1 f 5/13/2 6/14/2 8/15/2 f 8/15/2 7/16/2 5/13/2 - -# front-yellow f 1/17/6 2/18/6 6/19/6 f 6/19/6 5/20/6 1/17/6 - -# right-blue f 2/6/1 4/5/1 8/7/1 f 8/7/1 6/8/1 2/6/1 - -# back-green f 4/2/3 3/1/3 7/4/3 f 7/4/3 8/3/3 4/2/3 - -# left-red f 3/22/5 1/21/5 5/24/5 f 5/24/5 7/23/5 3/22/5 - - - - - - - diff --git a/examples/models/resources/pbr/trooper_albedo.png b/examples/models/resources/pbr/trooper_albedo.png Binary files differindex ac1422e4..9ba0f5a6 100644 --- a/examples/models/resources/pbr/trooper_albedo.png +++ b/examples/models/resources/pbr/trooper_albedo.png diff --git a/examples/models/resources/pbr/trooper_ao.png b/examples/models/resources/pbr/trooper_ao.png Binary files differindex 8567f7b4..442dd7fb 100644 --- a/examples/models/resources/pbr/trooper_ao.png +++ b/examples/models/resources/pbr/trooper_ao.png diff --git a/examples/models/resources/pbr/trooper_normals.png b/examples/models/resources/pbr/trooper_normals.png Binary files differindex 59c7bdc4..e04be883 100644 --- a/examples/models/resources/pbr/trooper_normals.png +++ b/examples/models/resources/pbr/trooper_normals.png diff --git a/examples/models/resources/pbr/trooper_roughness.png b/examples/models/resources/pbr/trooper_roughness.png Binary files differindex 53186d51..29f418f7 100644 --- a/examples/models/resources/pbr/trooper_roughness.png +++ b/examples/models/resources/pbr/trooper_roughness.png diff --git a/examples/models/resources/shaders/brdf.fs b/examples/models/resources/shaders/glsl100/brdf.fs index 3e8777d2..d04bc661 100644 --- a/examples/models/resources/shaders/brdf.fs +++ b/examples/models/resources/shaders/glsl100/brdf.fs @@ -10,13 +10,13 @@ #version 330 -#define MAX_SAMPLES 1024u // Input vertex attributes (from vertex shader) in vec2 fragTexCoord; // Constant values const float PI = 3.14159265359; +const uint MAX_SAMPLES = 1024u; // Output fragment color out vec4 finalColor; @@ -93,7 +93,7 @@ vec2 IntegrateBRDF(float NdotV, float roughness) vec3 V = vec3(sqrt(1.0 - NdotV*NdotV), 0.0, NdotV); vec3 N = vec3(0.0, 0.0, 1.0); - for (int i = 0; i < MAX_SAMPLES; i++) + for (uint i = 0u; i < MAX_SAMPLES; i++) { // Generate a sample vector that's biased towards the preferred alignment direction (importance sampling) diff --git a/examples/models/resources/shaders/brdf.vs b/examples/models/resources/shaders/glsl100/brdf.vs index 06384673..06384673 100644 --- a/examples/models/resources/shaders/brdf.vs +++ b/examples/models/resources/shaders/glsl100/brdf.vs diff --git a/examples/models/resources/shaders/cubemap.fs b/examples/models/resources/shaders/glsl100/cubemap.fs index e8e28536..e8e28536 100644 --- a/examples/models/resources/shaders/cubemap.fs +++ b/examples/models/resources/shaders/glsl100/cubemap.fs diff --git a/examples/models/resources/shaders/cubemap.vs b/examples/models/resources/shaders/glsl100/cubemap.vs index 5721eaa2..5721eaa2 100644 --- a/examples/models/resources/shaders/cubemap.vs +++ b/examples/models/resources/shaders/glsl100/cubemap.vs diff --git a/examples/models/resources/shaders/irradiance.fs b/examples/models/resources/shaders/glsl100/irradiance.fs index 87113673..b42d2143 100644 --- a/examples/models/resources/shaders/irradiance.fs +++ b/examples/models/resources/shaders/glsl100/irradiance.fs @@ -9,7 +9,7 @@ #version 330 // Input vertex attributes (from vertex shader) -in vec3 fragPos; +in vec3 fragPosition; // Input uniform values uniform samplerCube environmentMap; @@ -23,7 +23,7 @@ out vec4 finalColor; void main() { // The sample direction equals the hemisphere's orientation - vec3 normal = normalize(fragPos); + vec3 normal = normalize(fragPosition); vec3 irradiance = vec3(0.0); diff --git a/examples/models/resources/shaders/pbr.fs b/examples/models/resources/shaders/glsl100/pbr.fs index 38d56c5d..38d56c5d 100644 --- a/examples/models/resources/shaders/pbr.fs +++ b/examples/models/resources/shaders/glsl100/pbr.fs diff --git a/examples/models/resources/shaders/pbr.vs b/examples/models/resources/shaders/glsl100/pbr.vs index 8bd3faa1..8bd3faa1 100644 --- a/examples/models/resources/shaders/pbr.vs +++ b/examples/models/resources/shaders/glsl100/pbr.vs diff --git a/examples/models/resources/shaders/prefilter.fs b/examples/models/resources/shaders/glsl100/prefilter.fs index f5cf64be..9439810d 100644 --- a/examples/models/resources/shaders/prefilter.fs +++ b/examples/models/resources/shaders/glsl100/prefilter.fs @@ -11,7 +11,7 @@ #define CUBEMAP_RESOLUTION 1024.0 // Input vertex attributes (from vertex shader) -in vec3 fragPos; +in vec3 fragPosition; // Input uniform values uniform samplerCube environmentMap; @@ -79,7 +79,7 @@ vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) void main() { // Make the simplyfying assumption that V equals R equals the normal - vec3 N = normalize(fragPos); + vec3 N = normalize(fragPosition); vec3 R = N; vec3 V = R; diff --git a/examples/models/resources/shaders/skybox.fs b/examples/models/resources/shaders/glsl100/skybox.fs index 053a2517..053a2517 100644 --- a/examples/models/resources/shaders/skybox.fs +++ b/examples/models/resources/shaders/glsl100/skybox.fs diff --git a/examples/models/resources/shaders/skybox.vs b/examples/models/resources/shaders/glsl100/skybox.vs index dcbe6c3d..dcbe6c3d 100644 --- a/examples/models/resources/shaders/skybox.vs +++ b/examples/models/resources/shaders/glsl100/skybox.vs diff --git a/examples/models/resources/shaders/glsl330/brdf.fs b/examples/models/resources/shaders/glsl330/brdf.fs new file mode 100644 index 00000000..d04bc661 --- /dev/null +++ b/examples/models/resources/shaders/glsl330/brdf.fs @@ -0,0 +1,133 @@ +/******************************************************************************************* +* +* BRDF LUT Generation - Bidirectional reflectance distribution function fragment shader +* +* REF: https://github.com/HectorMF/BRDFGenerator +* +* Copyright (c) 2017 Victor Fisac +* +**********************************************************************************************/ + +#version 330 + + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; + +// Constant values +const float PI = 3.14159265359; +const uint MAX_SAMPLES = 1024u; + +// Output fragment color +out vec4 finalColor; + +vec2 Hammersley(uint i, uint N); +float RadicalInverseVdC(uint bits); +float GeometrySchlickGGX(float NdotV, float roughness); +float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness); +vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness); +vec2 IntegrateBRDF(float NdotV, float roughness); + +float RadicalInverseVdC(uint bits) +{ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +// Compute Hammersley coordinates +vec2 Hammersley(uint i, uint N) +{ + return vec2(float(i)/float(N), RadicalInverseVdC(i)); +} + +// Integrate number of importance samples for (roughness and NoV) +vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) +{ + float a = roughness*roughness; + float phi = 2.0 * PI * Xi.x; + float cosTheta = sqrt((1.0 - Xi.y)/(1.0 + (a*a - 1.0)*Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta*cosTheta); + + // Transform from spherical coordinates to cartesian coordinates (halfway vector) + vec3 H = vec3(cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta); + + // Transform from tangent space H vector to world space sample vector + vec3 up = ((abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0)); + vec3 tangent = normalize(cross(up, N)); + vec3 bitangent = cross(N, tangent); + vec3 sampleVec = tangent*H.x + bitangent*H.y + N*H.z; + + return normalize(sampleVec); +} + +float GeometrySchlickGGX(float NdotV, float roughness) +{ + // For IBL k is calculated different + float k = (roughness*roughness)/2.0; + + float nom = NdotV; + float denom = NdotV*(1.0 - k) + k; + + return nom/denom; +} + +// Compute the geometry term for the BRDF given roughness squared, NoV, NoL +float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) +{ + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, roughness); + float ggx1 = GeometrySchlickGGX(NdotL, roughness); + + return ggx1*ggx2; +} + +vec2 IntegrateBRDF(float NdotV, float roughness) +{ + float A = 0.0; + float B = 0.0; + vec3 V = vec3(sqrt(1.0 - NdotV*NdotV), 0.0, NdotV); + vec3 N = vec3(0.0, 0.0, 1.0); + + for (uint i = 0u; i < MAX_SAMPLES; i++) + { + // Generate a sample vector that's biased towards the preferred alignment direction (importance sampling) + + vec2 Xi = Hammersley(i, MAX_SAMPLES); // Compute a Hammersely coordinate + vec3 H = ImportanceSampleGGX(Xi, N, roughness); // Integrate number of importance samples for (roughness and NoV) + vec3 L = normalize(2.0*dot(V, H)*H - V); // Compute reflection vector L + + float NdotL = max(L.z, 0.0); // Compute normal dot light + float NdotH = max(H.z, 0.0); // Compute normal dot half + float VdotH = max(dot(V, H), 0.0); // Compute view dot half + + if (NdotL > 0.0) + { + float G = GeometrySmith(N, V, L, roughness); // Compute the geometry term for the BRDF given roughness squared, NoV, NoL + float GVis = (G*VdotH)/(NdotH*NdotV); // Compute the visibility term given G, VoH, NoH, NoV, NoL + float Fc = pow(1.0 - VdotH, 5.0); // Compute the fresnel term given VoH + + A += (1.0 - Fc)*GVis; // Sum the result given fresnel, geometry, visibility + B += Fc*GVis; + } + } + + // Calculate brdf average sample + A /= float(MAX_SAMPLES); + B /= float(MAX_SAMPLES); + + return vec2(A, B); +} + +void main() +{ + // Calculate brdf based on texture coordinates + vec2 brdf = IntegrateBRDF(fragTexCoord.x, fragTexCoord.y); + + // Calculate final fragment color + finalColor = vec4(brdf.r, brdf.g, 0.0, 1.0); +} diff --git a/examples/models/resources/shaders/glsl330/brdf.vs b/examples/models/resources/shaders/glsl330/brdf.vs new file mode 100644 index 00000000..06384673 --- /dev/null +++ b/examples/models/resources/shaders/glsl330/brdf.vs @@ -0,0 +1,25 @@ +/******************************************************************************************* +* +* rPBR [shader] - Bidirectional reflectance distribution function vertex shader +* +* Copyright (c) 2017 Victor Fisac +* +**********************************************************************************************/ + +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; +in vec2 vertexTexCoord; + +// Output vertex attributes (to fragment shader) +out vec2 fragTexCoord; + +void main() +{ + // Calculate fragment position based on model transformations + fragTexCoord = vertexTexCoord; + + // Calculate final vertex position + gl_Position = vec4(vertexPosition, 1.0); +}
\ No newline at end of file diff --git a/examples/models/resources/shaders/glsl330/cubemap.fs b/examples/models/resources/shaders/glsl330/cubemap.fs new file mode 100644 index 00000000..e8e28536 --- /dev/null +++ b/examples/models/resources/shaders/glsl330/cubemap.fs @@ -0,0 +1,38 @@ +/******************************************************************************************* +* +* rPBR [shader] - Equirectangular to cubemap fragment shader +* +* Copyright (c) 2017 Victor Fisac +* +**********************************************************************************************/ + +#version 330 + +// Input vertex attributes (from vertex shader) +in vec3 fragPosition; + +// Input uniform values +uniform sampler2D equirectangularMap; + +// Output fragment color +out vec4 finalColor; + +vec2 SampleSphericalMap(vec3 v) +{ + vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); + uv *= vec2(0.1591, 0.3183); + uv += 0.5; + return uv; +} + +void main() +{ + // Normalize local position + vec2 uv = SampleSphericalMap(normalize(fragPosition)); + + // Fetch color from texture map + vec3 color = texture(equirectangularMap, uv).rgb; + + // Calculate final fragment color + finalColor = vec4(color, 1.0); +} diff --git a/examples/models/resources/shaders/glsl330/cubemap.vs b/examples/models/resources/shaders/glsl330/cubemap.vs new file mode 100644 index 00000000..5721eaa2 --- /dev/null +++ b/examples/models/resources/shaders/glsl330/cubemap.vs @@ -0,0 +1,28 @@ +/******************************************************************************************* +* +* rPBR [shader] - Equirectangular to cubemap vertex shader +* +* Copyright (c) 2017 Victor Fisac +* +**********************************************************************************************/ + +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; + +// Input uniform values +uniform mat4 projection; +uniform mat4 view; + +// Output vertex attributes (to fragment shader) +out vec3 fragPosition; + +void main() +{ + // Calculate fragment position based on model transformations + fragPosition = vertexPosition; + + // Calculate final vertex position + gl_Position = projection*view*vec4(vertexPosition, 1.0); +} diff --git a/examples/models/resources/shaders/glsl330/irradiance.fs b/examples/models/resources/shaders/glsl330/irradiance.fs new file mode 100644 index 00000000..b42d2143 --- /dev/null +++ b/examples/models/resources/shaders/glsl330/irradiance.fs @@ -0,0 +1,58 @@ +/******************************************************************************************* +* +* rPBR [shader] - Irradiance cubemap fragment shader +* +* Copyright (c) 2017 Victor Fisac +* +**********************************************************************************************/ + +#version 330 + +// Input vertex attributes (from vertex shader) +in vec3 fragPosition; + +// Input uniform values +uniform samplerCube environmentMap; + +// Constant values +const float PI = 3.14159265359f; + +// Output fragment color +out vec4 finalColor; + +void main() +{ + // The sample direction equals the hemisphere's orientation + vec3 normal = normalize(fragPosition); + + vec3 irradiance = vec3(0.0); + + vec3 up = vec3(0.0, 1.0, 0.0); + vec3 right = cross(up, normal); + up = cross(normal, right); + + float sampleDelta = 0.025f; + float nrSamples = 0.0f; + + for (float phi = 0.0; phi < 2.0*PI; phi += sampleDelta) + { + for (float theta = 0.0; theta < 0.5*PI; theta += sampleDelta) + { + // Spherical to cartesian (in tangent space) + vec3 tangentSample = vec3(sin(theta)*cos(phi), sin(theta)*sin(phi), cos(theta)); + + // tangent space to world + vec3 sampleVec = tangentSample.x*right + tangentSample.y*up + tangentSample.z*normal; + + // Fetch color from environment cubemap + irradiance += texture(environmentMap, sampleVec).rgb*cos(theta)*sin(theta); + nrSamples++; + } + } + + // Calculate irradiance average value from samples + irradiance = PI*irradiance*(1.0/float(nrSamples)); + + // Calculate final fragment color + finalColor = vec4(irradiance, 1.0); +} diff --git a/examples/models/resources/shaders/glsl330/pbr.fs b/examples/models/resources/shaders/glsl330/pbr.fs new file mode 100644 index 00000000..38d56c5d --- /dev/null +++ b/examples/models/resources/shaders/glsl330/pbr.fs @@ -0,0 +1,298 @@ +/******************************************************************************************* +* +* rPBR [shader] - Physically based rendering fragment shader +* +* Copyright (c) 2017 Victor Fisac +* +**********************************************************************************************/ + +#version 330 + +#define MAX_REFLECTION_LOD 4.0 +#define MAX_DEPTH_LAYER 20 +#define MIN_DEPTH_LAYER 10 + +#define MAX_LIGHTS 4 +#define LIGHT_DIRECTIONAL 0 +#define LIGHT_POINT 1 + +struct MaterialProperty { + vec3 color; + int useSampler; + sampler2D sampler; +}; + +struct Light { + int enabled; + int type; + vec3 position; + vec3 target; + vec4 color; +}; + +// Input vertex attributes (from vertex shader) +in vec3 fragPosition; +in vec2 fragTexCoord; +in vec3 fragNormal; +in vec3 fragTangent; +in vec3 fragBinormal; + +// Input material values +uniform MaterialProperty albedo; +uniform MaterialProperty normals; +uniform MaterialProperty metalness; +uniform MaterialProperty roughness; +uniform MaterialProperty occlusion; +uniform MaterialProperty emission; +uniform MaterialProperty height; + +// Input uniform values +uniform samplerCube irradianceMap; +uniform samplerCube prefilterMap; +uniform sampler2D brdfLUT; + +// Input lighting values +uniform Light lights[MAX_LIGHTS]; + +// Other uniform values +uniform int renderMode; +uniform vec3 viewPos; +vec2 texCoord; + +// Constant values +const float PI = 3.14159265359; + +// Output fragment color +out vec4 finalColor; + +vec3 ComputeMaterialProperty(MaterialProperty property); +float DistributionGGX(vec3 N, vec3 H, float roughness); +float GeometrySchlickGGX(float NdotV, float roughness); +float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness); +vec3 fresnelSchlick(float cosTheta, vec3 F0); +vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness); +vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir); + +vec3 ComputeMaterialProperty(MaterialProperty property) +{ + vec3 result = vec3(0.0, 0.0, 0.0); + + if (property.useSampler == 1) result = texture(property.sampler, texCoord).rgb; + else result = property.color; + + return result; +} + +float DistributionGGX(vec3 N, vec3 H, float roughness) +{ + float a = roughness*roughness; + float a2 = a*a; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH*NdotH; + + float nom = a2; + float denom = (NdotH2*(a2 - 1.0) + 1.0); + denom = PI*denom*denom; + + return nom/denom; +} + +float GeometrySchlickGGX(float NdotV, float roughness) +{ + float r = (roughness + 1.0); + float k = r*r/8.0; + + float nom = NdotV; + float denom = NdotV*(1.0 - k) + k; + + return nom/denom; +} +float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) +{ + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, roughness); + float ggx1 = GeometrySchlickGGX(NdotL, roughness); + + return ggx1*ggx2; +} + +vec3 fresnelSchlick(float cosTheta, vec3 F0) +{ + return F0 + (1.0 - F0)*pow(1.0 - cosTheta, 5.0); +} + +vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) +{ + return F0 + (max(vec3(1.0 - roughness), F0) - F0)*pow(1.0 - cosTheta, 5.0); +} + +vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir) +{ + // Calculate the number of depth layers and calculate the size of each layer + float numLayers = mix(MAX_DEPTH_LAYER, MIN_DEPTH_LAYER, abs(dot(vec3(0.0, 0.0, 1.0), viewDir))); + float layerDepth = 1.0/numLayers; + + // Calculate depth of current layer + float currentLayerDepth = 0.0; + + // Calculate the amount to shift the texture coordinates per layer (from vector P) + // Note: height amount is stored in height material attribute color R channel (sampler use is independent) + vec2 P = viewDir.xy*height.color.r; + vec2 deltaTexCoords = P/numLayers; + + // Store initial texture coordinates and depth values + vec2 currentTexCoords = texCoords; + float currentDepthMapValue = texture(height.sampler, currentTexCoords).r; + + while (currentLayerDepth < currentDepthMapValue) + { + // Shift texture coordinates along direction of P + currentTexCoords -= deltaTexCoords; + + // Get depth map value at current texture coordinates + currentDepthMapValue = texture(height.sampler, currentTexCoords).r; + + // Get depth of next layer + currentLayerDepth += layerDepth; + } + + // Get texture coordinates before collision (reverse operations) + vec2 prevTexCoords = currentTexCoords + deltaTexCoords; + + // Get depth after and before collision for linear interpolation + float afterDepth = currentDepthMapValue - currentLayerDepth; + float beforeDepth = texture(height.sampler, prevTexCoords).r - currentLayerDepth + layerDepth; + + // Interpolation of texture coordinates + float weight = afterDepth/(afterDepth - beforeDepth); + vec2 finalTexCoords = prevTexCoords*weight + currentTexCoords*(1.0 - weight); + + return finalTexCoords; +} + +void main() +{ + // Calculate TBN and RM matrices + mat3 TBN = transpose(mat3(fragTangent, fragBinormal, fragNormal)); + + // Calculate lighting required attributes + vec3 normal = normalize(fragNormal); + vec3 view = normalize(viewPos - fragPosition); + vec3 refl = reflect(-view, normal); + + // Check if parallax mapping is enabled and calculate texture coordinates to use based on height map + // NOTE: remember that 'texCoord' variable must be assigned before calling any ComputeMaterialProperty() function + if (height.useSampler == 1) texCoord = ParallaxMapping(fragTexCoord, view); + else texCoord = fragTexCoord; // Use default texture coordinates + + // Fetch material values from texture sampler or color attributes + vec3 color = ComputeMaterialProperty(albedo); + vec3 metal = ComputeMaterialProperty(metalness); + vec3 rough = ComputeMaterialProperty(roughness); + vec3 emiss = ComputeMaterialProperty(emission); + vec3 ao = ComputeMaterialProperty(occlusion); + + // Check if normal mapping is enabled + if (normals.useSampler == 1) + { + // Fetch normal map color and transform lighting values to tangent space + normal = ComputeMaterialProperty(normals); + normal = normalize(normal*2.0 - 1.0); + normal = normalize(normal*TBN); + + // Convert tangent space normal to world space due to cubemap reflection calculations + refl = normalize(reflect(-view, normal)); + } + + // Calculate reflectance at normal incidence + vec3 F0 = vec3(0.04); + F0 = mix(F0, color, metal.r); + + // Calculate lighting for all lights + vec3 Lo = vec3(0.0); + vec3 lightDot = vec3(0.0); + + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (lights[i].enabled == 1) + { + // Calculate per-light radiance + vec3 light = vec3(0.0); + vec3 radiance = lights[i].color.rgb; + if (lights[i].type == LIGHT_DIRECTIONAL) light = -normalize(lights[i].target - lights[i].position); + else if (lights[i].type == LIGHT_POINT) + { + light = normalize(lights[i].position - fragPosition); + float distance = length(lights[i].position - fragPosition); + float attenuation = 1.0/(distance*distance); + radiance *= attenuation; + } + + // Cook-torrance BRDF + vec3 high = normalize(view + light); + float NDF = DistributionGGX(normal, high, rough.r); + float G = GeometrySmith(normal, view, light, rough.r); + vec3 F = fresnelSchlick(max(dot(high, view), 0.0), F0); + vec3 nominator = NDF*G*F; + float denominator = 4*max(dot(normal, view), 0.0)*max(dot(normal, light), 0.0) + 0.001; + vec3 brdf = nominator/denominator; + + // Store to kS the fresnel value and calculate energy conservation + vec3 kS = F; + vec3 kD = vec3(1.0) - kS; + + // Multiply kD by the inverse metalness such that only non-metals have diffuse lighting + kD *= 1.0 - metal.r; + + // Scale light by dot product between normal and light direction + float NdotL = max(dot(normal, light), 0.0); + + // Add to outgoing radiance Lo + // Note: BRDF is already multiplied by the Fresnel so it doesn't need to be multiplied again + Lo += (kD*color/PI + brdf)*radiance*NdotL*lights[i].color.a; + lightDot += radiance*NdotL + brdf*lights[i].color.a; + } + } + + // Calculate ambient lighting using IBL + vec3 F = fresnelSchlickRoughness(max(dot(normal, view), 0.0), F0, rough.r); + vec3 kS = F; + vec3 kD = 1.0 - kS; + kD *= 1.0 - metal.r; + + // Calculate indirect diffuse + vec3 irradiance = texture(irradianceMap, fragNormal).rgb; + vec3 diffuse = color*irradiance; + + // Sample both the prefilter map and the BRDF lut and combine them together as per the Split-Sum approximation + vec3 prefilterColor = textureLod(prefilterMap, refl, rough.r*MAX_REFLECTION_LOD).rgb; + vec2 brdf = texture(brdfLUT, vec2(max(dot(normal, view), 0.0), rough.r)).rg; + vec3 reflection = prefilterColor*(F*brdf.x + brdf.y); + + // Calculate final lighting + vec3 ambient = (kD*diffuse + reflection)*ao; + + // Calculate fragment color based on render mode + vec3 fragmentColor = ambient + Lo + emiss; // Physically Based Rendering + + if (renderMode == 1) fragmentColor = color; // Albedo + else if (renderMode == 2) fragmentColor = normal; // Normals + else if (renderMode == 3) fragmentColor = metal; // Metalness + else if (renderMode == 4) fragmentColor = rough; // Roughness + else if (renderMode == 5) fragmentColor = ao; // Ambient Occlusion + else if (renderMode == 6) fragmentColor = emiss; // Emission + else if (renderMode == 7) fragmentColor = lightDot; // Lighting + else if (renderMode == 8) fragmentColor = kS; // Fresnel + else if (renderMode == 9) fragmentColor = irradiance; // Irradiance + else if (renderMode == 10) fragmentColor = reflection; // Reflection + + // Apply HDR tonemapping + fragmentColor = fragmentColor/(fragmentColor + vec3(1.0)); + + // Apply gamma correction + fragmentColor = pow(fragmentColor, vec3(1.0/2.2)); + + // Calculate final fragment color + finalColor = vec4(fragmentColor, 1.0); +} diff --git a/examples/models/resources/shaders/glsl330/pbr.vs b/examples/models/resources/shaders/glsl330/pbr.vs new file mode 100644 index 00000000..8bd3faa1 --- /dev/null +++ b/examples/models/resources/shaders/glsl330/pbr.vs @@ -0,0 +1,49 @@ +/******************************************************************************************* +* +* rPBR [shader] - Physically based rendering vertex shader +* +* Copyright (c) 2017 Victor Fisac +* +**********************************************************************************************/ + +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec3 vertexNormal; +in vec4 vertexTangent; + +// Input uniform values +uniform mat4 mvp; +uniform mat4 matModel; + +// Output vertex attributes (to fragment shader) +out vec3 fragPosition; +out vec2 fragTexCoord; +out vec3 fragNormal; +out vec3 fragTangent; +out vec3 fragBinormal; + +void main() +{ + // Calculate binormal from vertex normal and tangent + vec3 vertexBinormal = cross(vertexNormal, vec3(vertexTangent)); + + // Calculate fragment normal based on normal transformations + mat3 normalMatrix = transpose(inverse(mat3(matModel))); + + // Calculate fragment position based on model transformations + fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f)); + + // Send vertex attributes to fragment shader + fragTexCoord = vertexTexCoord; + fragNormal = normalize(normalMatrix*vertexNormal); + fragTangent = normalize(normalMatrix*vec3(vertexTangent)); + fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal); + fragBinormal = normalize(normalMatrix*vertexBinormal); + fragBinormal = cross(fragNormal, fragTangent); + + // Calculate final vertex position + gl_Position = mvp*vec4(vertexPosition, 1.0); +}
\ No newline at end of file diff --git a/examples/models/resources/shaders/glsl330/prefilter.fs b/examples/models/resources/shaders/glsl330/prefilter.fs new file mode 100644 index 00000000..9439810d --- /dev/null +++ b/examples/models/resources/shaders/glsl330/prefilter.fs @@ -0,0 +1,120 @@ +/******************************************************************************************* +* +* rPBR [shader] - Prefiltered environment for reflections fragment shader +* +* Copyright (c) 2017 Victor Fisac +* +**********************************************************************************************/ + +#version 330 +#define MAX_SAMPLES 1024u +#define CUBEMAP_RESOLUTION 1024.0 + +// Input vertex attributes (from vertex shader) +in vec3 fragPosition; + +// Input uniform values +uniform samplerCube environmentMap; +uniform float roughness; + +// Constant values +const float PI = 3.14159265359f; + +// Output fragment color +out vec4 finalColor; + +float DistributionGGX(vec3 N, vec3 H, float roughness); +float RadicalInverse_VdC(uint bits); +vec2 Hammersley(uint i, uint N); +vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness); + +float DistributionGGX(vec3 N, vec3 H, float roughness) +{ + float a = roughness*roughness; + float a2 = a*a; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH*NdotH; + + float nom = a2; + float denom = (NdotH2*(a2 - 1.0) + 1.0); + denom = PI*denom*denom; + + return nom/denom; +} + +float RadicalInverse_VdC(uint bits) +{ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +vec2 Hammersley(uint i, uint N) +{ + return vec2(float(i)/float(N), RadicalInverse_VdC(i)); +} + +vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) +{ + float a = roughness*roughness; + float phi = 2.0 * PI * Xi.x; + float cosTheta = sqrt((1.0 - Xi.y)/(1.0 + (a*a - 1.0)*Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta*cosTheta); + + // Transform from spherical coordinates to cartesian coordinates (halfway vector) + vec3 H = vec3(cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta); + + // Transform from tangent space H vector to world space sample vector + vec3 up = ((abs(N.z) < 0.999) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0)); + vec3 tangent = normalize(cross(up, N)); + vec3 bitangent = cross(N, tangent); + vec3 sampleVec = tangent*H.x + bitangent*H.y + N*H.z; + + return normalize(sampleVec); +} + +void main() +{ + // Make the simplyfying assumption that V equals R equals the normal + vec3 N = normalize(fragPosition); + vec3 R = N; + vec3 V = R; + + vec3 prefilteredColor = vec3(0.0); + float totalWeight = 0.0; + + for (uint i = 0u; i < MAX_SAMPLES; i++) + { + // Generate a sample vector that's biased towards the preferred alignment direction (importance sampling) + vec2 Xi = Hammersley(i, MAX_SAMPLES); + vec3 H = ImportanceSampleGGX(Xi, N, roughness); + vec3 L = normalize(2.0*dot(V, H)*H - V); + + float NdotL = max(dot(N, L), 0.0); + if(NdotL > 0.0) + { + // Sample from the environment's mip level based on roughness/pdf + float D = DistributionGGX(N, H, roughness); + float NdotH = max(dot(N, H), 0.0); + float HdotV = max(dot(H, V), 0.0); + float pdf = D*NdotH/(4.0*HdotV) + 0.0001; + + float resolution = CUBEMAP_RESOLUTION; + float saTexel = 4.0*PI/(6.0*resolution*resolution); + float saSample = 1.0/(float(MAX_SAMPLES)*pdf + 0.0001); + float mipLevel = ((roughness == 0.0) ? 0.0 : 0.5*log2(saSample/saTexel)); + + prefilteredColor += textureLod(environmentMap, L, mipLevel).rgb*NdotL; + totalWeight += NdotL; + } + } + + // Calculate prefilter average color + prefilteredColor = prefilteredColor/totalWeight; + + // Calculate final fragment color + finalColor = vec4(prefilteredColor, 1.0); +} diff --git a/examples/models/resources/shaders/glsl330/skybox.fs b/examples/models/resources/shaders/glsl330/skybox.fs new file mode 100644 index 00000000..053a2517 --- /dev/null +++ b/examples/models/resources/shaders/glsl330/skybox.fs @@ -0,0 +1,31 @@ +/******************************************************************************************* +* +* rPBR [shader] - Background skybox fragment shader +* +* Copyright (c) 2017 Victor Fisac +* +**********************************************************************************************/ + +#version 330 + +// Input vertex attributes (from vertex shader) +in vec3 fragPosition; + +// Input uniform values +uniform samplerCube environmentMap; + +// Output fragment color +out vec4 finalColor; + +void main() +{ + // Fetch color from texture map + vec3 color = texture(environmentMap, fragPosition).rgb; + + // Apply gamma correction + color = color/(color + vec3(1.0)); + color = pow(color, vec3(1.0/2.2)); + + // Calculate final fragment color + finalColor = vec4(color, 1.0); +} diff --git a/examples/models/resources/shaders/glsl330/skybox.vs b/examples/models/resources/shaders/glsl330/skybox.vs new file mode 100644 index 00000000..4fe9a2c3 --- /dev/null +++ b/examples/models/resources/shaders/glsl330/skybox.vs @@ -0,0 +1,32 @@ +/******************************************************************************************* +* +* rPBR [shader] - Background skybox vertex shader +* +* Copyright (c) 2017 Victor Fisac +* +**********************************************************************************************/ + +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; + +// Input uniform values +uniform mat4 projection; +uniform mat4 view; + +// Output vertex attributes (to fragment shader) +out vec3 fragPosition; + +void main() +{ + // Calculate fragment position based on model transformations + fragPosition = vertexPosition; + + // Remove translation from the view matrix + mat4 rotView = mat4(mat3(view)); + vec4 clipPos = projection*rotView*vec4(vertexPosition, 1.0); + + // Calculate final vertex position + gl_Position = clipPos.xyzw; +} |
