UNPKG

@awayjs/graphics

Version:
181 lines (151 loc) 7.12 kB
import { ShaderRegisterElement, ShaderRegisterCache, ShaderRegisterData } from '@awayjs/stage'; import { ShaderBase, IAnimationSet, AnimationRegisterData } from '@awayjs/renderer'; import { VertexAnimationMode } from './data/VertexAnimationMode'; import { AnimationSetBase } from './AnimationSetBase'; /** * The animation data set used by vertex-based animators, containing vertex animation state data. * * @see VertexAnimator */ export class VertexAnimationSet extends AnimationSetBase implements IAnimationSet { private _iAnimationRegisterData: AnimationRegisterData; private _numPoses: number; private _blendMode: string; /** * Returns the number of poses made available at once to the GPU animation code. */ public get numPoses(): number { return this._numPoses; } /** * Returns the active blend mode of the vertex animator object. */ public get blendMode(): string { return this._blendMode; } /** * Returns whether or not normal data is used in last set GPU pass of the vertex shader. */ // public get useNormals():boolean // { // return this._uploadNormals; // } /** * Creates a new <code>VertexAnimationSet</code> object. * * @param numPoses The number of poses made available at once to the GPU animation code. * @param blendMode Optional value for setting the animation mode of the vertex animator object. * * @see away3d.animators.data.VertexAnimationMode */ constructor(numPoses: number = 2, blendMode: string = 'absolute') { super(); this._numPoses = numPoses; this._blendMode = blendMode; } /** * @inheritDoc */ public getAGALVertexCode(shader: ShaderBase, registerCache: ShaderRegisterCache, sharedRegisters: ShaderRegisterData): string { //grab animationRegisterData from the materialpassbase or create a new one if the first time this._iAnimationRegisterData = shader.animationRegisterData; if (this._iAnimationRegisterData == null) this._iAnimationRegisterData = shader.animationRegisterData = new AnimationRegisterData(); if (this._blendMode == VertexAnimationMode.ABSOLUTE) return this.getAbsoluteAGALCode(shader, registerCache, sharedRegisters); else return this.getAdditiveAGALCode(shader, registerCache, sharedRegisters); } /** * @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 { } /** * Generates the vertex AGAL code for absolute blending. */ private getAbsoluteAGALCode(shader: ShaderBase, registerCache: ShaderRegisterCache, sharedRegisters: ShaderRegisterData): string { let code: string = ''; const temp1: ShaderRegisterElement = registerCache.getFreeVertexVectorTemp(); registerCache.addVertexTempUsages(temp1, 1); const temp2: ShaderRegisterElement = registerCache.getFreeVertexVectorTemp(); const regs: Array<string> = new Array<string>('.x', '.y', '.z', '.w'); let len: number = sharedRegisters.animatableAttributes.length; const constantReg: ShaderRegisterElement = registerCache.getFreeVertexConstant(); this._iAnimationRegisterData.weightsIndex = constantReg.index; this._iAnimationRegisterData.poseIndices = new Array<number>(this._numPoses); let poseInput: ShaderRegisterElement; let k: number = 0; if (len > 2) len = 2; for (let i: number = 0; i < len; ++i) { code += 'mul ' + temp1 + ', ' + sharedRegisters.animatableAttributes[i] + ', ' + constantReg + regs[0] + '\n'; for (let j: number = 1; j < this._numPoses; ++j) { poseInput = registerCache.getFreeVertexAttribute(); this._iAnimationRegisterData.poseIndices[k++] = poseInput.index; code += 'mul ' + temp2 + ', ' + poseInput + ', ' + constantReg + regs[j] + '\n'; if (j < this._numPoses - 1) //TODO this is always the case, write better? code += 'add ' + temp1 + ', ' + temp1 + ', ' + temp2 + '\n'; } code += 'add ' + sharedRegisters.animationTargetRegisters[i] + ', ' + temp1 + ', ' + temp2 + '\n'; } // add code for bitangents if tangents are used if (shader.tangentDependencies > 0 || shader.outputsNormals) { code += 'dp3 ' + temp1 + '.x, ' + sharedRegisters.animatableAttributes[2] + ', ' + sharedRegisters.animationTargetRegisters[1] + '\n' + 'mul ' + temp1 + ', ' + sharedRegisters.animationTargetRegisters[1] + ', ' + temp1 + '.x\n' + 'sub ' + sharedRegisters.animationTargetRegisters[2] + ', ' + sharedRegisters.animationTargetRegisters[2] + ', ' + temp1 + '\n'; } // // // simply write attributes to targets, do not animate them // // projection will pick up on targets[0] to do the projection // var len:number = sharedRegisters.animatableAttributes.length; // for (var i:number = 0; i < len; ++i) // code += "mov " + sharedRegisters.animationTargetRegisters[i] + ", " + sharedRegisters.animatableAttributes[i] + "\n"; return code; } /** * Generates the vertex AGAL code for additive blending. */ private getAdditiveAGALCode(shader: ShaderBase, registerCache: ShaderRegisterCache, sharedRegisters: ShaderRegisterData): string { let code: string = ''; let len: number = sharedRegisters.animatableAttributes.length; const regs: Array<string> = ['.x', '.y', '.z', '.w']; const temp1: ShaderRegisterElement = registerCache.getFreeVertexVectorTemp(); const constantReg: ShaderRegisterElement = registerCache.getFreeVertexConstant(); this._iAnimationRegisterData.weightsIndex = constantReg.index; this._iAnimationRegisterData.poseIndices = new Array<number>(this._numPoses); let poseInput: ShaderRegisterElement; let k: number = 0; if (len > 2) len = 2; code += 'mov ' + sharedRegisters.animationTargetRegisters[0] + ', ' + sharedRegisters.animatableAttributes[0] + '\n'; if (shader.normalDependencies > 0) code += 'mov ' + sharedRegisters.animationTargetRegisters[1] + ', ' + sharedRegisters.animatableAttributes[1] + '\n'; for (let i: number = 0; i < len; ++i) { for (let j: number = 0; j < this._numPoses; ++j) { poseInput = registerCache.getFreeVertexAttribute(); this._iAnimationRegisterData.poseIndices[k++] = poseInput.index; code += 'mul ' + temp1 + ', ' + poseInput + ', ' + constantReg + regs[j] + '\n' + 'add ' + sharedRegisters.animationTargetRegisters[i] + ', ' + sharedRegisters.animationTargetRegisters[i] + ', ' + temp1 + '\n'; } } if (shader.tangentDependencies > 0 || shader.outputsNormals) { code += 'dp3 ' + temp1 + '.x, ' + sharedRegisters.animatableAttributes[2] + ', ' + sharedRegisters.animationTargetRegisters[1] + '\n' + 'mul ' + temp1 + ', ' + sharedRegisters.animationTargetRegisters[1] + ', ' + temp1 + '.x\n' + 'sub ' + sharedRegisters.animationTargetRegisters[2] + ', ' + sharedRegisters.animatableAttributes[2] + ', ' + temp1 + '\n'; } return code; } }