Отговори (2)
Първо, не искате да използвате gluLookAt
. gluLookAt
завърта камерата, но физическият екран, който потребителят гледа, не се завърта. gluLookAt
ще работи само ако екранът се завърти така, че нормалният екран да продължи да сочи към потребителя. Перспективното изкривяване на проекцията извън оста ще се погрижи за цялата ротация, от която се нуждаем.
Това, което трябва да вземете предвид във вашия модел, е позицията на екрана в пресечената част. Помислете за следното изображение. Червените точки са границите на екрана. Това, което трябва да постигнете, е тези позиции да останат постоянни в 3D WCS, тъй като физическият екран в реалния свят също (да се надяваме) не се движи. Мисля, че това е ключовото прозрение за виртуалната реалност и стереоскопията. Екранът е нещо като прозорец към виртуалната реалност и за да изравните реалния свят с виртуалната реалност, трябва да изравните пресечената част с този прозорец.
За да направите това, трябва да определите позицията на екрана в координатната система на Kinect. Ако приемем, че Kinect е в горната част на екрана, че +y сочи надолу и че единицата, която използвате, е милиметри, очаквам тези координати да бъдат нещо от рода на (+-300, 200, 0), ( +-300, 500, 0).
Сега има две възможности за далечния самолет. Можете или да изберете да използвате фиксирано разстояние от камерата до далечната равнина. Това би означавало, че далечната равнина ще се премести назад, ако потребителят се премести назад, вероятно изрязвайки обекти, които искате да нарисувате. Или можете да запазите далечната равнина на фиксирана позиция в WCS, както е показано на изображението. Вярвам, че второто е по-полезно. За близката равнина обаче мисля, че фиксираното разстояние от камерата е добре.
Входните данни са 3D позициите на екрана wcsPtTopLeftScreen
и wcsPtBottomRightScreen
, проследената позиция на главата wcsPtHead
, z стойността на далечната равнина wcsZFar
(всички в WCS) и z стойността на близката равнина camZNear
(в координатите на камерата) . Трябва да изчислим пресечените параметри в координатите на камерата.
camPtTopLeftScreen = wcsPtTopLeftScreen - wcsPtHead;
camPtTopLeftNear = camPtTopLeftScreen / camPtTopLeftScreen.z * camZNear;
и същото с долната дясна точка. Също:
camZFar = wcsZFar - wcsPtHead.z
Сега единственият проблем е, че Kinect и OpenGL използват различни координатни системи. В Kinect CS +y сочи надолу, +z сочи от потребителя към Kinect. В OpenGL +y сочи нагоре, +z сочи към зрителя. Това означава, че трябва да умножим y и z по -1:
glFrustum(camPtTopLeftNear.x, camPtBottomRightNear.x,
-camPtBottomRightNear.y, -camPtTopLeftNear.y, camZNear, camZFar);
Ако искате по-добро обяснение, което обхваща и стереоскопията, вижте този видеоклип, намерих го проницателен и добре направен.
Бърза демонстрация, може да се наложи да коригирате wcsWidth
, pxWidth
и wcsPtHead.z
.
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <glut.h>
#include <functional>
float heightFromWidth;
glm::vec3 camPtTopLeftNear, camPtBottomRightNear;
float camZNear, camZFar;
glm::vec3 wcsPtHead(0, 0, -700);
void moveCameraXY(int pxPosX, int pxPosY)
{
// Width of the screen in mm and in pixels.
float wcsWidth = 520.0;
float pxWidth = 1920.0f;
float wcsHeight = heightFromWidth * wcsWidth;
float pxHeight = heightFromWidth * pxWidth;
float wcsFromPx = wcsWidth / pxWidth;
glm::vec3 wcsPtTopLeftScreen(-wcsWidth/2.f, -wcsHeight/2.f, 0);
glm::vec3 wcsPtBottomRightScreen(wcsWidth/2.f, wcsHeight/2.f, 0);
wcsPtHead = glm::vec3(wcsFromPx * float(pxPosX - pxWidth / 2), wcsFromPx * float(pxPosY - pxHeight * 0.5f), wcsPtHead.z);
camZNear = 1.0;
float wcsZFar = 500;
glm::vec3 camPtTopLeftScreen = wcsPtTopLeftScreen - wcsPtHead;
camPtTopLeftNear = camZNear / camPtTopLeftScreen.z * camPtTopLeftScreen;
glm::vec3 camPtBottomRightScreen = wcsPtBottomRightScreen - wcsPtHead;
camPtBottomRightNear = camPtBottomRightScreen / camPtBottomRightScreen.z * camZNear;
camZFar = wcsZFar - wcsPtHead.z;
glutPostRedisplay();
}
void moveCameraZ(int button, int state, int x, int y)
{
// No mouse wheel in GLUT. :(
if ((button == 0) || (button == 2))
{
if (state == GLUT_DOWN)
return;
wcsPtHead.z += (button == 0 ? -1 : 1) * 100;
glutPostRedisplay();
}
}
void reshape(int w, int h)
{
heightFromWidth = float(h) / float(w);
glViewport(0, 0, w, h);
}
void drawObject(std::function<void(GLdouble)> drawSolid, std::function<void(GLdouble)> drawWireframe, GLdouble size)
{
glPushAttrib(GL_ALL_ATTRIB_BITS);
glEnable(GL_COLOR);
glDisable(GL_LIGHTING);
glColor4f(1, 1, 1, 1);
drawSolid(size);
glColor4f(0.8, 0.8, 0.8, 1);
glDisable(GL_DEPTH_TEST);
glLineWidth(1);
drawWireframe(size);
glColor4f(0, 0, 0, 1);
glEnable(GL_DEPTH_TEST);
glLineWidth(3);
drawWireframe(size);
glPopAttrib();
}
void display(void)
{
glPushAttrib(GL_ALL_ATTRIB_BITS);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
// In the Kinect CS, +y points down, +z points from the user towards the Kinect.
// In OpenGL, +y points up, +z points towards the viewer.
glm::mat4 mvpCube;
mvpCube = glm::frustum(camPtTopLeftNear.x, camPtBottomRightNear.x,
-camPtBottomRightNear.y, -camPtTopLeftNear.y, camZNear, camZFar);
mvpCube = glm::scale(mvpCube, glm::vec3(1, -1, -1));
mvpCube = glm::translate(mvpCube, -wcsPtHead);
glMatrixMode(GL_MODELVIEW); glLoadMatrixf(glm::value_ptr(mvpCube));
drawObject(glutSolidCube, glutWireCube, 140);
glm::mat4 mvpTeapot = glm::translate(mvpCube, glm::vec3(100, 0, 200));
mvpTeapot = glm::scale(mvpTeapot, glm::vec3(1, -1, -1)); // teapots are in OpenGL coordinates
glLoadMatrixf(glm::value_ptr(mvpTeapot));
glColor4f(1, 1, 1, 1);
drawObject(glutSolidTeapot, glutWireTeapot, 50);
glFlush();
glPopAttrib();
}
void leave(unsigned char, int, int)
{
exit(0);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutCreateWindow("glut test");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
moveCameraXY(0,0);
glutPassiveMotionFunc(moveCameraXY);
glutMouseFunc(moveCameraZ);
glutKeyboardFunc(leave);
glutFullScreen();
glutMainLoop();
return 0;
}
Следните изображения трябва да се гледат от разстояние, равно на 135% от ширината им на екрана (70 см на моя 52 см широк екран на цял екран).
gluLookAt
. Моето разбиране за glFrustum
беше, че параметрите, които влизат, ще установят обема на изрязване и при прилагане на gluLookAt
се случва изкривяването. Междувременно ще пробвам този метод, но можете ли да погледнете връзката относно lookAt не е правилният начин да отидете там, защото изглежда, че е правилен?
- person user1240679; 26.05.2013
glFrustum
и не използвах gluLookAt
, но не можах да постигна ефекта. Добавих още един въпрос относно получаването на изкривяване само с glFrustum
, за да проверя за това. Същият, откъдето направихте връзка тук. Друга връзка към въпрос за проекция извън оста . Използвайки gluLookAt
, аз просто правя трансформация на гледане и премествам „камерата“ на друга позиция, но не я завъртам. Исках да проверя отново с вас тук.
- person user1240679; 27.05.2013
center - eye
е кратна на (0,0,-1), тогава gluLookAt
няма да се върти, а само да се преобразува от -eye
. Но вие искате кубът да остане в центъра на екрана, следователно параметърът center
трябва да остане на (0,0,0)
. Ако след това преместите очите, gluLookAt
генерира завъртане. И да, преместването на камерата с -око е същото като преместването на сцената с +око.
- person Andreas Haferburg; 28.05.2013
glFrustum
очаква параметрите отгоре, отляво, отдолу и отдясно да са в близката равнина. camTopLeft/BottomRightScreen
са ъгловите точки на екрана, така че z-разстоянието от очите е camTopLeftScreen.z
. И за да изчислим параметрите на близката равнина, имаме нужда от z-разстояние от camZNear
, така че трябва да умножим тези точки с camZNear/camTopLeftScreen.z
. Това умножение означава, че мащабираме ъгловите точки в посока z на координатната система на камерата. Нека да видя дали мога да добавя това към чертежа.
- person Andreas Haferburg; 02.06.2013
camTopLeft/BottomRightScreen
имах предвид camTopLeftScreen
или camBottomRightScreen
, няма нищо общо с разделянето.
- person Andreas Haferburg; 02.06.2013
glLoadMatrix
. Ако е необходимо, може би бихте могли да отворите отделен въпрос и да го свържете тук.
- person Andreas Haferburg; 12.10.2014
Най-доброто обяснение за това как да използвате glFrustum за приложения за проследяване на главата, което можете да намерите, е в тази статия на Робърт Коима, наречена обобщена перспективна проекция:
http://csc.lsu.edu/~kooima/pdfs/gen-perspective.pdf
Освен това ви позволява просто да използвате стерео прожекции, просто трябва да превключвате между лява и дясна камера!