كيف يمكنني استخدام ناقل الجاذبية لتحويل المشهد بشكل صحيح للواقع المعزز؟

StackOverflow https://stackoverflow.com/questions/2541668

  •  23-09-2019
  •  | 
  •  

سؤال

أحاول معرفة كيفية الحصول على كائن OpenGL المحدد ليتم عرضه بشكل صحيح وفقًا لاتجاه الجهاز (أي ، وفقًا لمتجه الجاذبية من مقياس التسارع ، والتوجه من البوصلة).

يحتوي مشروع عينة Glgravity على مثال يشبه هذا تقريبًا (على الرغم من تجاهل العنوان) ، ولكنه يحتوي على بعض الخلل. على سبيل المثال ، يقفز Teapot 180deg حيث تعبر زاوية عرض الجهاز الأفق ، كما أنه يدور بشكل زاحف إذا قمت بميل الجهاز من الصورة إلى مشهد طبيعي. هذا جيد لسياق هذا التطبيق ، لأنه يظهر فقط كائنًا ولا يهم أنه يقوم بهذه الأشياء. ولكن هذا يعني أن الكود لا يعمل عندما تحاول محاكاة عرض الحياة الحقيقية لكائن OpenGL وفقًا لتوجه الجهاز. ما يحدث هو أنه يعمل تقريبًا ، لكن دوران العنوان الذي تطبقه من البوصلة "تالفة" من خلال الدورات الإضافية الزائفة التي شوهدت في مشروع مثال Glgravity.

هل يمكن لأي شخص أن يوفر رمزًا عينة يوضح كيفية ضبط اتجاه الجهاز بشكل صحيح (أي متجه الجاذبية) ، أو لإصلاح مثال glgravity حتى لا يتضمن تغييرات العنوان الزائفة؟

//Clear matrix to be used to rotate from the current referential to one based on the gravity vector
bzero(matrix, sizeof(matrix));
matrix[3][3] = 1.0;

//Setup first matrix column as gravity vector
matrix[0][0] = accel[0] / length;
matrix[0][1] = accel[1] / length;
matrix[0][2] = accel[2] / length;

//Setup second matrix column as an arbitrary vector in the plane perpendicular to the gravity vector {Gx, Gy, Gz} defined by by the equation "Gx * x + Gy * y + Gz * z = 0" in which we arbitrarily set x=0 and y=1
matrix[1][0] = 0.0;
matrix[1][1] = 1.0;
matrix[1][2] = -accel[1] / accel[2];
length = sqrtf(matrix[1][0] * matrix[1][0] + matrix[1][1] * matrix[1][1] + matrix[1][2] * matrix[1][2]);
matrix[1][0] /= length;
matrix[1][1] /= length;
matrix[1][2] /= length;

//Setup third matrix column as the cross product of the first two
matrix[2][0] = matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1];
matrix[2][1] = matrix[1][0] * matrix[0][2] - matrix[1][2] * matrix[0][0];
matrix[2][2] = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];

//Finally load matrix
glMultMatrixf((GLfloat*)matrix);

إليك توضيحًا يوضح كيفية الحصول على الارتفاع والإمالة اللازمة لمحلول Glulookat كما هو موضح في إجابتي الأخيرة:

// elevation comes from z component (0 = facing horizon)
elevationRadians = asin(gravityVector.z / Vector3DMagnitude(gravityVector));

// tilt is how far screen is from vertical, looking along z axis
tiltRadians = atan2(-gravityVector.y, -gravityVector.x) - M_PI_2;

متابعة اقتراح كريس: لست متأكدًا مما إذا كنت قد حصلت على كل هذا صحيح بسبب اختلاف اتفاقيات الصف/الأعمدة واتجاه CW أو CCW. ومع ذلك ، فإن الرمز التالي هو ما توصلت إليه:

Vector3D forward = Vector3DMake(0.0f, 0.0f, -1.0f);

// Multiply it by current rotation matrix to get teapot direction
Vector3D direction;     
direction.x = matrix[0][0] * forward.x + matrix[1][0] * forward.y + matrix[2][0] * forward.z;
direction.y = matrix[0][1] * forward.x + matrix[1][1] * forward.y + matrix[2][1] * forward.z;
direction.z = matrix[0][2] * forward.x + matrix[1][2] * forward.y + matrix[2][2] * forward.z;

heading = atan2(direction.z, direction.x) * 180 / M_PI;

