質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

1回答

948閲覧

クォータニオンを用いて物体を等速で回転させる方法が知りたい。

退会済みユーザー

退会済みユーザー

総合スコア0

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2022/11/02 02:16

提示コードのif文のキー入力部ですがクォータニオンを用いて立方体の回転を実装しているのですがキーを押しっぱなしにすると微妙に回転が遅くなって止まってしまうのですがこれはどう対処したらいいのでしょうか?等速で回転してくれません。

イメージ説明

transform

cpp

1/*############################################################################################ 2# 行列回転 取得 3############################################################################################*/ 4glm::mat4 FrameWork::Transform::getMatRotate()const 5{ 6 if( (rotateOrigin == glm::vec3(0,0,0)) || (rotateVector == glm::vec3(0,0,0)) ) 7 { 8 assert(0 && "Transform::setRotate() (origin == glm::vec3(0,0,0)) || (vec == glm::vec3(0,0,0)"); 9 } 10 11 return glm::mat4(RotationBetweenVectors(rotateOrigin,rotateVector)); 12} 13 14 15/*############################################################################################ 16# 2つのベクトルのなす角 17############################################################################################*/ 18glm::quat FrameWork::Transform::RotationBetweenVectors(glm::vec3 start, glm::vec3 dest)const 19{ 20 start = glm::normalize(start); 21 dest = glm::normalize(dest); 22 23 float cosTheta = glm::dot(start, dest); 24 glm::vec3 rotationAxis; 25 26 if (cosTheta < -1 + 0.001f) 27 { 28 rotationAxis = glm::cross(glm::vec3(0.0f, 0.0f, 1.0f), start); 29 if (glm::length2(rotationAxis) < 0.01) 30 { 31 rotationAxis = glm::cross(glm::vec3(1.0f, 0.0f, 0.0f), start); 32 } 33 34 rotationAxis = glm::normalize(rotationAxis); 35 36 return glm::angleAxis(glm::radians(180.0f), rotationAxis); 37 } 38 39 rotationAxis = glm::cross(start, dest); 40 41 float s = glm::sqrt((1 + cosTheta) * 2); 42 float invs = 1 / s; 43 44 return glm::quat 45 ( 46 s * 0.5f, 47 rotationAxis.x * invs, 48 rotationAxis.y * invs, 49 rotationAxis.z * invs 50 ); 51} 52 53
Player.cpp

cpp

1#include "Player.hpp" 2#include "FrameWork_3D/FrameWork.hpp" 3#include <memory> 4 5Player::Player() 6{ 7 //FrameWork::Resource::LoadModel("asset/model/mesh.fbx"); 8 texture = FrameWork::Resource::LoadTexture("asset/texture/debug.png",aiTextureType_BASE_COLOR); 9 10 model = FrameWork::Resource::LoadModel("asset/model/mesh.fbx"); 11 //model.setVertexBuffer(); 12 13 shader = std::make_shared<FrameWork::Shader>(); 14 shader->Load("asset/shader/3D/texture/BasicTexture.vert", "asset/shader/3D/texture/BasicTexture.frag"); 15 //shader->Load("asset/shader/3D/Monochromatic/BasicMono.vert","asset/shader/3D/Monochromatic/BasicMono.frag"); 16 17// texture = FrameWork::LoadTexture("asset/texture/debug.png", glm::vec2(8, 8)); 18 19 rotate = glm::vec3(0, 1, 0); 20 transform.position = glm::vec3(0, 0, 0); 21 transform.scale = glm::vec3(1,1,1); 22 transform.rotateOrigin = glm::vec3(0,1,0); 23 transform.rotateVector = rotate; 24 25 //transform.rotateOrigin = glm::vec3(1, 0, 0); 26 //transform.rotateVector = glm::vec3(1, 0, 0); 27 28 shader->setVertexAttribute(model->vao,model->vbo, "vertexPosition", 3, sizeof(FrameWork::VertexAttribute), sizeof(float) * 0); 29 shader->setVertexAttribute(model->vao, model->vbo, "vertexUV", 2, sizeof(FrameWork::VertexAttribute), sizeof(float) * 3); 30// shader->setVertexAttribute(sprite.vao, sprite.vbo, "vertexNormal", 3, sizeof(FrameWork::VertexAttribute_Sprite), sizeof(float) * 5); 31 32 //sprite.shader = shader; 33} 34 35void Player::Render(const glm::mat4 view) 36{ 37 shader->setEnable(); 38 39 40 41 if (FrameWork::Window::windowContext->getKeyInput(GLFW_KEY_UP) == true) 42 { 43 rotate.z += 0.01; 44 } 45 46 if (FrameWork::Window::windowContext->getKeyInput(GLFW_KEY_DOWN ) == true) 47 { 48 rotate.z -= 0.01; 49 } 50 51 52 if (FrameWork::Window::windowContext->getKeyInput(GLFW_KEY_RIGHT) == true) 53 { 54 rotate.x += 0.01; 55 } 56 57 if (FrameWork::Window::windowContext->getKeyInput(GLFW_KEY_LEFT ) == true) 58 { 59 rotate.x -= 0.01; 60 } 61 62 std::cout << "rotate.x: " << rotate.x << std::endl; 63 std::cout << "rotate.z: " << rotate.z << std::endl; 64 std::cout <<std::endl; 65 66 67 68 transform.rotateVector = rotate; 69 70 shader->setUniformSampler2D("uImage", 0, texture.getID()); 71 //shader->setUniform4f("uFragment",glm::vec4(1.0,0.0,0.0,0.0)); 72 shader->setUniformMatrix4x4fv("uViewProjection", view); 73 shader->setUniformMatrix4x4fv("uScale", transform.getMatScale()); 74 shader->setUniformMatrix4x4fv("uTranslate", transform.getMatPosition()); 75 shader->setUniformMatrix4x4fv("uRotate", transform.getMatRotate()); 76 model->Render(); 77 78 shader->setDisable(); 79} 80 81void Player::Update() 82{ 83 //sprite.setTexture(0, texture.at(0)); 84} 85 86

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

