Това е брилянтно - този първи ред е толкова прост. Разбирам коментара ви относно реда, но защо join() е наречен така? Това синхронен програмен поток ли е? Main() няма да прекрати, докато нишката ви не приключи?

person user1240679    schedule 23.05.2013    source източник
comment
Интересен проект. Чудя се какви са шансовете крайният резултат да е деца, които седят на сантиметър от телевизора, за да получат максимална представа за света? ;)   -  person Samuel Harmer    schedule 30.05.2013
comment
Накарахте ли го да работи с Kinect? Видео от гледна точка на потребителя би било наистина страхотно.   -  person Andreas Haferburg    schedule 31.05.2013


Отговори (2)


Първо, не искате да използвате gluLookAt. gluLookAt завърта камерата, но физическият екран, който потребителят гледа, не се завърта. gluLookAt ще работи само ако екранът се завърти така, че нормалният екран да продължи да сочи към потребителя. Перспективното изкривяване на проекцията извън оста ще се погрижи за цялата ротация, от която се нуждаем.

Това, което трябва да вземете предвид във вашия модел, е позицията на екрана в пресечената част. Помислете за следното изображение. Червените точки са границите на екрана. Това, което трябва да постигнете, е тези позиции да останат постоянни в 3D WCS, тъй като физическият екран в реалния свят също (да се надяваме) не се движи. Мисля, че това е ключовото прозрение за виртуалната реалност и стереоскопията. Екранът е нещо като прозорец към виртуалната реалност и за да изравните реалния свят с виртуалната реалност, трябва да изравните пресечената част с този прозорец.

Страхотни умения за MSPaint

За да направите това, трябва да определите позицията на екрана в координатната система на 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 см широк екран на цял екран). въведете описание на изображението туквъведете описание на изображението тук

