ورود

View Full Version : چرخوندن Quat در محور World



UfnCod3r
دوشنبه 19 فروردین 1392, 10:56 صبح
سلام من می خوام Quaternion درو محور World بچرخه . لوکال نباشه .
این رو نوشتم .

inline void worldRotate(flt angleX, flt angleY, flt angleZ)
{
XQuat q ;
XQuat inv;
q.setFromEuler(angleX, angleY, angleZ);
this->getInverse(&inv);
*this = (*this) * inv * q * (*this);
}


مدل ها درست می چرخن .
ولی دوربین دور محور خودش می چرخه نمی دونم چشه .:متعجب:
اینم کد:::لبخند:

#include <stdio.h>
#include <Windows.h>
#include <gl\GL.h>

//SSE vec,quat,mat4x4
#include "..\XSSE\XVec3.h"
#include "..\XSSE\XMath.h"
#include "..\XSSE\XVec4.h"
#include "..\XSSE\XQuat.h"
#include "..\XSSE\XMat4x4.h"


XMat4x4 gMatProj;
XMat4x4 gMatView;

XVec3 gCameraPos(0,4,4);
XQuat gCameraRotation(0,0,0,1);


struct XStaticMesh
{
XVec3 worldPos;
XQuat rotation;

void render()
{
XMat4x4 matrix = XMat4x4::CreateTranslation(worldPos)*XMat4x4::Crea teRotation(rotation);
glLoadMatrixf((gMatView*matrix).m);
glColor3f(1,1,0.8);
//DrawMode();
//draw axis ----
glDisable(GL_LIGHTING);
glCallList(gCallListwAxis);
glEnable(GL_LIGHTING);
}
};

XStaticMesh gModel1;
XStaticMesh gModel2;