コードを全部見ているわけじゃなく「ぱっと見の雰囲気」での話だけど…

  • 2つのベクトルの成す角 を求めていて,何かわからんけどクォータニオンはその角度に対応したものが求められる.
  • 2つのベクトルの初期値はどちらも (0,1,0)
  • キー操作で一方の側のベクトルの1つの要素が増減される

という話だとしたら…

等速で回転するには「2つのベクトルの成す角」なる量が常に等量だけ増加していく必要があるのでは?
(そんなことが可能かどうかは知らんが)

何が悪いか,に関しては,例えば,キーを押し続けて rotate.x += 0.01; が複数回実施されていくとき,「2つのベクトルの成す角」がどのように変化していくのかを考えてみればよい.
かなりの時間キーを押し続けて一方のベクトルが (すっごい大きいx値,1,0) になったとして,他方がずっと(0,1,0)固定なのであれば,角度は90度に漸近していくだけだ.


どうすれば良いか? に関しては,(2つのベクトルとかいう奴らの役割がわからない側からすれば,)単に,やりたいことを素直にやればいいじゃない? と思う.
例えば,「キーを押している状況ではある一定の角度 θ だけ回転する」ということをしたいなら,「回転角度θに対応するクォータニオン」を計算して使ってればいいんじゃないの?

投稿2022/11/02 03:00

fana

総合スコア11666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2022/11/02 03:03

> 角度は90度に漸近していくだけだ っていう話,昔もやったような気がするが,記憶違いか?
退会済みユーザー

退会済みユーザー

2022/11/02 03:04

質問ですが > 「キーを押している状況ではある一定の角度 θ だけ回転する」ということをしたいなら,「回転角度θに対応するクォータニオン」を計算 とありますが。これは何の値から計算すればいいのでしょうか?
fana

2022/11/02 03:07

「何の値」って何? あるキーを押したときに「どっち方向にどれだけ回したいか」っていう所望の変化量はあなたが決めるんじゃないの? どれだけ回したいか=角度θ が定数でいいなら定数で実装すればいいんじゃない?
fana

2022/11/04 03:06

退会しtail ! > shader->setUniformMatrix4x4fv("uRotate", transform.getMatRotate()); なる行から察するに,回転行列をシェーダのuniform変数に設定するんだろうから, 「回転行列そのもの あるいはそれを作り出せる何らかの情報」を保持しておいてキー押下時に更新すれば良いのだと思うよ. そしたら「その更新量とは何か」っていうだけの話になるよね. 押したキーに応じた方向に姿勢をちょっとだけ回す,ということをすればよいのであり,その「ちょっとだけ回す」角度のことを θ と述べたということである. (わざわざ言うまでも無いが,「ちょっとだけ回す」際の回転軸は押されたたキーから即決まるよね) で,「更新」ってのはマトリクスを左右どっちから乗じるのか?的な話もあり得たりするのだけど… まぁいいや.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問