UNPKG

load-collada-dae

Version:

Load the WebGL graphics buffer data from a collada .dae model and return a draw command that accepts options

135 lines (112 loc) 4.51 kB
module.exports = generateVertexShader // TODO: Add comments // TODO: Add documentation // - dual quaternion linear blending // - conditional texturing function generateVertexShader (opts) { var textureVars = '' var varyingStatement = '' if (opts.texture) { textureVars = ` attribute vec2 aTextureCoord; varying vec2 vTextureCoord; ` varyingStatement = ` vTextureCoord = aTextureCoord; ` } // TODO: Optimize default shader after benchmarks are in place var vertexShader = ` attribute vec3 aVertexPosition; attribute vec3 aVertexNormal; uniform bool uUseLighting; uniform vec3 uAmbientColor; uniform vec3 uLightingDirection; uniform vec3 uDirectionalColor; varying vec3 vLightWeighting; ${textureVars} attribute vec4 aJointIndex; attribute vec4 aJointWeight; uniform vec4 boneRotQuaternions[${opts.numJoints}]; uniform vec4 boneTransQuaternions[${opts.numJoints}]; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; uniform mat3 uNMatrix; void main (void) { // Blend our dual quaternion vec4 weightedRotQuat = boneRotQuaternions[int(aJointIndex.x)] * aJointWeight.x + boneRotQuaternions[int(aJointIndex.y)] * aJointWeight.y + boneRotQuaternions[int(aJointIndex.z)] * aJointWeight.z + boneRotQuaternions[int(aJointIndex.w)] * aJointWeight.w; vec4 weightedTransQuat = boneTransQuaternions[int(aJointIndex.x)] * aJointWeight.x + boneTransQuaternions[int(aJointIndex.y)] * aJointWeight.y + boneTransQuaternions[int(aJointIndex.z)] * aJointWeight.z + boneTransQuaternions[int(aJointIndex.w)] * aJointWeight.w; // Normalize our dual quaternion float xRot = weightedRotQuat[0]; float yRot = weightedRotQuat[1]; float zRot = weightedRotQuat[2]; float wRot = weightedRotQuat[3]; float rotQuatMagnitude = sqrt(xRot * xRot + yRot * yRot + zRot * zRot + wRot * wRot); weightedRotQuat = weightedRotQuat / rotQuatMagnitude; weightedTransQuat = weightedTransQuat / rotQuatMagnitude; float xR = weightedRotQuat[0]; float yR = weightedRotQuat[1]; float zR = weightedRotQuat[2]; float wR = weightedRotQuat[3]; float xT = weightedTransQuat[0]; float yT = weightedTransQuat[1]; float zT = weightedTransQuat[2]; float wT = weightedTransQuat[3]; float t0 = 2.0 * (-wT * xR + xT * wR - yT * zR + zT * yR); float t1 = 2.0 * (-wT * yR + xT * zR + yT * wR - zT * xR); float t2 = 2.0 * (-wT * zR - xT * yR + yT * xR + zT * wR); mat4 weightedMatrix = mat4( 1.0 - (2.0 * yR * yR) - (2.0 * zR * zR), (2.0 * xR * yR) + (2.0 * wR * zR), (2.0 * xR * zR) - (2.0 * wR * yR), 0, (2.0 * xR * yR) - (2.0 * wR * zR), 1.0 - (2.0 * xR * xR) - (2.0 * zR * zR), (2.0 * yR * zR) + (2.0 * wR * xR), 0, (2.0 * xR * zR) + (2.0 * wR * yR), (2.0 * yR * zR) - (2.0 * wR * xR), 1.0 - (2.0 * xR * xR) - (2.0 * yR * yR), 0, t0, t1, t2, 1 ); vec4 leftWorldSpace = weightedMatrix * vec4(aVertexPosition, 1.0); float y = leftWorldSpace.z; float z = -leftWorldSpace.y; leftWorldSpace.y = y; leftWorldSpace.z = z; if (uUseLighting) { // Dual Quaternion skinning always leads to rigid transformation matrices so // we only pass in the top left 3x3 of the modelMatrix without worrying // about transposing it // @see https://www.cs.utah.edu/~ladislav/kavan07skinning/kavan07skinning.pdf for // vertex normal transformation equation vec3 transformedNormal = (weightedMatrix * vec4(aVertexNormal, 0.0)).xyz; y = transformedNormal.z; z = -transformedNormal.y; transformedNormal.y = y; transformedNormal.z = z; // We convert our normal into column major before multiplying it with our normal matrix transformedNormal = uNMatrix * transformedNormal; float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 0.0); vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting; } else { vLightWeighting = vec3(1.0, 1.0, 1.0); } ${varyingStatement} gl_Position = uPMatrix * uMVMatrix * leftWorldSpace; } ` return vertexShader }