You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
8.0 KiB

пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
пре 10 месеци
  1. /*******************************************************************************************
  2. *
  3. * raylib [core] example - Using bones as socket for calculating the positioning of something
  4. *
  5. * Example originally created with raylib 4.5, last time updated with raylib 4.5
  6. *
  7. * Example contributed by iP (@ipzaur) and reviewed by Ramon Santamaria (@raysan5)
  8. *
  9. * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  10. * BSD-like license that allows static linking with closed source software
  11. *
  12. * Copyright (c) 2024 iP (@ipzaur)
  13. *
  14. ********************************************************************************************/
  15. #include "raylib.h"
  16. #include "raymath.h"
  17. #define BONE_SOCKETS 3
  18. #define BONE_SOCKET_HAT 0
  19. #define BONE_SOCKET_HAND_R 1
  20. #define BONE_SOCKET_HAND_L 2
  21. //------------------------------------------------------------------------------------
  22. // Program main entry point
  23. //------------------------------------------------------------------------------------
  24. int main(void)
  25. {
  26. // Initialization
  27. //--------------------------------------------------------------------------------------
  28. const int screenWidth = 800;
  29. const int screenHeight = 450;
  30. InitWindow(screenWidth, screenHeight, "raylib [models] example - bone socket");
  31. // Define the camera to look into our 3d world
  32. Camera camera = { 0 };
  33. camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position
  34. camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; // Camera looking at point
  35. camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
  36. camera.fovy = 45.0f; // Camera field-of-view Y
  37. camera.projection = CAMERA_PERSPECTIVE; // Camera projection type
  38. // Load gltf model
  39. Model characterModel = LoadModel("resources/models/gltf/greenman.glb"); // Load character model
  40. Model equipModel[BONE_SOCKETS] = {
  41. LoadModel("resources/models/gltf/greenman_hat.glb"), // Index for the hat model is the same as BONE_SOCKET_HAT
  42. LoadModel("resources/models/gltf/greenman_sword.glb"), // Index for the sword model is the same as BONE_SOCKET_HAND_R
  43. LoadModel("resources/models/gltf/greenman_shield.glb") // Index for the shield model is the same as BONE_SOCKET_HAND_L
  44. };
  45. bool showEquip[3] = { true, true, true }; // Toggle on/off equip
  46. // Load gltf model animations
  47. int animsCount = 0;
  48. unsigned int animIndex = 0;
  49. unsigned int animCurrentFrame = 0;
  50. ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/greenman.glb", &animsCount);
  51. // indices of bones for sockets
  52. int boneSocketIndex[BONE_SOCKETS] = { -1, -1, -1 };
  53. // search bones for sockets
  54. for (int i = 0; i < characterModel.boneCount; i++)
  55. {
  56. if (TextIsEqual(characterModel.bones[i].name, "socket_hat"))
  57. {
  58. boneSocketIndex[BONE_SOCKET_HAT] = i;
  59. continue;
  60. }
  61. if (TextIsEqual(characterModel.bones[i].name, "socket_hand_R"))
  62. {
  63. boneSocketIndex[BONE_SOCKET_HAND_R] = i;
  64. continue;
  65. }
  66. if (TextIsEqual(characterModel.bones[i].name, "socket_hand_L"))
  67. {
  68. boneSocketIndex[BONE_SOCKET_HAND_L] = i;
  69. continue;
  70. }
  71. }
  72. Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
  73. unsigned short angle = 0; // Set angle for rotate character
  74. DisableCursor(); // Limit cursor to relative movement inside the window
  75. SetTargetFPS(60); // Set our game to run at 60 frames-per-second
  76. //--------------------------------------------------------------------------------------
  77. // Main game loop
  78. while (!WindowShouldClose()) // Detect window close button or ESC key
  79. {
  80. // Update
  81. //----------------------------------------------------------------------------------
  82. UpdateCamera(&camera, CAMERA_THIRD_PERSON);
  83. // Rotate character
  84. if (IsKeyDown(KEY_F)) angle = (angle + 1)%360;
  85. else if (IsKeyDown(KEY_H)) angle = (360 + angle - 1)%360;
  86. // Select current animation
  87. if (IsKeyPressed(KEY_T)) animIndex = (animIndex + 1)%animsCount;
  88. else if (IsKeyPressed(KEY_G)) animIndex = (animIndex + animsCount - 1)%animsCount;
  89. // Toggle shown of equip
  90. if (IsKeyPressed(KEY_ONE)) showEquip[BONE_SOCKET_HAT] = !showEquip[BONE_SOCKET_HAT];
  91. if (IsKeyPressed(KEY_TWO)) showEquip[BONE_SOCKET_HAND_R] = !showEquip[BONE_SOCKET_HAND_R];
  92. if (IsKeyPressed(KEY_THREE)) showEquip[BONE_SOCKET_HAND_L] = !showEquip[BONE_SOCKET_HAND_L];
  93. // Update model animation
  94. ModelAnimation anim = modelAnimations[animIndex];
  95. animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount;
  96. UpdateModelAnimation(characterModel, anim, animCurrentFrame);
  97. //----------------------------------------------------------------------------------
  98. // Draw
  99. //----------------------------------------------------------------------------------
  100. BeginDrawing();
  101. ClearBackground(RAYWHITE);
  102. BeginMode3D(camera);
  103. // Draw character
  104. Quaternion characterRotate = QuaternionFromAxisAngle((Vector3){ 0.0f, 1.0f, 0.0f }, angle*DEG2RAD);
  105. characterModel.transform = MatrixMultiply(QuaternionToMatrix(characterRotate), MatrixTranslate(position.x, position.y, position.z));
  106. UpdateModelAnimation(characterModel, anim, animCurrentFrame);
  107. DrawMesh(characterModel.meshes[0], characterModel.materials[1], characterModel.transform);
  108. // Draw equipments (hat, sword, shield)
  109. for (int i = 0; i < BONE_SOCKETS; i++)
  110. {
  111. if (!showEquip[i]) continue;
  112. Transform *transform = &anim.framePoses[animCurrentFrame][boneSocketIndex[i]];
  113. Quaternion inRotation = characterModel.bindPose[boneSocketIndex[i]].rotation;
  114. Quaternion outRotation = transform->rotation;
  115. // Calculate socket rotation (angle between bone in initial pose and same bone in current animation frame)
  116. Quaternion rotate = QuaternionMultiply(outRotation, QuaternionInvert(inRotation));
  117. Matrix matrixTransform = QuaternionToMatrix(rotate);
  118. // Translate socket to its position in the current animation
  119. matrixTransform = MatrixMultiply(matrixTransform, MatrixTranslate(transform->translation.x, transform->translation.y, transform->translation.z));
  120. // Transform the socket using the transform of the character (angle and translate)
  121. matrixTransform = MatrixMultiply(matrixTransform, characterModel.transform);
  122. // Draw mesh at socket position with socket angle rotation
  123. DrawMesh(equipModel[i].meshes[0], equipModel[i].materials[1], matrixTransform);
  124. }
  125. DrawGrid(10, 1.0f);
  126. EndMode3D();
  127. DrawText("Use the T/G to switch animation", 10, 10, 20, GRAY);
  128. DrawText("Use the F/H to rotate character left/right", 10, 35, 20, GRAY);
  129. DrawText("Use the 1,2,3 to toggle shown of hat, sword and shield", 10, 60, 20, GRAY);
  130. EndDrawing();
  131. //----------------------------------------------------------------------------------
  132. }
  133. // De-Initialization
  134. //--------------------------------------------------------------------------------------
  135. UnloadModelAnimations(modelAnimations, animsCount);
  136. UnloadModel(characterModel); // Unload character model and meshes/material
  137. // Unload equipment model and meshes/material
  138. for (int i = 0; i < BONE_SOCKETS; i++) UnloadModel(equipModel[i]);
  139. CloseWindow(); // Close window and OpenGL context
  140. //--------------------------------------------------------------------------------------
  141. return 0;
  142. }