summaryrefslogtreecommitdiff
path: root/drivers/gles3/shaders/skeleton.glsl
blob: a1e3c098f42795b0e1c22b653b13daeae3895655 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/* clang-format off */
#[modes]

mode_base_pass =
mode_blend_pass = #define MODE_BLEND_PASS

#[specializations]

MODE_2D = true
USE_BLEND_SHAPES = false
USE_SKELETON = false
USE_NORMAL = false
USE_TANGENT = false
FINAL_PASS = false
USE_EIGHT_WEIGHTS = false

#[vertex]

#include "stdlib_inc.glsl"

#ifdef MODE_2D
#define VFORMAT vec2
#else
#define VFORMAT vec3
#endif

#ifdef FINAL_PASS
#define OFORMAT vec2
#else
#define OFORMAT uvec2
#endif

// These come from the source mesh and the output from previous passes.
layout(location = 0) in highp VFORMAT in_vertex;
#ifdef MODE_BLEND_PASS
#ifdef USE_NORMAL
layout(location = 1) in highp uvec2 in_normal;
#endif
#ifdef USE_TANGENT
layout(location = 2) in highp uvec2 in_tangent;
#endif
#else // MODE_BLEND_PASS
#ifdef USE_NORMAL
layout(location = 1) in highp vec2 in_normal;
#endif
#ifdef USE_TANGENT
layout(location = 2) in highp vec2 in_tangent;
#endif
#endif // MODE_BLEND_PASS

#ifdef USE_SKELETON
#ifdef USE_EIGHT_WEIGHTS
layout(location = 10) in highp uvec4 in_bone_attrib;
layout(location = 11) in highp uvec4 in_bone_attrib2;
layout(location = 12) in mediump vec4 in_weight_attrib;
layout(location = 13) in mediump vec4 in_weight_attrib2;
#else
layout(location = 10) in highp uvec4 in_bone_attrib;
layout(location = 11) in mediump vec4 in_weight_attrib;
#endif

uniform mediump sampler2D skeleton_texture; // texunit:0
#endif

/* clang-format on */
#ifdef MODE_BLEND_PASS
layout(location = 3) in highp VFORMAT blend_vertex;
#ifdef USE_NORMAL
layout(location = 4) in highp vec2 blend_normal;
#endif
#ifdef USE_TANGENT
layout(location = 5) in highp vec2 blend_tangent;
#endif
#endif // MODE_BLEND_PASS

out highp VFORMAT out_vertex; //tfb:

#ifdef USE_NORMAL
flat out highp OFORMAT out_normal; //tfb:USE_NORMAL
#endif
#ifdef USE_TANGENT
flat out highp OFORMAT out_tangent; //tfb:USE_TANGENT
#endif

#ifdef USE_BLEND_SHAPES
uniform highp float blend_weight;
uniform lowp float blend_shape_count;
#endif

vec2 signNotZero(vec2 v) {
	return mix(vec2(-1.0), vec2(1.0), greaterThanEqual(v.xy, vec2(0.0)));
}

vec3 oct_to_vec3(vec2 oct) {
	oct = oct * 2.0 - 1.0;
	vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));
	if (v.z < 0.0) {
		v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy);
	}
	return normalize(v);
}

vec2 vec3_to_oct(vec3 e) {
	e /= abs(e.x) + abs(e.y) + abs(e.z);
	vec2 oct = e.z >= 0.0f ? e.xy : (vec2(1.0f) - abs(e.yx)) * signNotZero(e.xy);
	return oct * 0.5f + 0.5f;
}

vec4 oct_to_tang(vec2 oct_sign_encoded) {
	// Binormal sign encoded in y component
	vec2 oct = vec2(oct_sign_encoded.x, abs(oct_sign_encoded.y) * 2.0 - 1.0);
	return vec4(oct_to_vec3(oct), sign(oct_sign_encoded.y));
}

vec2 tang_to_oct(vec4 base) {
	vec2 oct = vec3_to_oct(base.xyz);
	// Encode binormal sign in y component
	oct.y = oct.y * 0.5f + 0.5f;
	oct.y = base.w >= 0.0f ? oct.y : 1.0 - oct.y;
	return oct;
}

// Our original input for normals and tangents is 2 16-bit floats.
// Transform Feedback has to write out 32-bits per channel.
// Octahedral compression requires normalized vectors, but we need to store
// non-normalized vectors until the very end.
// Therefore, we will compress our normals into 16 bits using signed-normalized
// fixed point precision. This works well, because we know that each normal
// is no larger than |1| so we can normalize by dividing by the number of blend
// shapes.
uvec2 vec4_to_vec2(vec4 p_vec) {
	return uvec2(packSnorm2x16(p_vec.xy), packSnorm2x16(p_vec.zw));
}

vec4 vec2_to_vec4(uvec2 p_vec) {
	return vec4(unpackSnorm2x16(p_vec.x), unpackSnorm2x16(p_vec.y));
}

