ฉันพยายามทำให้ตัวละครน่าสนใจทำงานบน Android
แนวคิดนี้ค่อนข้างวานิลลา: ฉันมีเมทริกซ์ที่น่าสนใจและด้วยจุดสุดยอดแต่ละอันฉันจะส่งดัชนีเมทริกซ์ได้ถึงสี่และน้ำหนักที่สอดคล้องกันสี่ประการ ฉันรวมพวกมันไว้ในส่วนยอดและนำไปใช้กับจุดสุดยอดแต่ละอัน
นี่คือสิ่งที่ฉันกำลังทำในจุดสุดยอดในเกม iOS ของฉัน (ไม่ต้องสนใจมาตรฐาน):
attribute vec4 in_pos;
attribute vec4 in_normal;
attribute vec2 in_texture_coords;
attribute vec4 in_bone_index;
attribute vec4 in_bone_weight;
varying vec2 fs_texture_coords;
uniform mat4 world_view_projection;
uniform mat4 bones[@bind_matrix_count];
void main()
{
// Skinning
vec4 transformed_pos =
((in_pos * bones[int(in_bone_index.x)]) * in_bone_weight.x) +
((in_pos * bones[int(in_bone_index.y)]) * in_bone_weight.y) +
((in_pos * bones[int(in_bone_index.z)]) * in_bone_weight.z) +
((in_pos * bones[int(in_bone_index.w)]) * in_bone_weight.w);
gl_Position = world_view_projection * transformed_pos;
fs_texture_coords = in_texture_coords;
}
และใช้งานได้ดีทีเดียว อย่างไรก็ตามด้วยรหัสเดียวกันใน Android ในอุปกรณ์บางเครื่อง (โดยเฉพาะ Nexus 7 2013) คุณจะไม่สามารถเข้าถึงuniform
ดัชนีที่ไม่คงที่ได้ คุณไม่สามารถทำสิ่งนี้ได้:
bones[int(in_bone_index.w)]
เพราะbones[some_non_constant]
ได้รับการประเมินเสมอว่าbones[0]
ซึ่งไม่สนุกเลย สิ่งที่แย่ที่สุดคือคอมไพเลอร์ shader รวบรวมสิ่งนี้อย่างมีความสุข
ผู้ชายคนนี้ดูเหมือนจะมีปัญหาเดียวกัน เขาแก้ไขมันด้วยการเข้าถึงเครื่องแบบในฐานะเวกเตอร์แทนที่จะเป็นเมทริกซ์ ฉันทำแบบเดียวกันและในความเป็นจริงมันก็ใช้งานได้!
attribute vec4 in_pos;
attribute vec4 in_normal;
attribute vec2 in_texture_coords;
attribute vec4 in_bone_index;
attribute vec4 in_bone_weight;
varying vec2 fs_texture_coords;
uniform mat4 world_view_projection;
uniform vec4 bones[@bind_matrix_count * 4]; // four vec4's for each matrix
void main()
{
// Skinning
mat4 skin_0 = mat4(
bones[4 * int(in_bone_index.x) + 0],
bones[4 * int(in_bone_index.x) + 1],
bones[4 * int(in_bone_index.x) + 2],
bones[4 * int(in_bone_index.x) + 3]);
mat4 skin_1 = mat4(
bones[4 * int(in_bone_index.y) + 0],
bones[4 * int(in_bone_index.y) + 1],
bones[4 * int(in_bone_index.y) + 2],
bones[4 * int(in_bone_index.y) + 3]);
mat4 skin_2 = mat4(
bones[4 * int(in_bone_index.z) + 0],
bones[4 * int(in_bone_index.z) + 1],
bones[4 * int(in_bone_index.z) + 2],
bones[4 * int(in_bone_index.z) + 3]);
mat4 skin_3 = mat4(
bones[4 * int(in_bone_index.w) + 0],
bones[4 * int(in_bone_index.w) + 1],
bones[4 * int(in_bone_index.w) + 2],
bones[4 * int(in_bone_index.w) + 3]);
vec4 transformed_pos =
((in_pos * skin_0) * in_bone_weight.x) +
((in_pos * skin_1) * in_bone_weight.y) +
((in_pos * skin_2) * in_bone_weight.z) +
((in_pos * skin_3) * in_bone_weight.w);
gl_Position = world_view_projection * transformed_pos;
fs_texture_coords = in_texture_coords;
}
แต่ฉันคิดว่านี่เป็นโอกาส uniform
s ไม่ได้ตั้งใจให้เข้าถึงแบบสุ่มดังนั้นฉันจึงกลัวว่า "เทคนิค" นี้จะไม่ทำงานในทุกอุปกรณ์
ผู้ชายคนนี้ผ่านการฝึกอบรมของเขาเป็นพื้นผิวซึ่งเป็นความคิดที่ดีงาม ฉันสร้างพื้นผิว 4x32 OES_texture_float โดยที่เท็กเซลแต่ละตัวเป็นแถวเมทริกซ์และแต่ละแถวของพื้นผิวนั้นเป็นเมทริกซ์ทั้งหมด ฉันเข้าใช้งานเช่นนี้:
attribute vec4 in_pos;
attribute vec4 in_normal;
attribute vec2 in_texture_coords;
attribute vec4 in_bone_index;
attribute vec4 in_bone_weight;
varying vec2 fs_texture_coords;
uniform mat4 world_view_projection; // A texture!
uniform sampler2D bones;
void main()
{
// Skinning
mat4 bone0 = mat4(
texture2D(bones, vec2(0.00, in_bone_index.x / 32.0)),
texture2D(bones, vec2(0.25, in_bone_index.x / 32.0)),
texture2D(bones, vec2(0.50, in_bone_index.x / 32.0)),
texture2D(bones, vec2(0.75, in_bone_index.x / 32.0)));
mat4 bone1 = mat4(
texture2D(bones, vec2(0.00, in_bone_index.y / 32.0)),
texture2D(bones, vec2(0.25, in_bone_index.y / 32.0)),
texture2D(bones, vec2(0.50, in_bone_index.y / 32.0)),
texture2D(bones, vec2(0.75, in_bone_index.y / 32.0)));
mat4 bone2 = mat4(
texture2D(bones, vec2(0.00, in_bone_index.z / 32.0)),
texture2D(bones, vec2(0.25, in_bone_index.z / 32.0)),
texture2D(bones, vec2(0.50, in_bone_index.z / 32.0)),
texture2D(bones, vec2(0.75, in_bone_index.z / 32.0)));
mat4 bone3 = mat4(
texture2D(bones, vec2(0.00, in_bone_index.w / 32.0)),
texture2D(bones, vec2(0.25, in_bone_index.w / 32.0)),
texture2D(bones, vec2(0.50, in_bone_index.w / 32.0)),
texture2D(bones, vec2(0.75, in_bone_index.w / 32.0)));
vec4 transformed_pos =
((in_pos * bone0) * in_bone_weight.x) +
((in_pos * bone1) * in_bone_weight.y) +
((in_pos * bone2) * in_bone_weight.z) +
((in_pos * bone3) * in_bone_weight.w);
gl_Position = world_view_projection * transformed_pos;
fs_texture_coords = in_texture_coords;
}
ในความเป็นจริงมันใช้งานได้ดี ... จนกระทั่งฉันลองใช้กับ Galaxy Note 2 ของฉันในครั้งนี้ผู้รวบรวมบ่นว่าฉันไม่สามารถใช้texture2D
กับจุดสุดยอดได้!
ดังนั้นสิ่งที่ฉันกำลังทำคือการตรวจสอบว่า GPU รองรับการเข้าถึงพื้นผิวบน Shader ที่ยอดและถ้ามันรองรับ OES_texture_float ถ้าเป็นเช่นนั้นฉันใช้วิธีพื้นผิว หากไม่เป็นเช่นนั้นฉันใช้วิธีเวกเตอร์
อย่างไรก็ตามวิธีเนื้อสัมผัสไม่พร้อมใช้งานบนแพลตฟอร์มทั้งหมดและวิธีการแบบเวกเตอร์ทำงานโดยบังเอิญ ฉันต้องการทราบว่ามีวิธีที่จะผ่านการฝึกอบรมที่น่าสนใจของฉันไปยัง Shader ที่ซึ่งทำงานบนอุปกรณ์ทั้งหมดได้อย่างน่าเชื่อถือ
ฉันสามารถมีความต้องการขั้นต่ำของระบบปฏิบัติการที่สมเหตุสมผลเช่น Android 4.1 ขึ้นไป แต่ฉันต้องการมีวิธีแก้ไขปัญหาที่ทำงานบนอุปกรณ์ทั้งหมดที่ตรงตามข้อกำหนดเหล่านั้น