// Use this heading to adjust the teapot direction back to keep it fixed
// Rotate about vertical axis (Y), as it is a heading adjustment
glRotatef(heading, 0.0, 1.0, 0.0);

عندما أقوم بتشغيل هذا الرمز ، يبدو أن سلوك إبريق الشاي "تحسن" على سبيل المثال. لم يعد الرأس يقلب 180deg عندما يتم عرض شاشة الجهاز (في عرض الصورة) للأمام/للخلف من خلال الاستقامة. ومع ذلك ، فإنه لا يزال يجعل القفزات الرئيسية في العنوان عندما يتم وضع الجهاز (في عرض المناظر الطبيعية) إلى الأمام/الخلف. لذلك شيء ليس صحيحا. إنه يشير إلى أن الحساب أعلاه للعنصر الفعلي غير صحيح ...

لا يوجد حل صحيح

نصائح أخرى

لقد وجدت أخيرًا حلًا يعمل. :-)

لقد أسقطت نهج مصفوفة الدوران ، وبدلاً من ذلك اعتمدت glulookat. لجعل هذا العمل ، تحتاج إلى معرفة الجهاز "الارتفاع" (زاوية العرض بالنسبة إلى الأفق ، أي 0 في Horizon ، +90 Overhead) ، و "Tilt" للكاميرا (إلى أي مدى يبعد الجهاز عن طائرة X/Y IE . 0 عندما يكون العمودي/الصورة ، +/- 90 عندما يكون الأفقي/المشهد) ، وكلاهما يتم الحصول عليهما من مكونات متجه الجاذبية.

Vector3D eye, scene, up;
CGFloat distanceFromScene = 0.8;
// Adjust eye position for elevation (y/z)
eye.x = 0;
eye.y = distanceFromScene * -sin(elevationRadians); // eye position goes down as elevation angle goes up
eye.z = distanceFromScene * cos(elevationRadians);  // z position is maximum when elevation is zero 
// Lookat point is origin
scene = Vector3DMake(0, 0, 0); // Scene is at origin
// Camera tilt - involves x/y plane only - arbitrary vector length
up.x = sin(tiltRadians);
up.y = cos(tiltRadians);
up.z = 0;

ثم يمكنك فقط تطبيق تحول Glulookat ، وتدوير المشهد أيضًا وفقًا للعنصر الجهاز.

// Adjust view for device orientation
gluLookAt(eye.x, eye.y, eye.z, scene.x, scene.y, scene.z, up.x, up.y, up.z);
// Apply device heading to scene
glRotatef(currentHeadingDegrees, 0.0, 1.0, 0.0);

حاول تدوير الكائن اعتمادًا على قيم تسريع iPhone.

float angle = -atan2(accelX, accelY);

glPushMatrix();     
glTranslatef(centerPoint.x, centerPoint.y, 0);
glRotatef(angle, 0, 0, 1);
glTranslatef(-centerPoint.x, -centerPoint.y, 0);
glPopMatrix();

حيث CenterPoint هو النقطة الوسط الكائن.

oo ، لطيف.

يبدو أن glgravity يحصل على كل شيء بشكل صحيح باستثناء Yaw. هذا ما سأحاوله. افعل كل ما يفعله glgravity ، ثم هذا:

عرض ناقل في الاتجاه الذي تريد إبريق الشاي لوجهه ، باستخدام البوصلة أو أي شيء تختاره. ثم اضرب متجه "إلى الأمام" بواسطة مصفوفة الدوران الحالية في إبريق الشاي ، والتي ستمنحك الاتجاه إبريق الشاي هو مواجهة. قم بتسوية المتجهات إلى الطائرة الأفقية واتخذ الزاوية بينهما.

هذه الزاوية هي Yaw التصحيحية. ثم فقط glRotatef به.

سواء كانت بوصلة 3GS موثوقة وقوية بما يكفي حتى تعمل هذا الأمر. البوصلات الطبيعية لا تعمل عندما يكون المتجه الشمالي عموديًا على وجههم. لكنني جربت تطبيق Maps على 3GS لزميلي في العمل ويبدو أنه يتعامل ، لذلك ربما يكون لديهم حل ميكانيكي هناك. إن معرفة ما يفعله الجهاز فعليًا سيساعد على تفسير النتائج التي يقدمها.

تأكد من اختبار تطبيقك في القطبين الشمالي والجنوبي بمجرد الانتهاء. :-)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top