| // Copyright 2013 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| uniform FrameInfo { | |
| mat4 mvp; | |
| float enable_skinning; | |
| float joint_texture_size; | |
| } | |
| frame_info; | |
| uniform sampler2D joints_texture; | |
| // This attribute layout is expected to be identical to `SkinnedVertex` within | |
| // `impeller/scene/importer/scene.fbs`. | |
| in vec3 position; | |
| in vec3 normal; | |
| in vec4 tangent; | |
| in vec2 texture_coords; | |
| in vec4 color; | |
| in vec4 joints; | |
| in vec4 weights; | |
| out vec3 v_position; | |
| out mat3 v_tangent_space; | |
| out vec2 v_texture_coords; | |
| out vec4 v_color; | |
| const int kMatrixTexelStride = 4; | |
| mat4 GetJoint(float joint_index) { | |
| // The size of one texel in UV space. The joint texture should always be | |
| // square, so the answer is the same in both dimensions. | |
| float texel_size_uv = 1 / frame_info.joint_texture_size; | |
| // Each joint matrix takes up 4 pixels (16 floats), so we jump 4 pixels per | |
| // joint matrix. | |
| float matrix_start = joint_index * kMatrixTexelStride; | |
| // The texture space coordinates at the start of the matrix. | |
| float x = mod(matrix_start, frame_info.joint_texture_size); | |
| float y = floor(matrix_start / frame_info.joint_texture_size); | |
| // Nearest sample the middle of each the texel by adding `0.5 * texel_size_uv` | |
| // to both dimensions. | |
| y = (y + 0.5) * texel_size_uv; | |
| mat4 joint = | |
| mat4(texture(joints_texture, vec2((x + 0.5) * texel_size_uv, y)), | |
| texture(joints_texture, vec2((x + 1.5) * texel_size_uv, y)), | |
| texture(joints_texture, vec2((x + 2.5) * texel_size_uv, y)), | |
| texture(joints_texture, vec2((x + 3.5) * texel_size_uv, y))); | |
| return joint; | |
| } | |
| void main() { | |
| mat4 skin_matrix; | |
| if (frame_info.enable_skinning == 1) { | |
| skin_matrix = | |
| GetJoint(joints.x) * weights.x + GetJoint(joints.y) * weights.y + | |
| GetJoint(joints.z) * weights.z + GetJoint(joints.w) * weights.w; | |
| } else { | |
| skin_matrix = mat4(1); // Identity matrix. | |
| } | |
| gl_Position = frame_info.mvp * skin_matrix * vec4(position, 1.0); | |
| v_position = gl_Position.xyz; | |
| vec3 lh_tangent = (skin_matrix * vec4(tangent.xyz * tangent.w, 0.0)).xyz; | |
| vec3 out_normal = (skin_matrix * vec4(normal, 0.0)).xyz; | |
| v_tangent_space = mat3(frame_info.mvp) * | |
| mat3(lh_tangent, cross(out_normal, lh_tangent), out_normal); | |
| v_texture_coords = texture_coords; | |
| v_color = color; | |
| } |