it-swarm.dev

الخلط بين C++ وترتيب مصفوفة OpenGL (صف رئيسي مقابل عمود رئيسي)

أشعر بالحيرة بشكل كبير بشأن تعريفات المصفوفة. لدي فئة مصفوفة ، تحمل float[16] والتي افترضت أنها صف رئيسي ، بناءً على الملاحظات التالية:

float matrixA[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
float matrixB[4][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 }, { 12, 13, 14, 15 } };

كل من matrixA و matrixB لديهما نفس التخطيط الخطي في الذاكرة (أي كل الأرقام مرتبة). وفقًا لـ http://en.wikipedia.org/wiki/Row-major_order يشير هذا إلى تخطيط رئيسي للصف.

matrixA[0] == matrixB[0][0];
matrixA[3] == matrixB[0][3];
matrixA[4] == matrixB[1][0];
matrixA[7] == matrixB[1][3];

لذلك ، matrixB[0] = الصف 0 ، matrixB[1] = الصف 1 ، إلخ. مرة أخرى ، يشير هذا إلى تخطيط الصف الرئيسي.

تأتي مشكلتي/الارتباك عندما أقوم بإنشاء مصفوفة ترجمة تبدو كما يلي:

1, 0, 0, transX
0, 1, 0, transY
0, 0, 1, transZ
0, 0, 0, 1

التي وضعت في الذاكرة مثل ، { 1, 0, 0, transX, 0, 1, 0, transY, 0, 0, 1, transZ, 0, 0, 0, 1 }.

ثم عندما أتصل بـ glUniformMatrix4fv ، أحتاج إلى تعيين علامة النقل على GL_FALSE ، للإشارة إلى أنه عمود رئيسي ، وإلا فإن التحويلات مثل الترجمة/النطاق وما إلى ذلك لا يتم تطبيقها بشكل صحيح:

إذا كان transpos هو GL_FALSE ، فمن المفترض أن يتم توفير كل مصفوفة بترتيب العمود الرئيسي. إذا كان transpos هو GL_TRUE ، فمن المفترض أن يتم توفير كل مصفوفة في ترتيب الصفوف الرئيسية.

لماذا تحتاج المصفوفة الخاصة بي ، والتي تبدو صفًا رئيسيًا ، إلى تمرير OpenGL كعمود رئيسي؟

66
Mark Ingram

لا يصف تدوين المصفوفة المستخدم في وثائق opengl تخطيط في الذاكرة لمصفوفات OpenGL

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

تحتوي مصفوفات OpenGL على نفس تخطيط الذاكرة مثل مصفوفات DirectX .

x.x x.y x.z 0
y.x y.y y.z 0
z.x z.y z.z 0
p.x p.y p.z 1

أو

{ x.x x.y x.z 0 y.x y.y y.z 0 z.x z.y z.z 0 p.x p.y p.z 1 }
  • x و y و z هي ناقلات مكونة من ثلاثة مكونات تصف نظام إحداثي المصفوفة (نظام الإحداثيات المحلي ضمن نظام الإحداثيات العالمي).

  • p عبارة عن ناقل مكون من ثلاثة مكونات يصف أصل نظام إحداثيات المصفوفة.

مما يعني أنه يجب وضع مصفوفة الترجمة في ذاكرة مثل هذا:

{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 }.

اترك الأمر عند هذا الحد ، وينبغي أن يكون الباقي سهلاً.

--- الاقتباس من opengl القديم faq--


9.005 هل تعتبر مصفوفات OpenGL عمودًا رئيسيًا أم رئيسيًا؟

لأغراض البرمجة ، تكون مصفوفات OpenGL عبارة عن صفائف ذات قيمة 16 مع موجهات أساسية موضوعة بشكل متواصل في الذاكرة. تحتل مكونات الترجمة العناصر 13 و 14 و 15 من المصفوفة المكونة من 16 عنصرًا ، حيث يتم ترقيم المؤشرات من 1 إلى 16 كما هو موضح في القسم 2.11.2 من مواصفات OpenGL 2.1.

العمود الرئيسي مقابل الصف الرئيسي هو محض اصطلاحي. لاحظ أن مصفوفة ما بعد الضرب بمصفوفات العمود الرئيسي تنتج نفس النتيجة مثل مصفوفة الضرب المسبق بمصفوفات الصفوف الرئيسية. تستخدم مواصفات OpenGL والدليل المرجعي لـ OpenGL كلاً من الأعمدة الرئيسية. يمكنك استخدام أي تدوين ، طالما هو منصوص عليه بوضوح.

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


61
SigTerm

لتلخيص إجابات SigTerm و dsharlet: الطريقة المعتادة لتحويل ناقل في GLSL هي مضاعفة المتجه الأيسر بمصفوفة التحويل:

mat4 T; vec4 v; vec4 v_transformed; 
v_transformed = T*v;

لكي يعمل ذلك ، تتوقع OpenGL أن يكون تخطيط الذاكرة لـ T ، كما هو موضح بواسطة SigTerm ،

{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 }

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

v_transformed = v*T;

التي لا تسفر عن النتيجة الصحيحة إلا إذا تم تبديل T ، أي أن لديها تخطيط

{ 1, 0, 0, transX, 0, 1, 0, transY, 0, 0, 1, transZ, 0, 0, 0, 1 }

(أي "الصف الرئيسي"). نظرًا لأنك قدمت بالفعل التنسيق الصحيح إلى تظليلك ، أي الصف رئيسي ، فليس من الضروري تعيين علامة transpose من glUniform4v.

49
Roberto

أنت تتعامل مع قضيتين منفصلتين.

أولاً ، الأمثلة الخاصة بك تتعامل مع تخطيط الذاكرة. صفيف [4] [4] الخاص بك هو صف رئيسي لأنك استخدمت الاتفاقية التي أنشأتها صفائف C متعددة الأبعاد لمطابقة صفيفك الخطي.

المسألة الثانية هي مسألة اتفاقية لكيفية تفسير المصفوفات في برنامجك. يتم استخدام {glUniformMatrix4fv لتعيين معلمة تظليل. ما إذا كان يتم حساب التحويل الخاص بك للحصول على {صف متجه أو عمود متجه التحويل هو كيفية استخدام المصفوفة في رمز التظليل الخاص بك. نظرًا لأنك تحتاج إلى استخدام متجهات الأعمدة ، أفترض أن كود التظليل الخاص بك يستخدم المصفوفة A وموجه الأعمدة x لحساب x ' = فأس.

أود القول أن وثائق glUniformMatrix مربكة. وصف المعلمة transpos هو طريقة ملتوية حقًا لمجرد قول أن المصفوفة يتم نقلها أو لا. تقوم OpenGL نفسها بنقل تلك البيانات إلى تظليلك ، سواء أكنت ترغب في نقلها أم لا ، فهي مسألة تقليدية يجب أن تنشئها لبرنامجك.

يحتوي هذا الرابط على مزيد من المناقشة الجيدة: http://steve.hollasch.net/cgindex/math/matrix/column-vec.html

14
dsharlet