person Andreas Haferburg    schedule 26.05.2013
comment
Това просто променя цялата концепция, която имах в ума си. Ще опитам това, но това, което вече опитах, се основава на това ВРЪЗКА, за която източникът е тук и използва gluLookAt. Моето разбиране за glFrustum беше, че параметрите, които влизат, ще установят обема на изрязване и при прилагане на gluLookAt се случва изкривяването. Междувременно ще пробвам този метод, но можете ли да погледнете връзката относно lookAt не е правилният начин да отидете там, защото изглежда, че е правилен? - person user1240679; 26.05.2013
comment
Ето друга връзка, която описва защо не искате да ротирате. Докато контекстът е стереоскопия, се прилагат същите принципи като при проследяването на главата. - person Andreas Haferburg; 26.05.2013
comment
Опитах се да получа изкривяването на перспективата, като използвах само glFrustum и не използвах gluLookAt, но не можах да постигна ефекта. Добавих още един въпрос относно получаването на изкривяване само с glFrustum, за да проверя за това. Същият, откъдето направихте връзка тук. Друга връзка към въпрос за проекция извън оста . Използвайки gluLookAt, аз просто правя трансформация на гледане и премествам „камерата“ на друга позиция, но не я завъртам. Исках да проверя отново с вас тук. - person user1240679; 27.05.2013
comment
О, това беше ти. :) Трудно е да се разграничат анонимните потребители. Когато публикувахте тази връзка към Holotoy по-рано, вече не бях сигурен, затова добавих примерна реализация към моя отговор. Опитахте ли това? - person Andreas Haferburg; 27.05.2013
comment
Опитах същия тест тук. С окото на камерата далеч от модела, ето екранна снимка. Когато преместя окото по-близо до модела и наляво, тук е екранна снимка горе вдясно ъгълът на куба е на същата височина като горния ляв ъгъл. Това означава ли, че трансформацията на гледане тук е правилна? Преводът на сцената или преместването на камерата вместо това идват до едно и също нещо тук, това ли е? - person user1240679; 28.05.2013
comment
Не, това не е същият тест. Ако посоката на гледане center - eye е кратна на (0,0,-1), тогава gluLookAt няма да се върти, а само да се преобразува от -eye. Но вие искате кубът да остане в центъра на екрана, следователно параметърът center трябва да остане на (0,0,0). Ако след това преместите очите, gluLookAt генерира завъртане. И да, преместването на камерата с -око е същото като преместването на сцената с +око. - person Andreas Haferburg; 28.05.2013
comment
Според горните изчисления, „camTopLeftNear“ и „camBottomRightNear“ стават по-малки, когато главата на потребителя се премести по-далеч. Това намалява обема на изрязване и начертаният обект изглежда по-голям по размер. Въпреки това, обикновено, когато се движим по-далеч, размерът на всеки обект се намалява. не е ли Имам малко объркване, разбирайки това. P.S. Ще кача видеоклип много скоро и ще ви информирам тук. Благодаря отново - person user1240679; 02.06.2013
comment
Също така имах известно съмнение защо трябва да калкулираме „camTopLeftNear“ и „camBottomRightNear“. След като вече изчисляваме „camTopLeftScreen“ и „camBottomRightScreen“, защо изчисленията не могат да бъдат в тези координати? Защо трябва да умножаваме това с (1/camTopLeftScreen.z * camZNear). 'camZnear' в моя случай е 0,1. - person user1240679; 02.06.2013
comment
Що се отнася до първия ви въпрос, обектът на екрана не трябва да става по-малък. Когато потребителят се отдалечи от екрана, екранът в реалния свят вече става по-малък в зрителното поле на реалния свят на потребителя и с това обектът изглежда по-малък, въпреки че размерът му на екрана остава почти същият . - person Andreas Haferburg; 02.06.2013
comment
Втори въпрос: glFrustum очаква параметрите отгоре, отляво, отдолу и отдясно да са в близката равнина. camTopLeft/BottomRightScreen са ъгловите точки на екрана, така че z-разстоянието от очите е camTopLeftScreen.z. И за да изчислим параметрите на близката равнина, имаме нужда от z-разстояние от camZNear, така че трябва да умножим тези точки с camZNear/camTopLeftScreen.z. Това умножение означава, че мащабираме ъгловите точки в посока z на координатната система на камерата. Нека да видя дали мога да добавя това към чертежа. - person Andreas Haferburg; 02.06.2013
comment
Съжалявам, под camTopLeft/BottomRightScreen имах предвид camTopLeftScreen или camBottomRightScreen, няма нищо общо с разделянето. - person Andreas Haferburg; 02.06.2013
comment
Благодаря за точното обяснение по втория въпрос. Относно първото, не съм много сигурен дали все още го получавам ptoprely, така че ще взема пример от моя страна. Да приемем, че за първоначална потребителска позиция A параметрите „ляво/дясно“ на пресечената точка се оказват -0,25/0,25. Въпреки това, когато потребителят се придвижи по-далеч, лявото/дясното, както в горния случай, разделено на Z става -0,15/0,15. Така че кутия, която по-рано е заемала по-малка част, ще заема повече площ и ще се появи, за да стане по-голяма на екрана, когато потребителят се върне назад. - person user1240679; 02.06.2013
comment
Сравнявайки това със сценария от реалния свят, където размерът на обектите намалява, когато потребителят се движи назад, изглежда има нещо, което пропускам. Защо обектите на екрана трябва да стават по-големи по размер на екрана с увеличаване на Z? - person user1240679; 02.06.2013
comment
нека да продължим тази дискусия в чата - person Andreas Haferburg; 02.06.2013
comment
@AndreasHaferburg Опитвам се да внедря кода ви във вертекс шейдър в Quartz Composer. Използвам някои константи въз основа на пикселите на милиметър на моя екран. Пропускам стъпката на отрицателно мащабиране, която е специфична за Kinect. Трябва ли да завърша с gl_Position = mvpCube * gl_Vertex; - person David Braun; 12.10.2014
comment
@DavidBraun Звучи разумно, това ще замени glLoadMatrix. Ако е необходимо, може би бихте могли да отворите отделен въпрос и да го свържете тук. - person Andreas Haferburg; 12.10.2014
comment
Добри новини, успях да внедря кода на Kooima в Quartz. Той изгражда продуктовата матрица на пресечена точка, ротация и транслация. Наричам тази матрица m. Завършвам моя шейдър Quartz Vertex с gl_Position = m * gl_ModelViewMatrix * gl_Vertex; - person David Braun; 12.10.2014

Най-доброто обяснение за това как да използвате glFrustum за приложения за проследяване на главата, което можете да намерите, е в тази статия на Робърт Коима, наречена обобщена перспективна проекция:

http://csc.lsu.edu/~kooima/pdfs/gen-perspective.pdf

Освен това ви позволява просто да използвате стерео прожекции, просто трябва да превключвате между лява и дясна камера!

person linello    schedule 03.07.2013
comment
Трябваше да захапя куршума по-рано и да преработя този документ. Кодът всъщност беше много лесен за изпълнение. Благодаря за споделянето! - person David Braun; 12.10.2014