मैं एंड्रॉइड पर काम करने वाले चरित्र स्किनिंग प्राप्त करने की कोशिश कर रहा हूं।
यह विचार काफी वैनिला है: मेरे पास मेरी स्किनिंग मैट्रिसेस हैं, और प्रत्येक शीर्ष के साथ मैं चार मैट्रिक्स इंडेक्स और चार संबंधित वेट भेजती हूं। मैं उन्हें वर्टेक्स शेडर में योग करता हूं, और उन्हें प्रत्येक वर्टेक्स पर लागू करता हूं।
यह वही है जो मैं अपने गेम के 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;
}
वास्तव में, यह बहुत अच्छा काम किया ... जब तक मैंने इसे अपने गैलेक्सी नोट 2 पर आज़माया नहीं। इस बार कंपाइलर ने शिकायत की कि मैं texture2D
वर्टेक्सर शेडर पर उपयोग नहीं कर सकता !
तो मैं क्या कर रहा हूँ जाँच कर रहा है कि क्या GPU वर्टेक्स शैडर पर बनावट एक्सेस का समर्थन करता है और यदि यह OES_texture_bloat का समर्थन करता है। यदि ऐसा होता है, तो मैं बनावट दृष्टिकोण का उपयोग कर रहा हूं। यदि ऐसा नहीं होता है, तो मैं वेक्टर दृष्टिकोण का उपयोग कर रहा हूं।
हालाँकि, बनावट दृष्टिकोण सभी प्लेटफार्मों पर उपलब्ध नहीं है, और वेक्टर दृष्टिकोण संयोग से काम कर रहा है। मैं यह जानना चाहूंगा कि क्या मेरी स्किनिंग मेट्रिसेस को वर्टेक्स शॉडर में पास करने का कोई तरीका है, जो सभी उपकरणों के लिए मज़बूती से काम करता है।
मुझे एंड्रॉइड 4.1+ की तरह न्यूनतम उचित ओएस आवश्यकताएं हो सकती हैं, लेकिन मैं एक समाधान चाहता हूं जो सभी उपकरणों पर काम करता है जो उन आवश्यकताओं को पूरा करते हैं।