int main(int argc, char** argv)
{
XMath_Init();
XSSE_Init();
XCreateWnd(640, 480, "Test1");
XGLInit();



gModel1.worldPos.setZero();
gModel1.rotation.setIdentity();

gModel2.worldPos.setOne();
gModel2.rotation.setFromAngleAxisY(90.0f);

while (gLoop)
{
//input update ======================================
MSG msg;
memcpy(gKeysPre, gkeysCur, 255);
while (PeekMessage(&msg, gHWND, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//proj matrix
gMatProj = XMat4x4::CreatePerspective(45.0f, 1.3f, 0.0001f, 1000.0f);
//view matrix
gMatView = XMat4x4::CreateTranslation(gCameraPos) * XMat4x4::CreateRotation(gCameraRotation);
gMatView.invert();

//load proj matrix
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(gMatProj.m);

//load view matrix
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(gMatView.m);

//draw gride
glDisable(GL_LIGHTING);
glCallList(gCallListGrid);
glEnable(GL_LIGHTING);


//rotate model
if(XKeyDown('T'))
gModel1.rotation.worldRotate(3.0f,0,0);
if(XKeyDown('Y'))
gModel1.rotation.worldRotate(0.0f,3,0);
if(XKeyDown('U'))
gModel1.rotation.worldRotate(0.0f,0,3);


if(XKeyDown('E'))
gCameraPos.y++;
else if(XKeyDown('Q'))
gCameraPos.y--;


//move camera --------------------
if(XKeyDown('D'))
gCameraPos += gCameraRotation * XVec3::RIGHT;
else if(XKeyDown('A'))
gCameraPos -= gCameraRotation * XVec3::RIGHT;
if(XKeyDown('W'))
gCameraPos -= gCameraRotation * XVec3::FORWARD;
else if(XKeyDown('S'))
gCameraPos += gCameraRotation * XVec3::FORWARD;


//rotate camera -------------------
if(XKeyDown(VK_RIGHT))
gCameraRotation.worldRotate(0,-2,0);
else if(XKeyDown(VK_LEFT))
gCameraRotation.worldRotate(0,2,0);

if(XKeyDown(VK_UP))
gCameraRotation.worldRotate(-2,0,0);
if(XKeyDown(VK_DOWN))
gCameraRotation.worldRotate(2,0,0);


gModel1.render();
gModel2.render();

SwapBuffers(gHDC);
Sleep(32);

//exith with ESC
if(XKeyRelese(VK_ESCAPE))
gLoop = false;
}
return 1;
}

UfnCod3r
دوشنبه 19 فروردین 1392, 17:45 عصر
درضمن وقتی Euler رو می گیرم و اونو می چرخونم و وبعد تبدیل به Quat می کنم مشکلی پیش نمیاد.
البته کلا ابجکت های تو محیط درست می چرخن ولی دوربین نه .:ناراحت:
راستی هرکی کد تبدیل Quat به EulerAngle داره بده .
واس من همش خرابه :ناراحت:
1 سال بعد .... :لبخند:

سپول
سه شنبه 20 فروردین 1392, 00:32 صبح
مختصات world منظورت اینه که حول مرکز (0، 0، 0) بچرخه ؟

برای اون تابع هم :
https://bitbucket.org/sepul/dark-hammer/src/193041c72143b56a2bf1f5d507148e1ba7d49af7/src/core/vec-math.c?at=default

خط 187 تابع quat_geteuler
ظاهرا با مختصات opengl کار می کنی پس نتیجه رو منفی کن.

UfnCod3r
سه شنبه 20 فروردین 1392, 09:31 صبح
منظورم اینه

XVec3 ang = rotation.getEuler();
ang.y += 45.0f;
rotation.setFromEuler(ang);

می خوام عوض این کار یه تابع worldRotate بنویسم :|

inline void worldRotate(flt angleX, flt angleY, flt angleZ)
{
//oldRot = oldRot * inverseoldRot * worldRot * oldRot
XQuat q;
XQuat inv;
q.setFromEuler(angleX,angleY,angleZ);
this->getInverse(&inv);
*this = (*this) * inv * q * (*this);
}


الان رو مدل های تو محیط امتحان کردم می چرخه ولی دوربینم درست نمی چرخه کج میشه .
بی زحمت این رو اگه نگا کنی می بینی که
102549
قوری با g,h,j دو محور خودش می چرخه و با t,y,u هم دور محور اصلی .
دوربین هم با چپ و راست و بالا و پایین می چرخه ولی وقتی پایین می چرخم و بعد بالا محور z هم تغییر می کنه و دربین کج میشه . نمیدونم چشه :متفکر:
:متفکر:
:ناراحت:
کدشم همینه ::

XMat4x4 gMatProj;
XMat4x4 gMatView;

XVec3 gCameraPos(0,4,16);
XQuat gCameraRotation(0,0,0,1);

XStaticMesh gModel1;

void render()
{
gMatProj = XMat4x4::CreatePerspective(45.0f, 1.3f, 0.0001f, 1000.0f);
gMatView = XMat4x4::CreateTranslation(gCameraPos) * XMat4x4::CreateRotation(gCameraRotation);
gMatView.invert();

glMatrixMode(GL_PROJECTION);
glLoadMatrixf(gMatProj.m);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(gMatView.m);
//drawGrigd();

//world rotate
if(XKeyDown('T'))
gModel1.rotation.worldRotate(3.0f, 0.0f, 0.0f);
if(XKeyDown('Y'))
gModel1.rotation.worldRotate(0.0f, 3.0f, 0.0f);
if(XKeyDown('U'))
gModel1.rotation.worldRotate(0.0f, 0.0f, 3.0f);

//local rotate
if(XKeyDown('G'))
gModel1.rotation.rotateX(3);
if(XKeyDown('H'))
gModel1.rotation.rotateY(3);
if(XKeyDown('J'))
gModel1.rotation.rotateZ(3);

//movcamera
if(XKeyDown('D'))
gCameraPos += gCameraRotation * XVec3::RIGHT;
else if(XKeyDown('A'))
gCameraPos -= gCameraRotation * XVec3::RIGHT;

if(XKeyDown('W'))
gCameraPos -= gCameraRotation * XVec3::FORWARD;
else if(XKeyDown('S'))
gCameraPos += gCameraRotation * XVec3::FORWARD;

//rotate camera
if(XKeyDown(VK_RIGHT))
gCameraRotation.worldRotate(0,-2,0);
else if(XKeyDown(VK_LEFT))
gCameraRotation.worldRotate(0,2,0);

if(XKeyDown(VK_UP))
gCameraRotation.worldRotate(-2,0,0);
if(XKeyDown(VK_DOWN))
gCameraRotation.worldRotate(2,0,0);

//draw teapot
XMat4x4 modelMatrix = XMat4x4::CreateTranslation(gModel1.worldPos)*XMat4 x4::CreateRotation(gModel1.rotation);
glLoadMatrixf((gMatView*modelMatrix).m);
glutSolidTeapot(1.0f);
}

:ناراحت:
فکرکنم اخرم باید از همون ToEulet,SetEuler استفاده کنم راحت شم :ناراحت:

UfnCod3r
سه شنبه 20 فروردین 1392, 11:04 صبح
@سپول
اقا مطمنی اون تابع geteuler شما درسته
من دقیقا همونا رو نوشتم

void setFromEuler2(flt pitch, flt yaw, flt roll)
{
flt sp = sin(pitch * 0.5f);
flt cp = cos(pitch * 0.5f);
flt sy = sin(yaw * 0.5f);
flt cy = cos(yaw * 0.5f);
flt sr = sin(roll * 0.5f);
flt cr = cos(roll * 0.5f);

x = cy*sp*cr + sy*cp*sr;
y = -cy*sp*sr + sy*cp*cr;
z = -sy*sp*cr + cy*cp*sr;
w = cy*cp*cr + sy*sp*sr;
}
void toEuler2(flt* pitch, flt* yaw, flt* roll)
{
const flt epsilon = 0.0009765625f;
const flt threshold = 0.5f - epsilon;
flt xy = x*y;
flt zw = z*w;
flt t = xy + zw;

if ((t < -threshold) || (t > threshold))
{
flt sign = _math_sign(t);
*pitch = sign * X_HALF_PI;
*yaw = sign * 2.0f * atan2f(x, w);
*roll = 0.0f;
}
else
{
flt xx = x * x;
flt xz = x * z;
flt xw = x * w;

flt yy = y * y;
flt yw = y * w;
flt yz = y * z;

flt zz = z * z;

*yaw = atan2f(2 * yw - 2.0f * xz, 1.0f - 2.0f * yy - 2.0f * zz);
*pitch = atan2f(2 * xw - 2.0f * yz, 1.0f - 2.0f * xx - 2.0f * zz);
*roll = asinf(2.0f * t);
}
}

ولی نگا چی به چی تبدیل میشه

XQuat q;
flt pp,yy,rr;
pp = 1.570; //90
yy = 3.1415; //180
rr = 0.7853; //45
printf("%f %f %f\n", pp, yy, rr);
q.setFromEuler2(pp, yy, rr);
q.toEuler2(&pp, &yy, &rr);
printf("%f %f %f\n", pp, yy, rr);

نتیجه میشه


1.570233 2.356200 0.00056

:متعجب:

سپول
سه شنبه 20 فروردین 1392, 12:54 عصر
اقا مطمنی اون تابع geteuler شما درسته
آره؛ اگه می خوای تست کنی همون زاویه هایی که خروجی گرفتی رو دوباره بده به setFromEuler و نتیجه رو با مقدار های quaternion مقایسه کن. در واقع quaternion ها رو مقایسه کن نه euler رو.

دلیلش هم اینه که اون جوابی که می بینی همون pitch yaw roll اولیه نیست ولی با مقدارهای جدید هم به اون زاویه تو فضا می رسی. این هم یکی دیگه از اشکال های سیستم euler هست.

در مورد کدت هم یه نگاهی کردم، من با سیستم قدیمی opengl آشنایی چندانی ندارم ولی چندتا نکته به ذهنم رسید که امتحان کن.
- اولا خط 18 تابع glLoadMatrixf(gMatView.m); اضافی هست.
- برای محاسبه ماتریس view راه های سریعتری هست تا invert کردن. یه نگاهی به فایل camera.c در سورس dark-hammer بنداز (البته اون مختصات دست چپ حساب می کنه)
- اگه تابع worldRotate ات درست کار کنه عملکرد کد باید طبیعی باشه چون از خط 50 به بعد دوربین رو حول World چرخوندی یعنی قاعدتا باید حول محور مختصات بچرخه. درستش اینه که دوربین رو حول خودش بچرخونی. البته اگه دوربین first-person می خوای.