void main() {
#ifdef MODE_2D
	out_vertex = in_vertex;

#ifdef USE_BLEND_SHAPES
#ifdef MODE_BLEND_PASS
	out_vertex = in_vertex + blend_vertex * blend_weight;
#else
	out_vertex = in_vertex * blend_weight;
#endif
#ifdef FINAL_PASS
	out_vertex = normalize(out_vertex);
#endif
#endif // USE_BLEND_SHAPES

#ifdef USE_SKELETON

#define TEX(m) texelFetch(skeleton_texture, ivec2(m % 256u, m / 256u), 0)
#define GET_BONE_MATRIX(a, b, w) mat2x4(TEX(a), TEX(b)) * w

	uvec4 bones = in_bone_attrib * uvec4(2u);
	uvec4 bones_a = bones + uvec4(1u);

	highp mat2x4 m = GET_BONE_MATRIX(bones.x, bones_a.x, in_weight_attrib.x);
	m += GET_BONE_MATRIX(bones.y, bones_a.y, in_weight_attrib.y);
	m += GET_BONE_MATRIX(bones.z, bones_a.z, in_weight_attrib.z);
	m += GET_BONE_MATRIX(bones.w, bones_a.w, in_weight_attrib.w);

	mat4 bone_matrix = mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));

	//reverse order because its transposed
	out_vertex = (vec4(out_vertex, 0.0, 1.0) * bone_matrix).xy;
#endif // USE_SKELETON

#else // MODE_2D

#ifdef USE_BLEND_SHAPES
#ifdef MODE_BLEND_PASS
	out_vertex = in_vertex + blend_vertex * blend_weight;

#ifdef USE_NORMAL
	vec3 normal = vec2_to_vec4(in_normal).xyz * blend_shape_count;
	vec3 normal_blend = oct_to_vec3(blend_normal) * blend_weight;
#ifdef FINAL_PASS
	out_normal = vec3_to_oct(normalize(normal + normal_blend));
#else
	out_normal = vec4_to_vec2(vec4(normal + normal_blend, 0.0) / blend_shape_count);
#endif
#endif // USE_NORMAL

#ifdef USE_TANGENT
	vec4 tangent = vec2_to_vec4(in_tangent) * blend_shape_count;
	vec4 tangent_blend = oct_to_tang(blend_tangent) * blend_weight;
#ifdef FINAL_PASS
	out_tangent = tang_to_oct(vec4(normalize(tangent.xyz + tangent_blend.xyz), tangent.w));
#else
	out_tangent = vec4_to_vec2(vec4((tangent.xyz + tangent_blend.xyz) / blend_shape_count, tangent.w));
#endif
#endif // USE_TANGENT

#else // MODE_BLEND_PASS
	out_vertex = in_vertex * blend_weight;

#ifdef USE_NORMAL
	vec3 normal = oct_to_vec3(in_normal);
	out_normal = vec4_to_vec2(vec4(normal * blend_weight / blend_shape_count, 0.0));
#endif
#ifdef USE_TANGENT
	vec4 tangent = oct_to_tang(in_tangent);
	out_tangent = vec4_to_vec2(vec4(tangent.rgb * blend_weight / blend_shape_count, tangent.w));
#endif
#endif // MODE_BLEND_PASS
#else // USE_BLEND_SHAPES

	// Make attributes available to the skeleton shader if not written by blend shapes.
	out_vertex = in_vertex;
#ifdef USE_NORMAL
	out_normal = in_normal;
#endif
#ifdef USE_TANGENT
	out_tangent = in_tangent;
#endif
#endif // USE_BLEND_SHAPES

#ifdef USE_SKELETON

#define TEX(m) texelFetch(skeleton_texture, ivec2(m % 256u, m / 256u), 0)
#define GET_BONE_MATRIX(a, b, c, w) mat4(TEX(a), TEX(b), TEX(c), vec4(0.0, 0.0, 0.0, 1.0)) * w

	uvec4 bones = in_bone_attrib * uvec4(3);
	uvec4 bones_a = bones + uvec4(1);
	uvec4 bones_b = bones + uvec4(2);

	highp mat4 m;
	m = GET_BONE_MATRIX(bones.x, bones_a.x, bones_b.x, in_weight_attrib.x);
	m += GET_BONE_MATRIX(bones.y, bones_a.y, bones_b.y, in_weight_attrib.y);
	m += GET_BONE_MATRIX(bones.z, bones_a.z, bones_b.z, in_weight_attrib.z);
	m += GET_BONE_MATRIX(bones.w, bones_a.w, bones_b.w, in_weight_attrib.w);

#ifdef USE_EIGHT_WEIGHTS
	bones = in_bone_attrib2 * uvec4(3);
	bones_a = bones + uvec4(1);
	bones_b = bones + uvec4(2);

	m += GET_BONE_MATRIX(bones.x, bones_a.x, bones_b.x, in_weight_attrib2.x);
	m += GET_BONE_MATRIX(bones.y, bones_a.y, bones_b.y, in_weight_attrib2.y);
	m += GET_BONE_MATRIX(bones.z, bones_a.z, bones_b.z, in_weight_attrib2.z);
	m += GET_BONE_MATRIX(bones.w, bones_a.w, bones_b.w, in_weight_attrib2.w);
#endif

	// Reverse order because its transposed.
	out_vertex = (vec4(out_vertex, 1.0) * m).xyz;
#ifdef USE_NORMAL
	vec3 vertex_normal = oct_to_vec3(out_normal);
	out_normal = vec3_to_oct(normalize((vec4(vertex_normal, 0.0) * m).xyz));
#endif // USE_NORMAL
#ifdef USE_TANGENT
	vec4 vertex_tangent = oct_to_tang(out_tangent);
	out_tangent = tang_to_oct(vec4(normalize((vec4(vertex_tangent.xyz, 0.0) * m).xyz), vertex_tangent.w));
#endif // USE_TANGENT
#endif // USE_SKELETON
#endif // MODE_2D
}

/* clang-format off */
#[fragment]

void main() {

}
/* clang-format on */