@awayjs/graphics
Version:
AwayJS graphics classes
181 lines (151 loc) • 7.12 kB
text/typescript
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;
}
}