ฉันจะส่งเมทริกซ์หลายตัวไปยังจุดสุดยอดได้อย่างไร


9

ฉันกำลังฝึกอนิเมชั่นโดยใช้กระดูก / สกินนิ่ง ฉันกำลังพยายามส่งเมทริกซ์หนึ่งส่วนต่อจุดยอด ฉันนึกถึงสองแนวทางนี้

วิธีที่ 1

ฉันมีมือจับอันเดียวสำหรับเมทริกซ์กระดูกแต่ละอันเช่นนี้

u_Bone0 = GLES20.glGetUniformLocation(mProgram, "u_Bone[0]");
u_Bone1 = GLES20.glGetUniformLocation(mProgram, "u_Bone[1]");

และในการที่onDrawฉันส่งแต่ละคนไปยัง shader: GLES20.glUniformMatrix4fv(u_Bone0, 1, false, matrix0, 0);

เห็นได้ชัดว่านี่ไม่ใช่วิธีที่ดีถ้าฉันมีเมทริกซ์จำนวนมาก ความคิดที่สองของฉันที่ฉันยังไม่ได้ลองเนื่องจากมีโค้ดจำนวนมากสำหรับการปรับโครงสร้าง

วิธีที่ 2

คือการใช้glUniformMatrix4fvเพื่อส่งพวกเขาทั้งหมดในครั้งเดียว (สมมติว่าฉันมี 20 เมทริกซ์)

GLES20.glUniformMatrix4fv(u_Bones, 20, false, matrices, 0);

ที่เป็นmatrices float[16 * 20]แต่จากนั้นการปรับเปลี่ยนเมทริกซ์สำหรับแต่ละกระดูกจะค่อนข้างน่าเบื่อ ตัวอย่างเช่นถ้าฉันต้องการหาเมทริกซ์ที่ 3 ฉันต้องการบางสิ่งตามแนวของ

float[] _3rd = Arrays.copy(matrices, 3*16, 4*16);

และการประหยัดกลับคืนค่าสามารถเป็นที่น่ารำคาญยิ่งขึ้น


ฉันใช้วิธีที่ 1 ตอนนี้ แต่มันไม่ได้ดูฉลาดมาก ...

วิธีที่ดีที่สุดในการส่งเมทริกซ์หลายตัวไปยัง OpenGL ES 2 shader คืออะไร?

LE: ฉันใช้ Android ดังนั้นฉันกำลังมองหาโซลูชัน Java


แค่ sidenote: ถ้าคุณมีเมทริกซ์มากเกินไปคุณสามารถส่งพวกมันผ่าน fp texture ได้
Kromster

คำตอบ:


2

การส่งเมทริกซ์หลายตัวไปยัง shader นั้นตรงไปตรงมา:

Shader:

uniform mat4 mBones[20]; //20 matrices
.. skipped code ..
vec4 vert = vec4(vPosition, 1.0) * mBones[int(vaBoneId)];

โปรแกรม:

glUniformMatrix4fv(fShaderUnitSkeletal.uBones, 20, False, @bones20[0]); // Passing 20 matrices

การปรับเมทริกซ์สำหรับกระดูกแต่ละอันนั้นไม่เกี่ยวข้องกับวิธีที่คุณส่งพวกมันไปยัง shader คุณสามารถทำการปรับเปลี่ยนได้ง่ายขึ้นถ้าคุณทำงานกับโครงสร้างแทนอาร์เรย์ของตัวเลข

bones20: array of TMatrix; // Declare array of matrices
bones20[2] := TMatrix.Identity; //Reset 3rd matrix

1
ฉันใช้ Android / Java ดังนั้นฉันไม่สามารถใช้ "โครงสร้าง" หรือชนิดข้อมูลอื่น ๆ (ขออภัยสำหรับความคิดเห็นสั้น ๆ ฉันไม่สามารถอธิบาย ATM ได้ แต่จะกลับมาใหม่ในภายหลัง)
async

2

ฉันอยากจะแนะนำให้ใช้ VBO เติม VBO ของคุณด้วยเมทริกซ์และส่งผ่านพวกเขาโดยใช้คุณลักษณะแทนเครื่องแบบ ด้วยวิธีดังกล่าว VBO จะแจกจ่าย mat4 ใหม่ต่อการส่งผ่านจุดยอดใน shader

เมื่อคุณผูก VBO ก่อนวาด (หรือสร้าง VAO สำหรับสถานะเหล่านี้):

  • เปิดใช้งานคุณลักษณะจุดสุดยอด (glEnableVertexAttribArray)
  • ตั้งค่าตัวหารแอตทริบิวต์จุดสุดยอดเป็น 0 (glVertexAttribDivisor)
  • ตั้งค่าตัวชี้คุณลักษณะจุดสุดยอด (glVertexAttribPointer)

ดูวิธีส่ง mat4 เป็นแอตทริบิวต์: /programming/17355051/using-a-matrix-as-vertex-attribute-in-opengl3-core-profile

หวังว่านี่จะช่วยได้


1
น่าสนใจ อย่างไรก็ตามเมทริกซ์อาจเปลี่ยนค่อนข้างบ่อย (ตัวอย่างเช่นฉันอาจเพิ่มการหมุนเพิ่มเติมให้กับหนึ่งในนั้นในทุกเฟรม) พวกเขาจะไม่เหมือนเดิม VBOs เหมาะสมกับสถานการณ์นี้หรือไม่
async

ใช่คุณเพียงแค่อัปโหลดเมทริกซ์ใหม่ทุกเฟรมโดยใช้ glBufferData
Luka

0

วิธีที่ 1 สามารถขยายเพื่อใช้อาร์เรย์เพื่อสรุปจำนวนเมทริกซ์ในโค้ด: (สมมติว่า java)

int[] u_Bone=new int[NUM_MATRICES];

for(int i=0;i<u_Bone.length;i++)
   u_Bone[i]=GLES20.glGetUniformLocation(mProgram, "u_Bone["+i+"]");

และเมื่อคุณตั้งค่าเมทริกซ์คุณสามารถทำได้

for(int i=0;i<matrix.length;i++)
    GLES20.glUniformMatrix4fv(u_Bone[i], 1, false, matrix[i], 0);

ฉันลงเอยด้วยการใช้สิ่งนี้ แต่ก็ยังไม่ปรับปรุงสิ่งที่มาก แต่จนถึงตอนนี้อาจเป็นวิธีที่ดีที่สุด
async
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.