// FIXME: Temporary fix! precision highp float; //////////////////////////////////////////////////////////////////////////////// // // Defines // // Maximum number of bones of animated models #define BBMOD_MAX_BONES 128 // Maximum number of vec4 uniforms for dynamic batch data #define BBMOD_MAX_BATCH_VEC4S 192 //////////////////////////////////////////////////////////////////////////////// // // Attributes // attribute vec4 in_Position; attribute vec3 in_Normal; attribute vec2 in_TextureCoord0; attribute vec4 in_TangentW; attribute vec4 in_BoneIndex; attribute vec4 in_BoneWeight; //////////////////////////////////////////////////////////////////////////////// // // Uniforms // uniform vec2 bbmod_TextureOffset; uniform vec2 bbmod_TextureScale; uniform vec4 bbmod_Bones[2 * BBMOD_MAX_BONES]; //////////////////////////////////////////////////////////////////////////////// // // Varyings // varying vec3 v_vVertex; varying vec2 v_vTexCoord; varying mat3 v_mTBN; varying vec4 v_vPosition; varying vec4 v_vPosShadowmap; //////////////////////////////////////////////////////////////////////////////// // // Includes // vec3 QuaternionRotate(vec4 q, vec3 v) { return (v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v)); } vec3 DualQuaternionTransform(vec4 real, vec4 dual, vec3 v) { return (QuaternionRotate(real, v) + 2.0 * (real.w * dual.xyz - dual.w * real.xyz + cross(real.xyz, dual.xyz))); } /// @desc Transforms vertex and normal by animation and/or batch data. /// /// @param vertex Variable to hold the transformed vertex. /// @param normal Variable to hold the transformed normal. /// @param tangent Variable to hold the transformed tangent. /// @param bitangent Variable to hold the transformed bitangent. void Transform( inout vec4 vertex, inout vec3 normal, inout vec3 tangent, inout vec3 bitangent) { // Source: // https://www.cs.utah.edu/~ladislav/kavan07skinning/kavan07skinning.pdf // https://www.cs.utah.edu/~ladislav/dq/dqs.cg ivec4 i = ivec4(in_BoneIndex) * 2; ivec4 j = i + 1; vec4 real0 = bbmod_Bones[i.x]; vec4 real1 = bbmod_Bones[i.y]; vec4 real2 = bbmod_Bones[i.z]; vec4 real3 = bbmod_Bones[i.w]; vec4 dual0 = bbmod_Bones[j.x]; vec4 dual1 = bbmod_Bones[j.y]; vec4 dual2 = bbmod_Bones[j.z]; vec4 dual3 = bbmod_Bones[j.w]; if (dot(real0, real1) < 0.0) { real1 *= -1.0; dual1 *= -1.0; } if (dot(real0, real2) < 0.0) { real2 *= -1.0; dual2 *= -1.0; } if (dot(real0, real3) < 0.0) { real3 *= -1.0; dual3 *= -1.0; } vec4 blendReal = real0 * in_BoneWeight.x + real1 * in_BoneWeight.y + real2 * in_BoneWeight.z + real3 * in_BoneWeight.w; vec4 blendDual = dual0 * in_BoneWeight.x + dual1 * in_BoneWeight.y + dual2 * in_BoneWeight.z + dual3 * in_BoneWeight.w; float len = length(blendReal); blendReal /= len; blendDual /= len; vertex = vec4(DualQuaternionTransform(blendReal, blendDual, vertex.xyz), 1.0); normal = QuaternionRotate(blendReal, normal); tangent = QuaternionRotate(blendReal, tangent); bitangent = QuaternionRotate(blendReal, bitangent); vertex = gm_Matrices[MATRIX_WORLD] * vertex; normal = normalize((gm_Matrices[MATRIX_WORLD] * vec4(normal, 0.0)).xyz); tangent = normalize((gm_Matrices[MATRIX_WORLD] * vec4(tangent, 0.0)).xyz); bitangent = normalize((gm_Matrices[MATRIX_WORLD] * vec4(bitangent, 0.0)).xyz); } //////////////////////////////////////////////////////////////////////////////// // // Main // void main() { vec4 position = in_Position; vec3 normal = in_Normal; vec3 tangent = in_TangentW.xyz; vec3 bitangent = cross(normal, tangent) * in_TangentW.w; Transform(position, normal, tangent, bitangent); vec4 positionWVP = gm_Matrices[MATRIX_PROJECTION] * (gm_Matrices[MATRIX_VIEW] * position); v_vVertex = position.xyz; gl_Position = positionWVP; v_vPosition = positionWVP; v_vTexCoord = bbmod_TextureOffset + in_TextureCoord0 * bbmod_TextureScale; v_mTBN = mat3(tangent, bitangent, normal); }