GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
phantomx_mk2_renderer_model.cpp
[詳解]
1
3
4// Copyright(c) 2023-2025 Design Engineering Laboratory, Saitama University
5// Released under the MIT license
6// https://opensource.org/licenses/mit-license.php
7
9
10#include <DxLib.h>
11
12#include "math_util.h"
13#include "math_rot_converter.h"
15#include "dxlib_util.h"
16#include "model_loader.h"
17#include "phantomx_mk2_const.h"
18
19
20namespace designlab
21{
22
24 const std::shared_ptr<const IHexapodCoordinateConverter>& converter_ptr,
25 const std::shared_ptr<const IHexapodJointCalculator>& calculator_ptr) :
26 converter_ptr_(converter_ptr),
27 calculator_ptr_(calculator_ptr),
28 draw_node_{}
29{
30}
31
33{
34 draw_node_ = node;
35
36 if (calculator_ptr_ == nullptr) { return; }
37
38 draw_joint_state_ = calculator_ptr_->CalculateAllJointState(node);
39}
40
42{
43 dxlib_util::SetZBufferEnable(); // Zバッファを有効にする.
44
45 DrawBody(); // ボディの描画.
46
47 for (int i = 0; i < HexapodConst::kLegNum; i++)
48 {
49 DrawCoxaLink(i); // 脚の描画.
50
51 DrawFemurLink(i); // 脚の描画.
52
53 DrawTibiaLink(i); // 脚の描画.
54
55 DrawJointAxis(i); // 関節軸の描画.
56 }
57}
58
59void PhantomXMkIIRendererModel::DrawBody() const
60{
61 const int body_model_handle = ModelLoader::GetIns()->GetModelHandle("model/body.mv1");
62
63 // モデルの読み込みがされていなければ描画しない(というかできない)
64 if (body_model_handle == -1)
65 {
66 printfDx("モデルの読み込みに失敗しました.(body_model_handle)");
67 }
68
69 const VECTOR scale = VGet(10.f, 10.f, 10.f); // モデルの寸法を調整するためのスケール.
70
71
72 MV1SetScale(body_model_handle, scale);
73
74 // dxlib の座標系は左手座標系なので,右手座標系に変換するために逆転させる.
75 MV1SetRotationMatrix(body_model_handle,
77
78 MV1SetPosition(body_model_handle, dxlib_util::ConvertToDxlibVec(draw_node_.center_of_mass_global_coord));
79
80 MV1DrawModel(body_model_handle);
81
82 // 胴体の正面に目印のために球を描画する.
83 const VECTOR sphere_pos = dxlib_util::ConvertToDxlibVec(RotateVector3({ PhantomXMkIIConst::kCoxaBaseOffsetX - 20.f, 0.f, 0.f }, draw_node_.posture) + draw_node_.center_of_mass_global_coord);
84 const float sphere_radius = 30.f;
85 const int sphere_div_num = 16;
86 const unsigned int sphere_color = GetColor(255, 0, 0);
87 const unsigned int spec_color = GetColor(255, 255, 255);
88
89 DrawSphere3D(sphere_pos, sphere_radius, sphere_div_num, sphere_color, spec_color, TRUE);
90}
91
92void PhantomXMkIIRendererModel::DrawCoxaLink(const int leg_index) const
93{
94 const int coxa_model_handle = ModelLoader::GetIns()->GetModelHandle("model/coxa_fixed.mv1");
95
96 if (coxa_model_handle == -1)
97 {
98 printfDx("モデルの読み込みに失敗しました.(coxa_model_handle)");
99 }
100
101 if (draw_joint_state_[leg_index].joint_pos_leg_coordinate.size() != 4)
102 {
103 return;
104 }
105 if (draw_joint_state_[leg_index].joint_angle.size() != 3)
106 {
107 return;
108 }
109
110 // Coxa Joint は2つの Connect Link で構成されているので,それぞれ描画する.
111 const VECTOR scale = VGet(10.f, 10.f, 10.f);
112
113 const VECTOR coxa_joint_pos_global = dxlib_util::ConvertToDxlibVec(
114 converter_ptr_->ConvertLegToGlobalCoordinate(
115 draw_joint_state_[leg_index].joint_pos_leg_coordinate[0], leg_index, draw_node_.center_of_mass_global_coord, draw_node_.posture, true));
116
117 const Quaternion coxa_quat = Quaternion::MakeByAngleAxis(math_util::ConvertDegToRad(-90.0f), Vector3::GetLeftVec()) *
118 Quaternion::MakeByAngleAxis(draw_joint_state_[leg_index].joint_angle[0], Vector3::GetUpVec()) *
119 draw_node_.posture.ToLeftHandCoordinate();
120
121 MV1SetScale(coxa_model_handle, scale);
122
123 // dxlib の座標系は左手座標系なので,右手座標系に変換するために逆転させる.
124 MV1SetRotationMatrix(coxa_model_handle, dxlib_util::ConvertToDxlibMat(ToRotationMatrix(coxa_quat)));
125
126 MV1SetPosition(coxa_model_handle, coxa_joint_pos_global);
127
128 MV1DrawModel(coxa_model_handle);
129}
130
131void PhantomXMkIIRendererModel::DrawFemurLink(const int leg_index) const
132{
133 const int thign_model_handle = ModelLoader::GetIns()->GetModelHandle("model/thign_l.mv1");
134
135 if (thign_model_handle == -1) { printfDx("モデルの読み込みに失敗しました.(thign_model_handle)"); }
136
137 if (draw_joint_state_[leg_index].joint_pos_leg_coordinate.size() != 4) { return; }
138 if (draw_joint_state_[leg_index].joint_angle.size() != 3) { return; }
139
140 // パラメータの計算.
141 const VECTOR scale = VGet(10.f, 10.f, 10.f);
142
143 const VECTOR femur_joint_pos_global_coord = dxlib_util::ConvertToDxlibVec(
144 converter_ptr_->ConvertLegToGlobalCoordinate(
145 draw_joint_state_[leg_index].joint_pos_leg_coordinate[1], leg_index, draw_node_.center_of_mass_global_coord, draw_node_.posture, true));
146
147 const float coxa_angle = draw_joint_state_[leg_index].joint_angle[0];
148 const float femur_angle = draw_joint_state_[leg_index].joint_angle[1];
149
150 // リンクが曲がっているため,簡単のために回転軸を結ぶように仮想的なリンクを使っている.
151 // そのため,仮想的なリンクの角度を補正する必要がある.
152 constexpr float virtual_link_offset_angle = math_util::ConvertDegToRad(12.5f);
153
154 const Quaternion thign_def_quat =
158 Quaternion::MakeByAngleAxis(virtual_link_offset_angle, Vector3::GetLeftVec()) *
160
161 // 原点の位置が少しズレているので,補正する.
164
165 // 描画する.
166 MV1SetScale(thign_model_handle, scale);
167
168 // dxlib の座標系は左手座標系なので,右手座標系に変換するために逆転させる.
169 Quaternion thign_quat = thign_def_quat * draw_node_.posture.ToLeftHandCoordinate();
170 MV1SetRotationMatrix(thign_model_handle, dxlib_util::ConvertToDxlibMat(ToRotationMatrix(thign_quat)));
171
172 MV1SetPosition(thign_model_handle, femur_joint_pos_global_coord + offset_pos);
173
174 MV1DrawModel(thign_model_handle);
175}
176
177void PhantomXMkIIRendererModel::DrawTibiaLink(const int leg_index) const
178{
179 // モデルの読み込みを行う.
180 // ここで呼び出すと毎フレーム読み込むことになりそうだが,
181 // 実際は既に読込済みならばそのハンドルが返ってくるだけなので問題ない.
182 // こんなところでこの処理を書いているのは,コンストラクタで呼び出すと,
183 // Dxlib の初期化が終わっていないので,エラーが出るからである.
184 int tibia_model_handle = ModelLoader::GetIns()->GetModelHandle("model/tibia_l_fixed.mv1");
185
186 if (tibia_model_handle == -1)
187 {
188 printfDx("モデルの読み込みに失敗しました.(tibia_model_handle)");
189 }
190
191 if (draw_joint_state_[leg_index].joint_pos_leg_coordinate.size() != 4)
192 {
193 return;
194 }
195 if (draw_joint_state_[leg_index].joint_angle.size() != 3)
196 {
197 return;
198 }
199
200 // パラメータの計算.
201 const VECTOR scale = VGet(0.01f, 0.01f, 0.01f);
202
203 const VECTOR tibia_joint_pos_global_coord = dxlib_util::ConvertToDxlibVec(
204 converter_ptr_->ConvertLegToGlobalCoordinate(
205 draw_joint_state_[leg_index].joint_pos_leg_coordinate[2], leg_index, draw_node_.center_of_mass_global_coord, draw_node_.posture, true));
206
207 const float coxa_angle = draw_joint_state_[leg_index].joint_angle[0];
208
209 const float femur_angle = draw_joint_state_[leg_index].joint_angle[1];
210
211 const float tibia_angle = draw_joint_state_[leg_index].joint_angle[2];
212
213 const Quaternion default_quat =
217 Quaternion::MakeByAngleAxis(-femur_angle - tibia_angle, Vector3::GetLeftVec()) *
221
224
225 // 描画する.
226 MV1SetScale(tibia_model_handle, scale);
227
228 // dxlib の座標系は左手座標系なので,右手座標系に変換するために逆転させる.
229 const Quaternion tibia_quat = default_quat * draw_node_.posture.ToLeftHandCoordinate();
230 MV1SetRotationMatrix(tibia_model_handle, dxlib_util::ConvertToDxlibMat(ToRotationMatrix(tibia_quat)));
231
232 MV1SetPosition(tibia_model_handle, tibia_joint_pos_global_coord + offset_pos);
233
234 MV1DrawModel(tibia_model_handle);
235}
236
237void PhantomXMkIIRendererModel::DrawJointAxis(const int leg_index) const
238{
239 if (draw_joint_state_[leg_index].joint_pos_leg_coordinate.size() != 4)
240 {
241 return;
242 }
243 if (draw_joint_state_[leg_index].joint_angle.size() != 3)
244 {
245 return;
246 }
247
248 const float axis_length = 100.f;
249 const float axis_radius = 2.f;
250 const int axis_div_num = 16;
251
252 const unsigned int coxa_axis_color = GetColor(0, 0, 255);
253 const unsigned int femur_axis_color = GetColor(0, 255, 0);
254 const unsigned int tibia_axis_color = femur_axis_color;
255 const unsigned int spec_color = GetColor(255, 255, 255);
256
257 const float coxa_angle = draw_joint_state_[leg_index].joint_angle[0];
258
259 // Coxa の回転軸.
260 {
261 const VECTOR coxa_joint_pos_global_coord = dxlib_util::ConvertToDxlibVec(
262 converter_ptr_->ConvertLegToGlobalCoordinate(
263 draw_joint_state_[leg_index].joint_pos_leg_coordinate[0], leg_index, draw_node_.center_of_mass_global_coord, draw_node_.posture, true));
264
265 const VECTOR axis_vec = dxlib_util::ConvertToDxlibVec(
266 RotateVector3(Vector3::GetUpVec() * axis_length / 2, draw_node_.posture));
267
268 DrawCapsule3D(coxa_joint_pos_global_coord - axis_vec, coxa_joint_pos_global_coord + axis_vec, axis_radius, axis_div_num, coxa_axis_color, spec_color, TRUE);
269 }
270
271 // Femurの回転軸.
272 {
273 const VECTOR femur_joint_pos_global_coord = dxlib_util::ConvertToDxlibVec(
274 converter_ptr_->ConvertLegToGlobalCoordinate(
275 draw_joint_state_[leg_index].joint_pos_leg_coordinate[1], leg_index, draw_node_.center_of_mass_global_coord, draw_node_.posture, true));
276
277 const Quaternion default_quat = Quaternion::MakeByAngleAxis(coxa_angle, Vector3::GetUpVec());
278
279 const VECTOR axis_vec = dxlib_util::ConvertToDxlibVec(
280 RotateVector3(Vector3::GetLeftVec() * axis_length / 2, draw_node_.posture * default_quat));
281
282 DrawCapsule3D(femur_joint_pos_global_coord - axis_vec, femur_joint_pos_global_coord + axis_vec, axis_radius, axis_div_num, femur_axis_color, spec_color, TRUE);
283 }
284
285 // Tibiaの回転軸.
286 {
287 const VECTOR tibia_joint_pos_global_coord = dxlib_util::ConvertToDxlibVec(
288 converter_ptr_->ConvertLegToGlobalCoordinate(
289 draw_joint_state_[leg_index].joint_pos_leg_coordinate[2], leg_index, draw_node_.center_of_mass_global_coord, draw_node_.posture, true));
290
291 const Quaternion default_quat = Quaternion::MakeByAngleAxis(coxa_angle, Vector3::GetUpVec());
292
293 const VECTOR axis_vec = dxlib_util::ConvertToDxlibVec(
294 RotateVector3(Vector3::GetLeftVec() * axis_length / 2, draw_node_.posture * default_quat));
295
296 DrawCapsule3D(tibia_joint_pos_global_coord - axis_vec, tibia_joint_pos_global_coord + axis_vec, axis_radius, axis_div_num, tibia_axis_color, spec_color, TRUE);
297 }
298}
299
300} // namespace designlab
static constexpr int kLegNum
int GetModelHandle(const std::string &file_path)
Dxlibは3Dモデルを描画する際に,モデルのハンドルを指定する. モデルがまだ読み込まれていない場合は, モデルを読み込んでから,ハンドル番号を返す. すでに読み込みずみのモデルを読み込んだ場...
static constexpr float kCoxaBaseOffsetX
coxa linkの付け根までの長さ(上方向)[mm].
void Draw() const override
描画処理を行う. const 関数にしているのは, 描画処理の中でメンバ変数を変更しないようにするため.
PhantomXMkIIRendererModel(const std::shared_ptr< const IHexapodCoordinateConverter > &converter_ptr, const std::shared_ptr< const IHexapodJointCalculator > &calculator_ptr)
void SetNode(const RobotStateNode &node) override
ノードをセットする.
static ModelLoader * GetIns()
インスタンスを取得する. このクラスを継承したクラスは クラス名::getIns()-> の形式でメンバ関数を呼び出す.
Definition singleton.h:34
void SetZBufferEnable()
デフォルトだと描画処理を書いた順に描画されるが, これをZバッファを使用して奥行きを考慮して描画するようにする. 毎フレーム実行する必要がある.
MATRIX ConvertToDxlibMat(const RotationMatrix3x3 &mat)
このプログラムで使用しているMatrixを, Dxlibの行列を示すMATRIXに変換する.
Definition dxlib_util.h:44
VECTOR ConvertToDxlibVec(const Vector3 &vec)
Dxlibの座標を示すVECTORと,このプログラムで使用しているVectorを変換する. ロボット座標系は右手座標系, Dxlibは左手座標系(工学は右手・ゲームライブラリは左手が多い)なのでyを...
Definition dxlib_util.h:35
constexpr T ConvertDegToRad(const T deg) noexcept
角度を [deg] から [rad] に変換する関数.
Definition math_util.h:126
Vector3 RotateVector3(const Vector3 &vec, const EulerXYZ &rot)
回転させたベクトルを返す.三角関数の処理が多く重たいので注意.
RotationMatrix3x3 ToRotationMatrix(const Quaternion &q)
クォータニオンから回転角行列への変換.
static Quaternion MakeByAngleAxis(float rad_angle, const Vector3 &axis)
回転軸と回転角からクォータニオンを作成する. q = cos(θ/2) * w + sin(θ/2) * { v.x + v.y + v.z } となる. ノルムは必ず1になる.
constexpr Quaternion ToLeftHandCoordinate() const noexcept
左手座標系への変換を行う. 言うまでもないが,機械工学では通例右手座標系を使う. しかし,dxlib は左手座標系なので,dxlib で描画するときは, この関数を使って左手座標系に変換する必要があ...
グラフ構造のためのノード(頂点).旧名 LNODE
Vector3 center_of_mass_global_coord
[4 * 3 = 12byte] グローバル座標系における重心の位置.旧名 GCOM
Quaternion posture
[4 * 4 = 16byte] 姿勢を表すクォータニオン.
static constexpr Vector3 GetUpVec() noexcept
上に進む単位ベクトルを返す. 静的な関数なので,Vector3::GetUpVec() と呼び出せる.
static constexpr Vector3 GetFrontVec() noexcept
正面に進む単位ベクトルを返す. 静的な関数なので,Vector3::GetFrontVec() と呼び出せる.
static constexpr Vector3 GetLeftVec() noexcept
左に進む単位ベクトルを返す. 静的な関数なので,Vector3::GetLeftVec() と呼び出せる.