import { ShaderRegisterElement, ShaderRegisterCache, ShaderRegisterData } from '@awayjs/stage'; import { ShaderBase, IAnimationSet } from '@awayjs/renderer'; import { AnimationSetBase } from './AnimationSetBase'; /** * The animation data set used by skeleton-based animators, containing skeleton animation data. * * @see away.animators.SkeletonAnimator */ export class SkeletonAnimationSet extends AnimationSetBase implements IAnimationSet { private _jointsPerVertex: number; private _matricesIndex: number; /** * Returns the amount of skeleton joints that can be linked to a single vertex via skinned weight values. For GPU-base animation, the * maximum allowed value is 4. */ public get jointsPerVertex(): number { return this._jointsPerVertex; } public get matricesIndex(): number { return this._matricesIndex; } /** * Creates a new SkeletonAnimationSet object. * * @param jointsPerVertex Sets the amount of skeleton joints that can be linked to a single vertex via skinned weight values. For GPU-base animation, the maximum allowed value is 4. Defaults to 4. */ constructor(jointsPerVertex: number = 4) { super(); this._jointsPerVertex = jointsPerVertex; } /** * @inheritDoc */ public getAGALVertexCode(shader: ShaderBase, registerCache: ShaderRegisterCache, sharedRegisters: ShaderRegisterData): string { this._matricesIndex = registerCache.numUsedVertexConstants; const indexOffset0: number = this._matricesIndex; const indexOffset1: number = this._matricesIndex + 1; const indexOffset2: number = this._matricesIndex + 2; const indexStream: ShaderRegisterElement = registerCache.getFreeVertexAttribute(); shader.jointIndexIndex = indexStream.index; const weightStream: ShaderRegisterElement = registerCache.getFreeVertexAttribute(); shader.jointWeightIndex = weightStream.index; const indices: Array = [indexStream + '.x', indexStream + '.y', indexStream + '.z', indexStream + '.w']; const weights: Array = [weightStream + '.x', weightStream + '.y', weightStream + '.z', weightStream + '.w']; const temp1: ShaderRegisterElement = registerCache.getFreeVertexVectorTemp(); let dot: string = 'dp4'; let code: string = ''; const len: number = sharedRegisters.animatableAttributes.length; for (let i: number = 0; i < len; ++i) { const source: ShaderRegisterElement = sharedRegisters.animatableAttributes[i]; const target: ShaderRegisterElement = sharedRegisters.animationTargetRegisters[i]; for (let j: number = 0; j < this._jointsPerVertex; ++j) { registerCache.getFreeVertexConstant(); registerCache.getFreeVertexConstant(); registerCache.getFreeVertexConstant(); code += dot + ' ' + temp1 + '.x, ' + source + ', vc[' + indices[j] + '+' + indexOffset0 + ']\n' + dot + ' ' + temp1 + '.y, ' + source + ', vc[' + indices[j] + '+' + indexOffset1 + ']\n' + dot + ' ' + temp1 + '.z, ' + source + ', vc[' + indices[j] + '+' + indexOffset2 + ']\n' + 'mov ' + temp1 + '.w, ' + source + '.w\n' + 'mul ' + temp1 + ', ' + temp1 + ', ' + weights[j] + '\n'; // apply weight // add or mov to target. Need to write to a temp reg first, because an output can be a target if (j == 0) code += 'mov ' + target + ', ' + temp1 + '\n'; else code += 'add ' + target + ', ' + target + ', ' + temp1 + '\n'; } // switch to dp3 once positions have been transformed, from now on, it should only be vectors instead of points dot = 'dp3'; } return code; } /** * @inheritDoc */ public getAGALFragmentCode(shader: ShaderBase, registerCache: ShaderRegisterCache, shadedTarget: ShaderRegisterElement): string { return ''; } /** * @inheritDoc */ public getAGALUVCode(shader: ShaderBase, registerCache: ShaderRegisterCache, sharedRegisters: ShaderRegisterData): string { return 'mov ' + sharedRegisters.animatedUV + ',' + sharedRegisters.uvInput + '\n'; } /** * @inheritDoc */ public doneAGALCode(shader: ShaderBase): void { } }