1
0
Fork 0

Update to Cubism 5 SDK for Web R1 beta1

hfjnulyz-patch-1
wada 2023-08-17 11:05:59 +09:00
parent 6971f204ce
commit ae7a189f98
34 changed files with 3968 additions and 2626 deletions

View File

@ -15,6 +15,7 @@ rules:
prettier/prettier:
- error
- singleQuote: true
trailingComma: none
camelcase: "off"
'@typescript-eslint/naming-convention':
- warn
@ -58,6 +59,8 @@ rules:
'@typescript-eslint/no-unsafe-member-access': off
'@typescript-eslint/no-unsafe-argument': off
'@typescript-eslint/no-unsafe-call': off
'@typescript-eslint/no-explicit-any': off
'@typescript-eslint/no-unused-vars': off
'no-inner-declarations': off
'no-global-assign': off
'prefer-const': warn

View File

@ -5,6 +5,32 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [5-r.1-beta.1] - 2023-08-17
### Added
* Add the function to get the ID of a given parameter.(`CubismModel.getParameterId`)
* Add the `CubismExpressionMotionManager` class.
### Changed
* Change the visibility of the `CubismId` constructor to private.
* Please use `CubismFramework.getIdManager().getId()` to get `CubismId`.
* Change the word `DrawMesh` to `DrawMeshWebGL`.
### Fixed
* Fix a bug that the value applied by multiply was not appropriate during expression transitions.
* Fix the structure of the class in renderer.
* Fix a issue where `ARRAY_BUFFER` was used on multiple targets.
* Separate shader class from `cubismrenderer` class.
* Separate the high precision mask process from the clipping mask setup process.
### Removed
* Remove several arguments of `DrawMesh` function.
## [4-r.7] - 2023-05-25
### Added
@ -182,6 +208,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Reformat code using Prettier and ESLint.
[5-r.1-beta.1]: https://github.com/Live2D/CubismWebFramework/compare/4-r.7...5-r.1-beta.1
[4-r.7]: https://github.com/Live2D/CubismWebFramework/compare/4-r.6.2...4-r.7
[4-r.6.2]: https://github.com/Live2D/CubismWebFramework/compare/4-r.6.1...4-r.6.2
[4-r.6.1]: https://github.com/Live2D/CubismWebFramework/compare/4-r.6...4-r.6.1

View File

@ -4,7 +4,7 @@
# Cubism Web Framework
Live2D Cubism 4 Editor で出力したモデルをアプリケーションで利用するためのフレームワークです。
Live2D Cubism Editor で出力したモデルをアプリケーションで利用するためのフレームワークです。
モデルを表示、操作するための各種機能を提供します。
モデルをロードするには Live2D Cubism Core ライブラリと組み合わせて使用します。
@ -17,18 +17,27 @@ Live2D Cubism 4 Editor で出力したモデルをアプリケーションで利
本 SDK を使用する前に、[ライセンス](LICENSE.md)をご確認ください。
## Cubism 5新機能や過去バージョンとの互換性について
本 SDK はCubism 5に対応した製品です。
Cubism 5 Editorに搭載された新機能のSDK対応については [こちら](https://docs.live2d.com/cubism-sdk-manual/cubism-5-new-functions/)をご確認ください。
過去バージョンのCubism SDKとの互換性については [こちら](https://docs.live2d.com/cubism-sdk-manual/compatibility-with-cubism-5/)をご確認ください。
## 開発環境
### Node.js
* 20.1.0
* 18.16.0
* 16.20.0
* 20.5.1
* 18.17.1
* 16.20.2
### TypeScript
5.0.4
5.1.6
## 開発環境構築

View File

@ -4,7 +4,7 @@
# Cubism Web Framework
This is a framework for using models output by Live2D Cubism 4 Editor in applications.
This is a framework for using models output by Live2D Cubism Editor in applications.
It provides various functions for displaying and manipulating the model.
It is used in conjunction with the Live2D Cubism Core library to load the model.
@ -17,17 +17,26 @@ You can use it as a JavaScript library that can be used in the browser by buildi
Please check the [license](LICENSE.md) before using this SDK.
## Compatibility with Cubism 5 new features and previous Cubism SDK versions
This SDK is compatible with Cubism 5.
For SDK compatibility with new features in Cubism 5 Editor, please refer to [here](https://docs.live2d.com/en/cubism-sdk-manual/cubism-5-new-functions/).
For compatibility with previous versions of Cubism SDK, please refer to [here](https://docs.live2d.com/en/cubism-sdk-manual/compatibility-with-cubism-5/).
## Development environment
### Node.js
* 20.1.0
* 18.16.0
* 16.20.0
* 20.5.1
* 18.17.1
* 16.20.2
### TypeScript
5.0.4
5.1.6
## Development environment construction

1738
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,13 +8,13 @@
"clean": "rimraf dist"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.59.5",
"@typescript-eslint/parser": "^5.59.5",
"eslint": "^8.40.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"prettier": "^2.8.8",
"rimraf": "^5.0.0",
"typescript": "^5.0.4"
"@typescript-eslint/eslint-plugin": "^6.4.0",
"@typescript-eslint/parser": "^6.4.0",
"eslint": "^8.47.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"prettier": "^3.0.1",
"rimraf": "^5.0.1",
"typescript": "^5.1.6"
}
}

View File

@ -60,7 +60,7 @@ export const CubismDefaultParameterId = Object.freeze<Record<string, string>>({
ParamBustY: 'ParamBustY',
ParamBaseX: 'ParamBaseX',
ParamBaseY: 'ParamBaseY',
ParamNONE: 'NONE:',
ParamNONE: 'NONE:'
});
// Namespace definition for compatibility.

View File

@ -73,7 +73,7 @@ enum FrequestNode {
FrequestNode_Textures, // getRoot().getValueByString(FileReferences).getValueByString(Textures)
FrequestNode_Physics, // getRoot().getValueByString(FileReferences).getValueByString(Physics)
FrequestNode_Pose, // getRoot().getValueByString(FileReferences).getValueByString(Pose)
FrequestNode_HitAreas, // getRoot().getValueByString(HitAreas)
FrequestNode_HitAreas // getRoot().getValueByString(HitAreas)
}
/**

View File

@ -219,7 +219,7 @@ export enum EyeState {
EyeState_Interval, // まばたきしていない状態
EyeState_Closing, // まぶたが閉じていく途中の状態
EyeState_Closed, // まぶたが閉じている状態
EyeState_Opening, // まぶたが開いていく途中の状態
EyeState_Opening // まぶたが開いていく途中の状態
}
// Namespace definition for compatibility.

View File

@ -11,8 +11,23 @@ import { csmString } from '../type/csmstring';
* Drawable
*
* Drawable
*
* @note IDCubismId
* CubismIdManager().getId(id)使
*/
export class CubismId {
/**
* 使CubismId
*
* @param id ID
* @returns CubismId
* @note IDCubismId
* CubismIdManager().getId(id)使
*/
public static _createIdInternal(id: string | csmString) {
return new CubismId(id);
}
/**
* ID
*/
@ -20,18 +35,6 @@ export class CubismId {
return this._id;
}
/**
*
*/
public constructor(id: string | csmString) {
if (typeof id === 'string') {
this._id = new csmString(id);
return;
}
this._id = id;
}
/**
* id
* @param c id
@ -64,6 +67,20 @@ export class CubismId {
return false;
}
/**
*
*
* @note
*/
private constructor(id: string | csmString) {
if (typeof id === 'string') {
this._id = new csmString(id);
return;
}
this._id = id;
}
private _id: csmString; // ID名
}

View File

@ -57,7 +57,7 @@ export class CubismIdManager {
return result;
}
result = new CubismId(id);
result = CubismId._createIdInternal(id);
this._ids.pushBack(result);
} else {
return this.registerId(id.s);

View File

@ -10,7 +10,7 @@ import { CubismRenderer } from './rendering/cubismrenderer';
import {
CSM_ASSERT,
CubismLogInfo,
CubismLogWarning,
CubismLogWarning
} from './utils/cubismdebug';
import { Value } from './utils/cubismjson';
@ -56,7 +56,7 @@ let s_cubismIdManager: CubismIdManager = null;
*/
export const Constant = Object.freeze<Record<string, number>>({
vertexOffset: 0, // メッシュ頂点のオフセット値
vertexStep: 2, // メッシュ頂点のステップ値
vertexStep: 2 // メッシュ頂点のステップ値
});
export function csmDelete<T>(address: T): void {
@ -274,7 +274,7 @@ export enum LogLevel {
LogLevel_Info, // Infoログ
LogLevel_Warning, // 警告ログ
LogLevel_Error, // エラーログ
LogLevel_Off, // ログ出力無効
LogLevel_Off // ログ出力無効
}
// Namespace definition for compatibility.

View File

@ -33,7 +33,7 @@ export class CubismMatrix44 {
): void {
const c: Float32Array = new Float32Array([
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0,
0.0
]);
const n = 4;
@ -57,7 +57,7 @@ export class CubismMatrix44 {
public loadIdentity(): void {
const c: Float32Array = new Float32Array([
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
1.0,
1.0
]);
this.setMatrix(c);
@ -175,7 +175,7 @@ export class CubismMatrix44 {
x,
y,
0.0,
1.0,
1.0
]);
CubismMatrix44.multiply(tr1, this._tr, this._tr);
@ -235,7 +235,7 @@ export class CubismMatrix44 {
0.0,
0.0,
0.0,
1.0,
1.0
]);
CubismMatrix44.multiply(tr1, this._tr, this._tr);

View File

@ -14,7 +14,10 @@ export class CubismVector2 {
/**
*
*/
public constructor(public x?: number, public y?: number) {
public constructor(
public x?: number,
public y?: number
) {
this.x = x == undefined ? 0.0 : x;
this.y = y == undefined ? 0.0 : y;

View File

@ -72,7 +72,7 @@ export class CubismViewMatrix extends CubismMatrix44 {
x,
y,
0.0,
1.0,
1.0
]);
CubismMatrix44.multiply(tr1, this._tr, this._tr);
@ -117,7 +117,7 @@ export class CubismViewMatrix extends CubismMatrix44 {
cx,
cy,
0.0,
1.0,
1.0
]);
const tr2: Float32Array = new Float32Array([
@ -136,7 +136,7 @@ export class CubismViewMatrix extends CubismMatrix44 {
0.0,
0.0,
0.0,
1.0,
1.0
]);
const tr3: Float32Array = new Float32Array([
@ -155,7 +155,7 @@ export class CubismViewMatrix extends CubismMatrix44 {
-cx,
-cy,
0.0,
1.0,
1.0
]);
CubismMatrix44.multiply(tr3, this._tr, this._tr);

View File

@ -9,7 +9,7 @@ import { CubismIdHandle } from '../id/cubismid';
import { CubismFramework } from '../live2dcubismframework';
import {
CubismBlendMode,
CubismTextureColor,
CubismTextureColor
} from '../rendering/cubismrenderer';
import { csmMap } from '../type/csmmap';
import { csmVector } from '../type/csmvector';
@ -846,6 +846,18 @@ export class CubismModel {
return this._model.parameters.defaultValues[parameterIndex];
}
/**
* indexID
*
* @param parameterIndex
* @returns ID
*/
public getParameterId(parameterIndex: number): CubismIdHandle {
return CubismFramework.getIdManager().getId(
this._model.parameters.ids[parameterIndex]
);
}
/**
*
* @param parameterIndex

View File

@ -14,6 +14,7 @@ import { CubismModelMatrix } from '../math/cubismmodelmatrix';
import { CubismTargetPoint } from '../math/cubismtargetpoint';
import { ACubismMotion, FinishedMotionCallback } from '../motion/acubismmotion';
import { CubismExpressionMotion } from '../motion/cubismexpressionmotion';
import { CubismExpressionMotionManager } from '../motion/cubismexpressionmotionmanager';
import { CubismMotion } from '../motion/cubismmotion';
import { CubismMotionManager } from '../motion/cubismmotionmanager';
import { CubismMotionQueueManager } from '../motion/cubismmotionqueuemanager';
@ -371,7 +372,7 @@ export class CubismUserModel {
);
// 表情マネージャーを作成
this._expressionManager = new CubismMotionManager();
this._expressionManager = new CubismExpressionMotionManager();
// ドラッグによるアニメーション
this._dragManager = new CubismTargetPoint();
@ -415,7 +416,7 @@ export class CubismUserModel {
protected _model: CubismModel; // Modelインスタンス
protected _motionManager: CubismMotionManager; // モーション管理
protected _expressionManager: CubismMotionManager; // 表情管理
protected _expressionManager: CubismExpressionMotionManager; // 表情管理
protected _eyeBlink: CubismEyeBlink; // 自動まばたき
protected _breath: CubismBreath; // 呼吸
protected _modelMatrix: CubismModelMatrix; // モデル行列

View File

@ -78,6 +78,38 @@ export abstract class ACubismMotion {
}
}
const fadeWeight = this.updateFadeWeight(motionQueueEntry, userTimeSeconds);
//---- 全てのパラメータIDをループする ----
this.doUpdateParameters(
model,
userTimeSeconds,
fadeWeight,
motionQueueEntry
);
// 後処理
// 終了時刻を過ぎたら終了フラグを立てる(CubismMotionQueueManager)
if (
motionQueueEntry.getEndTime() > 0 &&
motionQueueEntry.getEndTime() < userTimeSeconds
) {
motionQueueEntry.setIsFinished(true); // 終了
}
}
/**
* @brief
*
*
*
* @param[in] motionQueueEntry CubismMotionQueueManager
* @param[in] userTimeSeconds []
*/
public updateFadeWeight(
motionQueueEntry: CubismMotionQueueEntry,
userTimeSeconds: number
): number {
let fadeWeight: number = this._weight; // 現在の値と掛け合わせる割合
//---- フェードイン・アウトの処理 ----
@ -104,22 +136,7 @@ export abstract class ACubismMotion {
CSM_ASSERT(0.0 <= fadeWeight && fadeWeight <= 1.0);
//---- 全てのパラメータIDをループする ----
this.doUpdateParameters(
model,
userTimeSeconds,
fadeWeight,
motionQueueEntry
);
// 後処理
// 終了時刻を過ぎたら終了フラグを立てる(CubismMotionQueueManager)
if (
motionQueueEntry.getEndTime() > 0 &&
motionQueueEntry.getEndTime() < userTimeSeconds
) {
motionQueueEntry.setIsFinished(true); // 終了
}
return fadeWeight;
}
/**

View File

@ -31,6 +31,9 @@ const DefaultFadeTime = 1.0;
*
*/
export class CubismExpressionMotion extends ACubismMotion {
static readonly DefaultAdditiveValue = 0.0; // 加算適用の初期値
static readonly DefaultMultiplyValue = 1.0; // 乗算適用の初期値
/**
*
* @param buffer exp
@ -63,7 +66,7 @@ export class CubismExpressionMotion extends ACubismMotion {
const parameter: ExpressionParameter = this._parameters.at(i);
switch (parameter.blendType) {
case ExpressionBlendType.ExpressionBlendType_Add: {
case ExpressionBlendType.Additive: {
model.addParameterValueById(
parameter.parameterId,
parameter.value,
@ -71,7 +74,7 @@ export class CubismExpressionMotion extends ACubismMotion {
);
break;
}
case ExpressionBlendType.ExpressionBlendType_Multiply: {
case ExpressionBlendType.Multiply: {
model.multiplyParameterValueById(
parameter.parameterId,
parameter.value,
@ -79,7 +82,7 @@ export class CubismExpressionMotion extends ACubismMotion {
);
break;
}
case ExpressionBlendType.ExpressionBlendType_Overwrite: {
case ExpressionBlendType.Overwrite: {
model.setParameterValueById(
parameter.parameterId,
parameter.value,
@ -94,6 +97,163 @@ export class CubismExpressionMotion extends ACubismMotion {
}
}
/**
* @brief
*
*
*
* @param[in] model
* @param[in] userTimeSeconds []
* @param[in] motionQueueEntry CubismMotionQueueManager
* @param[in] expressionParameterValues
* @param[in] expressionIndex
*/
public calculateExpressionParameters(
model: CubismModel,
userTimeSeconds: number,
motionQueueEntry: CubismMotionQueueEntry,
expressionParameterValues: csmVector<ExpressionParameterValue>,
expressionIndex: number
) {
if (!motionQueueEntry.isAvailable()) {
return;
}
if (!motionQueueEntry.isStarted()) {
motionQueueEntry.setIsStarted(true);
motionQueueEntry.setStartTime(userTimeSeconds - this._offsetSeconds); // モーションの開始時刻を記録
motionQueueEntry.setFadeInStartTime(userTimeSeconds); // フェードインの開始時刻
const duration = this.getDuration();
if (motionQueueEntry.getEndTime() < 0.0) {
// 開始していないうちに終了設定している場合がある
motionQueueEntry.setEndTime(
duration <= 0.0 ? -1 : motionQueueEntry.getStartTime() + duration
);
// duration == -1 の場合はループする
}
}
this._fadeWeight = this.updateFadeWeight(motionQueueEntry, userTimeSeconds);
// モデルに適用する値を計算
for (let i = 0; i < expressionParameterValues.getSize(); ++i) {
const expressionParameterValue = expressionParameterValues.at(i);
if (expressionParameterValue.parameterId == null) {
continue;
}
const currentParameterValue = (expressionParameterValue.overwriteValue =
model.getParameterValueById(expressionParameterValue.parameterId));
const expressionParameters = this.getExpressionParameters();
let parameterIndex = -1;
for (let j = 0; j < expressionParameters.getSize(); ++j) {
if (
expressionParameterValue.parameterId !=
expressionParameters.at(j).parameterId
) {
continue;
}
parameterIndex = j;
break;
}
// 再生中のExpressionが参照していないパラメータは初期値を適用
if (parameterIndex < 0) {
if (expressionIndex == 0) {
expressionParameterValue.additiveValue =
CubismExpressionMotion.DefaultAdditiveValue;
expressionParameterValue.multiplyValue =
CubismExpressionMotion.DefaultMultiplyValue;
expressionParameterValue.overwriteValue = currentParameterValue;
} else {
expressionParameterValue.additiveValue = this.calculateValue(
expressionParameterValue.additiveValue,
CubismExpressionMotion.DefaultAdditiveValue
);
expressionParameterValue.multiplyValue = this.calculateValue(
expressionParameterValue.multiplyValue,
CubismExpressionMotion.DefaultMultiplyValue
);
expressionParameterValue.overwriteValue = this.calculateValue(
expressionParameterValue.overwriteValue,
currentParameterValue
);
}
continue;
}
// 値を計算
const value = expressionParameters.at(parameterIndex).value;
let newAdditiveValue, newMultiplyValue, newOverwriteValue;
switch (expressionParameters.at(parameterIndex).blendType) {
case ExpressionBlendType.Additive:
newAdditiveValue = value;
newMultiplyValue = CubismExpressionMotion.DefaultMultiplyValue;
newOverwriteValue = currentParameterValue;
break;
case ExpressionBlendType.Multiply:
newAdditiveValue = CubismExpressionMotion.DefaultAdditiveValue;
newMultiplyValue = value;
newOverwriteValue = currentParameterValue;
break;
case ExpressionBlendType.Overwrite:
newAdditiveValue = CubismExpressionMotion.DefaultAdditiveValue;
newMultiplyValue = CubismExpressionMotion.DefaultMultiplyValue;
newOverwriteValue = value;
break;
default:
return;
}
if (expressionIndex == 0) {
expressionParameterValue.additiveValue = newAdditiveValue;
expressionParameterValue.multiplyValue = newMultiplyValue;
expressionParameterValue.overwriteValue = newOverwriteValue;
} else {
expressionParameterValue.additiveValue =
expressionParameterValue.additiveValue * (1.0 - this._fadeWeight) +
newAdditiveValue * this._fadeWeight;
expressionParameterValue.multiplyValue =
expressionParameterValue.multiplyValue * (1.0 - this._fadeWeight) +
newMultiplyValue * this._fadeWeight;
expressionParameterValue.overwriteValue =
expressionParameterValue.overwriteValue * (1.0 - this._fadeWeight) +
newOverwriteValue * this._fadeWeight;
}
}
}
/**
* @brief
*
*
*
* @return
*/
public getExpressionParameters() {
return this._parameters;
}
/**
* @brief
*
*
*
* @returns
*/
public getFadeWeight() {
return this._fadeWeight;
}
protected parse(buffer: ArrayBuffer, size: number) {
const json: CubismJson = CubismJson.create(buffer, size);
const root: Value = json.getRoot();
@ -130,20 +290,20 @@ export class CubismExpressionMotion extends ACubismMotion {
param.getValueByString(ExpressionKeyBlend).isNull() ||
param.getValueByString(ExpressionKeyBlend).getString() == BlendValueAdd
) {
blendType = ExpressionBlendType.ExpressionBlendType_Add;
blendType = ExpressionBlendType.Additive;
} else if (
param.getValueByString(ExpressionKeyBlend).getString() ==
BlendValueMultiply
) {
blendType = ExpressionBlendType.ExpressionBlendType_Multiply;
blendType = ExpressionBlendType.Multiply;
} else if (
param.getValueByString(ExpressionKeyBlend).getString() ==
BlendValueOverwrite
) {
blendType = ExpressionBlendType.ExpressionBlendType_Overwrite;
blendType = ExpressionBlendType.Overwrite;
} else {
// その他 仕様にない値を設定した時は加算モードにすることで復旧
blendType = ExpressionBlendType.ExpressionBlendType_Add;
blendType = ExpressionBlendType.Additive;
}
// 設定オブジェクトを作成してリストに追加する
@ -159,25 +319,40 @@ export class CubismExpressionMotion extends ACubismMotion {
CubismJson.delete(json); // JSONデータは不要になったら削除する
}
/**
* @brief
*
*
*
* @param source
* @param destination
* @param weight
* @returns
*/
public calculateValue(source: number, destination: number): number {
return source * (1.0 - this._fadeWeight) + destination * this._fadeWeight;
}
/**
*
*/
protected constructor() {
super();
this._parameters = new csmVector<ExpressionParameter>();
this._fadeWeight = 0.0;
}
_parameters: csmVector<ExpressionParameter>; // 表情のパラメータ情報リスト
private _parameters: csmVector<ExpressionParameter>; // 表情のパラメータ情報リスト
private _fadeWeight: number; // 表情の現在のウェイト
}
/**
*
*/
export enum ExpressionBlendType {
ExpressionBlendType_Add = 0, // 加算
ExpressionBlendType_Multiply = 1, // 乗算
ExpressionBlendType_Overwrite = 2, // 上書き
Additive = 0, // 加算
Multiply = 1, // 乗算
Overwrite = 2 // 上書き
}
/**
@ -191,6 +366,8 @@ export class ExpressionParameter {
// Namespace definition for compatibility.
import * as $ from './cubismexpressionmotion';
import { ExpressionParameterValue } from './cubismexpressionmotionmanager';
import { CubismDefaultParameterId } from '../cubismdefaultparameterid';
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace Live2DCubismFramework {
export const CubismExpressionMotion = $.CubismExpressionMotion;

View File

@ -0,0 +1,267 @@
import { CubismId, CubismIdHandle } from '../id/cubismid';
import { csmDelete } from '../live2dcubismframework';
import { CubismModel } from '../model/cubismmodel';
import { csmVector, iterator } from '../type/csmvector';
import { ACubismMotion } from './acubismmotion';
import { CubismExpressionMotion } from './cubismexpressionmotion';
import { CubismMotionQueueEntry } from './cubismmotionqueueentry';
import {
CubismMotionQueueEntryHandle,
CubismMotionQueueManager
} from './cubismmotionqueuemanager';
/**
* @brief
*/
export class ExpressionParameterValue {
parameterId: CubismIdHandle; // パラメーターID
additiveValue: number; // 加算値
multiplyValue: number; // 乗算値
overwriteValue: number; // 上書き値
}
/**
* @brief
*
*
*/
export class CubismExpressionMotionManager extends CubismMotionQueueManager {
/**
*
*/
public constructor() {
super();
this._currentPriority = 0;
this._reservePriority = 0;
this._expressionParameterValues = new csmVector<ExpressionParameterValue>();
}
/**
*
*/
public release(): void {
if (this._expressionParameterValues) {
csmDelete(this._expressionParameterValues);
this._expressionParameterValues = null;
}
}
/**
* @brief
*
*
*
* @returns
*/
public getCurrentPriority(): number {
return this._currentPriority;
}
/**
* @brief
*
*
*
* @return
*/
public getReservePriority(): number {
return this._reservePriority;
}
/**
* @brief
*
*
*
* @param[in] priority
*/
public setReservePriority(priority: number) {
this._reservePriority = priority;
}
/**
* @brief
*
*
*
* @param[in] motion
* @param[in] autoDelete true
* @param[in] priority
* @return IsFinished()使-1
*/
public startMotionPriority(
motion: ACubismMotion,
autoDelete: boolean,
priority: number
): CubismMotionQueueEntryHandle {
if (priority == this.getReservePriority()) {
this.setReservePriority(0);
}
this._currentPriority = priority;
return this.startMotion(motion, autoDelete, this._userTimeSeconds);
}
/**
* @brief
*
*
*
* @param[in] model
* @param[in] deltaTimeSeconds []
* @retval true
* @retval false
*/
public updateMotion(model: CubismModel, deltaTimeSeconds: number): boolean {
this._userTimeSeconds += deltaTimeSeconds;
let updated = false;
const motions = this.getCubismMotionQueueEntries();
let expressionWeight = 0.0;
let expressionIndex = 0;
// ------- 処理を行う --------
// 既にモーションがあれば終了フラグを立てる
for (
let ite: iterator<CubismMotionQueueEntry> = this._motions.begin();
ite.notEqual(this._motions.end());
) {
const motionQueueEntry = ite.ptr();
if (motionQueueEntry == null) {
ite = motions.erase(ite); //削除
continue;
}
const expressionMotion = <CubismExpressionMotion>(
motionQueueEntry.getCubismMotion()
);
if (expressionMotion == null) {
csmDelete(motionQueueEntry);
ite = motions.erase(ite); //削除
continue;
}
const expressionParameters = expressionMotion.getExpressionParameters();
if (motionQueueEntry.isAvailable()) {
// 再生中のExpressionが参照しているパラメータをすべてリストアップ
for (let i = 0; i < expressionParameters.getSize(); ++i) {
if (expressionParameters.at(i).parameterId == null) {
continue;
}
let index = -1;
// リストにパラメータIDが存在するか検索
for (let j = 0; j < this._expressionParameterValues.getSize(); ++j) {
if (
this._expressionParameterValues.at(j).parameterId !=
expressionParameters.at(i).parameterId
) {
continue;
}
index = j;
break;
}
if (index >= 0) {
continue;
}
// パラメータがリストに存在しないなら新規追加
const item: ExpressionParameterValue = new ExpressionParameterValue();
item.parameterId = expressionParameters.at(i).parameterId;
item.additiveValue = CubismExpressionMotion.DefaultAdditiveValue;
item.multiplyValue = CubismExpressionMotion.DefaultMultiplyValue;
item.overwriteValue = model.getParameterValueById(item.parameterId);
this._expressionParameterValues.pushBack(item);
}
}
// ------ 値を計算する ------
expressionMotion.calculateExpressionParameters(
model,
this._userTimeSeconds,
motionQueueEntry,
this._expressionParameterValues,
expressionIndex
);
expressionWeight +=
expressionMotion.getFadeInTime() == 0.0
? 1.0
: CubismMath.getEasingSine(
(this._userTimeSeconds - motionQueueEntry.getFadeInStartTime()) /
expressionMotion.getFadeInTime()
);
updated = true;
if (motionQueueEntry.isTriggeredFadeOut()) {
// フェードアウト開始
motionQueueEntry.startFadeOut(
motionQueueEntry.getFadeOutSeconds(),
this._userTimeSeconds
);
}
ite.preIncrement();
++expressionIndex;
}
// ----- 最新のExpressionのフェードが完了していればそれ以前を削除する ------
if (motions.getSize() > 1) {
const expressionMotion = <CubismExpressionMotion>(
motions.at(motions.getSize() - 1).getCubismMotion()
);
if (expressionMotion.getFadeWeight() >= 1.0) {
// 配列の最後の要素は削除しない
for (let i = motions.getSize() - 2; i >= 0; --i) {
const motionQueueEntry = motions.at(i);
csmDelete(motionQueueEntry);
motions.remove(i);
}
}
}
if (expressionWeight > 1.0) {
expressionWeight = 1.0;
}
// モデルに各値を適用
for (let i = 0; i < this._expressionParameterValues.getSize(); ++i) {
const expressionParameterValue = this._expressionParameterValues.at(i);
model.setParameterValueById(
expressionParameterValue.parameterId,
(expressionParameterValue.overwriteValue +
expressionParameterValue.additiveValue) *
expressionParameterValue.multiplyValue,
expressionWeight
);
expressionParameterValue.additiveValue =
CubismExpressionMotion.DefaultAdditiveValue;
expressionParameterValue.multiplyValue =
CubismExpressionMotion.DefaultMultiplyValue;
}
return updated;
}
private _expressionParameterValues: csmVector<ExpressionParameterValue>; ///< モデルに適用する各パラメータの値
private _currentPriority: number; ///< 現在再生中のモーションの優先度
private _reservePriority: number; ///< 再生予定のモーションの優先度。再生中は0になる。モーションファイルを別スレッドで読み込むときの機能。
private _startExpressionTime: number; ///< 表情の再生開始時刻
}
// Namespace definition for compatibility.
import * as $ from './cubismexpressionmotionmanager';
import { CubismMath } from '../math/cubismmath';
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace Live2DCubismFramework {
export const CubismExpressionMotionManager = $.CubismExpressionMotionManager;
export type CubismExpressionMotionManager = $.CubismExpressionMotionManager;
}

View File

@ -14,7 +14,7 @@ import { csmVector } from '../type/csmvector';
import {
CSM_ASSERT,
CubismLogDebug,
CubismLogWarning,
CubismLogWarning
} from '../utils/cubismdebug';
import { ACubismMotion, FinishedMotionCallback } from './acubismmotion';
import {
@ -24,7 +24,7 @@ import {
CubismMotionEvent,
CubismMotionPoint,
CubismMotionSegment,
CubismMotionSegmentType,
CubismMotionSegmentType
} from './cubismmotioninternal';
import { CubismMotionJson, EvaluationOptionFlag } from './cubismmotionjson';
import { CubismMotionQueueEntry } from './cubismmotionqueueentry';
@ -212,7 +212,7 @@ function evaluateCurve(
// Get first point of next segment.
pointPosition =
motionData.segments.at(i).basePointIndex +
(motionData.segments.at(i).segmentType ==
((motionData.segments.at(i).segmentType as CubismMotionSegmentType) ==
CubismMotionSegmentType.CubismMotionSegmentType_Bezier
? 3
: 1);

View File

@ -17,7 +17,7 @@ import { csmVector } from '../type/csmvector';
export enum CubismMotionCurveTarget {
CubismMotionCurveTarget_Model, // モデルに対して
CubismMotionCurveTarget_Parameter, // パラメータに対して
CubismMotionCurveTarget_PartOpacity, // パーツの不透明度に対して
CubismMotionCurveTarget_PartOpacity // パーツの不透明度に対して
}
/**
@ -29,7 +29,7 @@ export enum CubismMotionSegmentType {
CubismMotionSegmentType_Linear = 0, // リニア
CubismMotionSegmentType_Bezier = 1, // ベジェ曲線
CubismMotionSegmentType_Stepped = 2, // ステップ
CubismMotionSegmentType_InverseStepped = 3, // インバースステップ
CubismMotionSegmentType_InverseStepped = 3 // インバースステップ
}
/**

View File

@ -76,7 +76,7 @@ export class CubismMotionJson {
.toBoolean();
}
public getEvaluationOptionFlag(flagType: number): boolean {
public getEvaluationOptionFlag(flagType: EvaluationOptionFlag): boolean {
if (
EvaluationOptionFlag.EvaluationOptionFlag_AreBeziersRistricted == flagType
) {
@ -371,7 +371,7 @@ export class CubismMotionJson {
* @brief
*/
export enum EvaluationOptionFlag {
EvaluationOptionFlag_AreBeziersRistricted = 0, ///< ベジェハンドルの規制状態
EvaluationOptionFlag_AreBeziersRistricted = 0 ///< ベジェハンドルの規制状態
}
// Namespace definition for compatibility.

View File

@ -9,7 +9,7 @@ import { CubismModel } from '../model/cubismmodel';
import { ACubismMotion } from './acubismmotion';
import {
CubismMotionQueueEntryHandle,
CubismMotionQueueManager,
CubismMotionQueueManager
} from './cubismmotionqueuemanager';
/**

View File

@ -226,6 +226,15 @@ export class CubismMotionQueueEntry {
return this._fadeOutSeconds;
}
/**
*
*
* @return
*/
public getCubismMotion(): ACubismMotion {
return this._motion;
}
_autoDelete: boolean; // 自動削除
_motion: ACubismMotion; // モーション

View File

@ -183,6 +183,18 @@ export class CubismMotionQueueManager {
}
}
/**
* @brief CubismMotionQueueEntry
*
* CubismMotionQueueEntry
*
* @return CubismMotionQueueEntry
* @retval NULL
*/
public getCubismMotionQueueEntries(): csmVector<CubismMotionQueueEntry> {
return this._motions;
}
/**
* CubismMotionQueueEntry

View File

@ -17,7 +17,7 @@ import {
CubismPhysicsRig,
CubismPhysicsSource,
CubismPhysicsSubRig,
CubismPhysicsTargetType,
CubismPhysicsTargetType
} from './cubismphysicsinternal';
import { CubismPhysicsJson } from './cubismphysicsjson';

View File

@ -13,7 +13,7 @@ import { csmVector } from '../type/csmvector';
*
*/
export enum CubismPhysicsTargetType {
CubismPhysicsTargetType_Parameter, // パラメータに対して適用
CubismPhysicsTargetType_Parameter // パラメータに対して適用
}
/**
@ -22,7 +22,7 @@ export enum CubismPhysicsTargetType {
export enum CubismPhysicsSource {
CubismPhysicsSource_X, // X軸の位置から
CubismPhysicsSource_Y, // Y軸の位置から
CubismPhysicsSource_Angle, // 角度から
CubismPhysicsSource_Angle // 角度から
}
/**

View File

@ -0,0 +1,706 @@
/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
import { Constant } from '../live2dcubismframework';
import { csmVector } from '../type/csmvector';
import { csmRect } from '../type/csmrectf';
import { CubismMatrix44 } from '../math/cubismmatrix44';
import { CubismModel } from '../model/cubismmodel';
import { CubismClippingContext, CubismTextureColor } from './cubismrenderer';
import { CubismLogError, CubismLogWarning } from '../utils/cubismdebug';
const ColorChannelCount = 4; // 実験時に1チャンネルの場合は1、RGBだけの場合は3、アルファも含める場合は4
const ClippingMaskMaxCountOnDefault = 36; // 通常のフレームバッファ一枚あたりのマスク最大数
const ClippingMaskMaxCountOnMultiRenderTexture = 32; // フレームバッファが2枚以上ある場合のフレームバッファ一枚あたりのマスク最大数
export type ClippingContextConstructor<
T_ClippingContext extends CubismClippingContext
> = new (
manager: CubismClippingManager<T_ClippingContext>,
drawableMasks: Int32Array,
drawableMaskCounts: number
) => T_ClippingContext;
export interface ICubismClippingManager {
getClippingMaskBufferSize(): number;
}
export abstract class CubismClippingManager<
T_ClippingContext extends CubismClippingContext
> implements ICubismClippingManager
{
/**
*
*/
public constructor(
clippingContextFactory: ClippingContextConstructor<T_ClippingContext>
) {
this._renderTextureCount = 0;
this._clippingMaskBufferSize = 256;
this._clippingContextListForMask = new csmVector<T_ClippingContext>();
this._clippingContextListForDraw = new csmVector<T_ClippingContext>();
this._channelColors = new csmVector<CubismTextureColor>();
this._tmpBoundsOnModel = new csmRect();
this._tmpMatrix = new CubismMatrix44();
this._tmpMatrixForMask = new CubismMatrix44();
this._tmpMatrixForDraw = new CubismMatrix44();
this._clippingContexttConstructor = clippingContextFactory;
let tmp: CubismTextureColor = new CubismTextureColor();
tmp.R = 1.0;
tmp.G = 0.0;
tmp.B = 0.0;
tmp.A = 0.0;
this._channelColors.pushBack(tmp);
tmp = new CubismTextureColor();
tmp.R = 0.0;
tmp.G = 1.0;
tmp.B = 0.0;
tmp.A = 0.0;
this._channelColors.pushBack(tmp);
tmp = new CubismTextureColor();
tmp.R = 0.0;
tmp.G = 0.0;
tmp.B = 1.0;
tmp.A = 0.0;
this._channelColors.pushBack(tmp);
tmp = new CubismTextureColor();
tmp.R = 0.0;
tmp.G = 0.0;
tmp.B = 0.0;
tmp.A = 1.0;
this._channelColors.pushBack(tmp);
}
/**
*
*/
public release(): void {
for (let i = 0; i < this._clippingContextListForMask.getSize(); i++) {
if (this._clippingContextListForMask.at(i)) {
this._clippingContextListForMask.at(i).release();
this._clippingContextListForMask.set(i, void 0);
}
this._clippingContextListForMask.set(i, null);
}
this._clippingContextListForMask = null;
// _clippingContextListForDrawは_clippingContextListForMaskにあるインスタンスを指している。上記の処理により要素ごとのDELETEは不要。
for (let i = 0; i < this._clippingContextListForDraw.getSize(); i++) {
this._clippingContextListForDraw.set(i, null);
}
this._clippingContextListForDraw = null;
for (let i = 0; i < this._channelColors.getSize(); i++) {
this._channelColors.set(i, null);
}
this._channelColors = null;
if (this._clearedFrameBufferFlags != null) {
this._clearedFrameBufferFlags.clear();
}
this._clearedFrameBufferFlags = null;
}
/**
*
* 使
* @param model
* @param renderTextureCount
*/
public initialize(model: CubismModel, renderTextureCount: number): void {
// レンダーテクスチャの合計枚数の設定
// 1以上の整数でない場合はそれぞれ警告を出す
if (renderTextureCount % 1 != 0) {
CubismLogWarning(
'The number of render textures must be specified as an integer. The decimal point is rounded down and corrected to an integer.'
);
// 小数点以下を除去
renderTextureCount = ~~renderTextureCount;
}
if (renderTextureCount < 1) {
CubismLogWarning(
'The number of render textures must be an integer greater than or equal to 1. Set the number of render textures to 1.'
);
}
// 負の値が使われている場合は強制的に1枚と設定する
this._renderTextureCount = renderTextureCount < 1 ? 1 : renderTextureCount;
this._clearedFrameBufferFlags = new csmVector<boolean>(
this._renderTextureCount
);
// クリッピングマスクを使う描画オブジェクトをすべて登録する
// クリッピングマスクは、通常数個程度に限定して使うものとする
for (let i = 0; i < model.getDrawableCount(); i++) {
if (model.getDrawableMaskCounts()[i] <= 0) {
// クリッピングマスクが使用されていないアートメッシュ(多くの場合使用しない)
this._clippingContextListForDraw.pushBack(null);
continue;
}
// 既にあるClipContextと同じかチェックする
let clippingContext: T_ClippingContext = this.findSameClip(
model.getDrawableMasks()[i],
model.getDrawableMaskCounts()[i]
);
if (clippingContext == null) {
// 同一のマスクが存在していない場合は生成する
clippingContext = new this._clippingContexttConstructor(
this,
model.getDrawableMasks()[i],
model.getDrawableMaskCounts()[i]
);
this._clippingContextListForMask.pushBack(clippingContext);
}
clippingContext.addClippedDrawable(i);
this._clippingContextListForDraw.pushBack(clippingContext);
}
}
/**
*
*
* NULL
* @param drawableMasks
* @param drawableMaskCounts
* @return NULL
*/
public findSameClip(
drawableMasks: Int32Array,
drawableMaskCounts: number
): T_ClippingContext {
// 作成済みClippingContextと一致するか確認
for (let i = 0; i < this._clippingContextListForMask.getSize(); i++) {
const clippingContext: T_ClippingContext =
this._clippingContextListForMask.at(i);
const count: number = clippingContext._clippingIdCount;
// 個数が違う場合は別物
if (count != drawableMaskCounts) {
continue;
}
let sameCount = 0;
// 同じIDを持つか確認。配列の数が同じなので、一致した個数が同じなら同じ物を持つとする
for (let j = 0; j < count; j++) {
const clipId: number = clippingContext._clippingIdList[j];
for (let k = 0; k < count; k++) {
if (drawableMasks[k] == clipId) {
sameCount++;
break;
}
}
}
if (sameCount == count) {
return clippingContext;
}
}
return null; // 見つからなかった
}
/**
*
* @param model
* @param isRightHanded
*/
public setupMatrixForHighPrecision(
model: CubismModel,
isRightHanded: boolean
): void {
// 全てのクリッピングを用意する
// 同じクリップ複数の場合はまとめて一つのクリップを使う場合は1度だけ設定する
let usingClipCount = 0;
for (
let clipIndex = 0;
clipIndex < this._clippingContextListForMask.getSize();
clipIndex++
) {
// 1つのクリッピングマスクに関して
const cc: T_ClippingContext =
this._clippingContextListForMask.at(clipIndex);
// このクリップを利用する描画オブジェクト群全体を囲む矩形を計算
this.calcClippedDrawTotalBounds(model, cc);
if (cc._isUsing) {
usingClipCount++; // 使用中としてカウント
}
}
// マスク行列作成処理
if (usingClipCount > 0) {
this.setupLayoutBounds(0);
// サイズがレンダーテクスチャの枚数と合わない場合は合わせる
if (this._clearedFrameBufferFlags.getSize() != this._renderTextureCount) {
this._clearedFrameBufferFlags.clear();
for (let i = 0; i < this._renderTextureCount; i++) {
this._clearedFrameBufferFlags.pushBack(false);
}
} else {
// マスクのクリアフラグを毎フレーム開始時に初期化
for (let i = 0; i < this._renderTextureCount; i++) {
this._clearedFrameBufferFlags.set(i, false);
}
}
// 実際にマスクを生成する
// 全てのマスクをどの様にレイアウトして描くかを決定し、ClipContext , ClippedDrawContext に記憶する
for (
let clipIndex = 0;
clipIndex < this._clippingContextListForMask.getSize();
clipIndex++
) {
// --- 実際に1つのマスクを描く ---
const clipContext: T_ClippingContext =
this._clippingContextListForMask.at(clipIndex);
const allClippedDrawRect: csmRect = clipContext._allClippedDrawRect; //このマスクを使う、全ての描画オブジェクトの論理座標上の囲み矩形
const layoutBoundsOnTex01 = clipContext._layoutBounds; //この中にマスクを収める
const MARGIN = 0.05;
let scaleX = 0.0;
let scaleY = 0.0;
const ppu: number = model.getPixelsPerUnit();
const maskPixelSize: number = clipContext
.getClippingManager()
.getClippingMaskBufferSize();
const physicalMaskWidth: number =
layoutBoundsOnTex01.width * maskPixelSize;
const physicalMaskHeight: number =
layoutBoundsOnTex01.height * maskPixelSize;
this._tmpBoundsOnModel.setRect(allClippedDrawRect);
if (this._tmpBoundsOnModel.width * ppu > physicalMaskWidth) {
this._tmpBoundsOnModel.expand(allClippedDrawRect.width * MARGIN, 0.0);
scaleX = layoutBoundsOnTex01.width / this._tmpBoundsOnModel.width;
} else {
scaleX = ppu / physicalMaskWidth;
}
if (this._tmpBoundsOnModel.height * ppu > physicalMaskHeight) {
this._tmpBoundsOnModel.expand(
0.0,
allClippedDrawRect.height * MARGIN
);
scaleY = layoutBoundsOnTex01.height / this._tmpBoundsOnModel.height;
} else {
scaleY = ppu / physicalMaskHeight;
}
// マスク生成時に使う行列を求める
this.createMatrixForMask(
isRightHanded,
layoutBoundsOnTex01,
scaleX,
scaleY
);
clipContext._matrixForMask.setMatrix(this._tmpMatrixForMask.getArray());
clipContext._matrixForDraw.setMatrix(this._tmpMatrixForDraw.getArray());
}
}
}
/**
*
* @param isRightHanded
* @param layoutBoundsOnTex01
* @param scaleX
* @param scaleY
*/
public createMatrixForMask(
isRightHanded: boolean,
layoutBoundsOnTex01: csmRect,
scaleX: number,
scaleY: number
): void {
this._tmpMatrix.loadIdentity();
{
// Layout0..1 を -1..1に変換
this._tmpMatrix.translateRelative(-1.0, -1.0);
this._tmpMatrix.scaleRelative(2.0, 2.0);
}
{
// view to Layout0..1
this._tmpMatrix.translateRelative(
layoutBoundsOnTex01.x,
layoutBoundsOnTex01.y
); //new = [translate]
this._tmpMatrix.scaleRelative(scaleX, scaleY); //new = [translate][scale]
this._tmpMatrix.translateRelative(
-this._tmpBoundsOnModel.x,
-this._tmpBoundsOnModel.y
); //new = [translate][scale][translate]
}
// tmpMatrixForMask が計算結果
this._tmpMatrixForMask.setMatrix(this._tmpMatrix.getArray());
this._tmpMatrix.loadIdentity();
{
this._tmpMatrix.translateRelative(
layoutBoundsOnTex01.x,
layoutBoundsOnTex01.y * (isRightHanded ? -1.0 : 1.0)
); //new = [translate]
this._tmpMatrix.scaleRelative(
scaleX,
scaleY * (isRightHanded ? -1.0 : 1.0)
); //new = [translate][scale]
this._tmpMatrix.translateRelative(
-this._tmpBoundsOnModel.x,
-this._tmpBoundsOnModel.y
); //new = [translate][scale][translate]
}
this._tmpMatrixForDraw.setMatrix(this._tmpMatrix.getArray());
}
/**
*
* 使
* 4RGBA56RGBA2,2,1,1
*
* @param usingClipCount
*/
public setupLayoutBounds(usingClipCount: number): void {
const useClippingMaskMaxCount =
this._renderTextureCount <= 1
? ClippingMaskMaxCountOnDefault
: ClippingMaskMaxCountOnMultiRenderTexture * this._renderTextureCount;
if (usingClipCount <= 0 || usingClipCount > useClippingMaskMaxCount) {
if (usingClipCount > useClippingMaskMaxCount) {
// マスクの制限数の警告を出す
CubismLogError(
'not supported mask count : {0}\n[Details] render texture count : {1}, mask count : {2}',
usingClipCount - useClippingMaskMaxCount,
this._renderTextureCount,
usingClipCount
);
}
// この場合は一つのマスクターゲットを毎回クリアして使用する
for (
let index = 0;
index < this._clippingContextListForMask.getSize();
index++
) {
const clipContext: T_ClippingContext =
this._clippingContextListForMask.at(index);
clipContext._layoutChannelNo = 0; // どうせ毎回消すので固定
clipContext._layoutBounds.x = 0.0;
clipContext._layoutBounds.y = 0.0;
clipContext._layoutBounds.width = 1.0;
clipContext._layoutBounds.height = 1.0;
clipContext._bufferIndex = 0;
}
return;
}
// レンダーテクスチャが1枚なら9分割する最大36枚
const layoutCountMaxValue = this._renderTextureCount <= 1 ? 9 : 8;
// 指定された数のレンダーテクスチャを極力いっぱいに使ってマスクをレイアウトするデフォルトなら1
// マスクグループの数が4以下ならRGBA各チャンネルに1つずつマスクを配置し、5以上6以下ならRGBAを2,2,1,1と配置する
let countPerSheetDiv: number = usingClipCount / this._renderTextureCount; // レンダーテクスチャ1枚あたり何枚割り当てるか
let countPerSheetMod: number = usingClipCount % this._renderTextureCount; // この番号のレンダーテクスチャまでに一つずつ配分する
// 小数点は切り捨てる
countPerSheetDiv = ~~countPerSheetDiv;
countPerSheetMod = ~~countPerSheetMod;
// RGBAを順番に使っていく
let div: number = countPerSheetDiv / ColorChannelCount; // 1チャンネルに配置する基本のマスク
let mod: number = countPerSheetDiv % ColorChannelCount; // 余り、この番号のチャンネルまでに一つずつ配分する
// 小数点は切り捨てる
div = ~~div;
mod = ~~mod;
// RGBAそれぞれのチャンネルを用意していく0:R, 1:G, 2:B, 3:A
let curClipIndex = 0; // 順番に設定していく
for (
let renderTextureNo = 0;
renderTextureNo < this._renderTextureCount;
renderTextureNo++
) {
for (let channelNo = 0; channelNo < ColorChannelCount; channelNo++) {
// このチャンネルにレイアウトする数
let layoutCount: number = div + (channelNo < mod ? 1 : 0);
// このレンダーテクスチャにまだ割り当てられていなければ追加する
const checkChannelNo = mod + 1 >= ColorChannelCount ? 0 : mod + 1;
if (layoutCount < layoutCountMaxValue && channelNo == checkChannelNo) {
layoutCount += renderTextureNo < countPerSheetMod ? 1 : 0;
}
// 分割方法を決定する
if (layoutCount == 0) {
// 何もしない
} else if (layoutCount == 1) {
// 全てをそのまま使う
const clipContext: T_ClippingContext =
this._clippingContextListForMask.at(curClipIndex++);
clipContext._layoutChannelNo = channelNo;
clipContext._layoutBounds.x = 0.0;
clipContext._layoutBounds.y = 0.0;
clipContext._layoutBounds.width = 1.0;
clipContext._layoutBounds.height = 1.0;
clipContext._bufferIndex = renderTextureNo;
} else if (layoutCount == 2) {
for (let i = 0; i < layoutCount; i++) {
let xpos: number = i % 2;
// 小数点は切り捨てる
xpos = ~~xpos;
const cc: T_ClippingContext = this._clippingContextListForMask.at(
curClipIndex++
);
cc._layoutChannelNo = channelNo;
// UVを2つに分解して使う
cc._layoutBounds.x = xpos * 0.5;
cc._layoutBounds.y = 0.0;
cc._layoutBounds.width = 0.5;
cc._layoutBounds.height = 1.0;
cc._bufferIndex = renderTextureNo;
}
} else if (layoutCount <= 4) {
// 4分割して使う
for (let i = 0; i < layoutCount; i++) {
let xpos: number = i % 2;
let ypos: number = i / 2;
// 小数点は切り捨てる
xpos = ~~xpos;
ypos = ~~ypos;
const cc = this._clippingContextListForMask.at(curClipIndex++);
cc._layoutChannelNo = channelNo;
cc._layoutBounds.x = xpos * 0.5;
cc._layoutBounds.y = ypos * 0.5;
cc._layoutBounds.width = 0.5;
cc._layoutBounds.height = 0.5;
cc._bufferIndex = renderTextureNo;
}
} else if (layoutCount <= layoutCountMaxValue) {
// 9分割して使う
for (let i = 0; i < layoutCount; i++) {
let xpos = i % 3;
let ypos = i / 3;
// 小数点は切り捨てる
xpos = ~~xpos;
ypos = ~~ypos;
const cc: T_ClippingContext = this._clippingContextListForMask.at(
curClipIndex++
);
cc._layoutChannelNo = channelNo;
cc._layoutBounds.x = xpos / 3.0;
cc._layoutBounds.y = ypos / 3.0;
cc._layoutBounds.width = 1.0 / 3.0;
cc._layoutBounds.height = 1.0 / 3.0;
cc._bufferIndex = renderTextureNo;
}
} else {
// マスクの制限枚数を超えた場合の処理
CubismLogError(
'not supported mask count : {0}\n[Details] render texture count : {1}, mask count : {2}',
usingClipCount - useClippingMaskMaxCount,
this._renderTextureCount,
usingClipCount
);
// SetupShaderProgramでオーバーアクセスが発生するので仮で数値を入れる
// もちろん描画結果は正しいものではなくなる
for (let index = 0; index < layoutCount; index++) {
const cc: T_ClippingContext = this._clippingContextListForMask.at(
curClipIndex++
);
cc._layoutChannelNo = 0;
cc._layoutBounds.x = 0.0;
cc._layoutBounds.y = 0.0;
cc._layoutBounds.width = 1.0;
cc._layoutBounds.height = 1.0;
cc._bufferIndex = 0;
}
}
}
}
}
/**
*
* @param model
* @param clippingContext
*/
public calcClippedDrawTotalBounds(
model: CubismModel,
clippingContext: T_ClippingContext
): void {
// 被クリッピングマスク(マスクされる描画オブジェクト)の全体の矩形
let clippedDrawTotalMinX: number = Number.MAX_VALUE;
let clippedDrawTotalMinY: number = Number.MAX_VALUE;
let clippedDrawTotalMaxX: number = Number.MIN_VALUE;
let clippedDrawTotalMaxY: number = Number.MIN_VALUE;
// このマスクが実際に必要か判定する
// このクリッピングを利用する「描画オブジェクト」がひとつでも使用可能であればマスクを生成する必要がある
const clippedDrawCount: number =
clippingContext._clippedDrawableIndexList.length;
for (
let clippedDrawableIndex = 0;
clippedDrawableIndex < clippedDrawCount;
clippedDrawableIndex++
) {
// マスクを使用する描画オブジェクトの描画される矩形を求める
const drawableIndex: number =
clippingContext._clippedDrawableIndexList[clippedDrawableIndex];
const drawableVertexCount: number =
model.getDrawableVertexCount(drawableIndex);
const drawableVertexes: Float32Array =
model.getDrawableVertices(drawableIndex);
let minX: number = Number.MAX_VALUE;
let minY: number = Number.MAX_VALUE;
let maxX: number = -Number.MAX_VALUE;
let maxY: number = -Number.MAX_VALUE;
const loop: number = drawableVertexCount * Constant.vertexStep;
for (
let pi: number = Constant.vertexOffset;
pi < loop;
pi += Constant.vertexStep
) {
const x: number = drawableVertexes[pi];
const y: number = drawableVertexes[pi + 1];
if (x < minX) {
minX = x;
}
if (x > maxX) {
maxX = x;
}
if (y < minY) {
minY = y;
}
if (y > maxY) {
maxY = y;
}
}
// 有効な点が一つも取れなかったのでスキップ
if (minX == Number.MAX_VALUE) {
continue;
}
// 全体の矩形に反映
if (minX < clippedDrawTotalMinX) {
clippedDrawTotalMinX = minX;
}
if (minY < clippedDrawTotalMinY) {
clippedDrawTotalMinY = minY;
}
if (maxX > clippedDrawTotalMaxX) {
clippedDrawTotalMaxX = maxX;
}
if (maxY > clippedDrawTotalMaxY) {
clippedDrawTotalMaxY = maxY;
}
if (clippedDrawTotalMinX == Number.MAX_VALUE) {
clippingContext._allClippedDrawRect.x = 0.0;
clippingContext._allClippedDrawRect.y = 0.0;
clippingContext._allClippedDrawRect.width = 0.0;
clippingContext._allClippedDrawRect.height = 0.0;
clippingContext._isUsing = false;
} else {
clippingContext._isUsing = true;
const w: number = clippedDrawTotalMaxX - clippedDrawTotalMinX;
const h: number = clippedDrawTotalMaxY - clippedDrawTotalMinY;
clippingContext._allClippedDrawRect.x = clippedDrawTotalMinX;
clippingContext._allClippedDrawRect.y = clippedDrawTotalMinY;
clippingContext._allClippedDrawRect.width = w;
clippingContext._allClippedDrawRect.height = h;
}
}
}
/**
* 使
* @return 使
*/
public getClippingContextListForDraw(): csmVector<T_ClippingContext> {
return this._clippingContextListForDraw;
}
/**
*
* @return
*/
public getClippingMaskBufferSize(): number {
return this._clippingMaskBufferSize;
}
/**
*
* @return
*/
public getRenderTextureCount(): number {
return this._renderTextureCount;
}
/**
* RGBA
* @param channelNo RGBA0:R, 1:G, 2:B, 3:A
*/
public getChannelFlagAsColor(channelNo: number): CubismTextureColor {
return this._channelColors.at(channelNo);
}
/**
*
* @param size
*/
public setClippingMaskBufferSize(size: number): void {
this._clippingMaskBufferSize = size;
}
protected _clearedFrameBufferFlags: csmVector<boolean>; //マスクのクリアフラグの配列
protected _channelColors: csmVector<CubismTextureColor>;
protected _clippingContextListForMask: csmVector<T_ClippingContext>; // マスク用クリッピングコンテキストのリスト
protected _clippingContextListForDraw: csmVector<T_ClippingContext>; // 描画用クリッピングコンテキストのリスト
protected _clippingMaskBufferSize: number; // クリッピングマスクのバッファサイズ(初期値:256
protected _renderTextureCount: number; // 生成するレンダーテクスチャの枚数
protected _tmpMatrix: CubismMatrix44; // マスク計算用の行列
protected _tmpMatrixForMask: CubismMatrix44; // マスク計算用の行列
protected _tmpMatrixForDraw: CubismMatrix44; // マスク計算用の行列
protected _tmpBoundsOnModel: csmRect; // マスク配置計算用の矩形
protected _clippingContexttConstructor: ClippingContextConstructor<T_ClippingContext>;
}

View File

@ -7,6 +7,8 @@
import { CubismMatrix44 } from '../math/cubismmatrix44';
import { CubismModel } from '../model/cubismmodel';
import { csmRect } from '../type/csmrectf';
import { ICubismClippingManager } from './cubismclippingmanager';
/**
*
@ -123,6 +125,24 @@ export abstract class CubismRenderer {
return JSON.parse(JSON.stringify(this._modelColor));
}
/**
*
*
* @param opacity
*
* @return RGBA
*/
getModelColorWithOpacity(opacity: number): CubismTextureColor {
const modelColorRGBA: CubismTextureColor = this.getModelColor();
modelColorRGBA.A *= opacity;
if (this.isPremultipliedAlpha()) {
modelColorRGBA.R *= modelColorRGBA.A;
modelColorRGBA.G *= modelColorRGBA.A;
modelColorRGBA.B *= modelColorRGBA.A;
}
return modelColorRGBA;
}
/**
* α
* truefalse
@ -224,33 +244,6 @@ export abstract class CubismRenderer {
*/
public abstract doDrawModel(): void;
/**
*
*
* @param textureNo
* @param indexCount
* @param vertexCount
* @param indexArray
* @param vertexArray
* @param uvArray uv
* @param opacity
* @param colorBlendMode
* @param invertedMask 使使
*/
public abstract drawMesh(
textureNo: number,
indexCount: number,
vertexCount: number,
indexArray: Uint16Array,
vertexArray: Float32Array,
uvArray: Float32Array,
multiplyColor: CubismTextureColor,
screenColor: CubismTextureColor,
opacity: number,
colorBlendMode: CubismBlendMode,
invertedMask: boolean
): void;
/**
*
*/
@ -278,7 +271,7 @@ export abstract class CubismRenderer {
export enum CubismBlendMode {
CubismBlendMode_Normal = 0, // 通常
CubismBlendMode_Additive = 1, // 加算
CubismBlendMode_Multiplicative = 2, // 乗算
CubismBlendMode_Multiplicative = 2 // 乗算
}
/**
@ -301,6 +294,75 @@ export class CubismTextureColor {
A: number; // αチャンネル
}
/**
*
*/
export abstract class CubismClippingContext {
/**
*
*/
public constructor(clippingDrawableIndices: Int32Array, clipCount: number) {
// クリップしているマスク用のDrawableのインデックスリスト
this._clippingIdList = clippingDrawableIndices;
// マスクの数
this._clippingIdCount = clipCount;
this._allClippedDrawRect = new csmRect();
this._layoutBounds = new csmRect();
this._clippedDrawableIndexList = [];
this._matrixForMask = new CubismMatrix44();
this._matrixForDraw = new CubismMatrix44();
this._bufferIndex = 0;
}
/**
*
* @return
*/
public abstract getClippingManager(): ICubismClippingManager;
/**
*
*/
public release(): void {
if (this._layoutBounds != null) {
this._layoutBounds = null;
}
if (this._allClippedDrawRect != null) {
this._allClippedDrawRect = null;
}
if (this._clippedDrawableIndexList != null) {
this._clippedDrawableIndexList = null;
}
}
/**
*
*
* @param drawableIndex
*/
public addClippedDrawable(drawableIndex: number) {
this._clippedDrawableIndexList.push(drawableIndex);
}
public _isUsing: boolean; // 現在の描画状態でマスクの準備が必要ならtrue
public readonly _clippingIdList: Int32Array; // クリッピングマスクのIDリスト
public _clippingIdCount: number; // クリッピングマスクの数
public _layoutChannelNo: number; // RGBAのいずれのチャンネルにこのクリップを配置するか0:R, 1:G, 2:B, 3:A
public _layoutBounds: csmRect; // マスク用チャンネルのどの領域にマスクを入れるかView座標-1~1, UVは0~1に直す
public _allClippedDrawRect: csmRect; // このクリッピングで、クリッピングされるすべての描画オブジェクトの囲み矩形(毎回更新)
public _matrixForMask: CubismMatrix44; // マスクの位置計算結果を保持する行列
public _matrixForDraw: CubismMatrix44; // 描画オブジェクトの位置計算結果を保持する行列
public _clippedDrawableIndexList: number[]; // このマスクにクリップされる描画オブジェクトのリスト
public _bufferIndex: number; // このマスクが割り当てられるレンダーテクスチャ(フレームバッファ)やカラーバッファのインデックス
}
// Namespace definition for compatibility.
import * as $ from './cubismrenderer';
// eslint-disable-next-line @typescript-eslint/no-namespace

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ import {
CSM_LOG_LEVEL_ERROR,
CSM_LOG_LEVEL_INFO,
CSM_LOG_LEVEL_VERBOSE,
CSM_LOG_LEVEL_WARNING,
CSM_LOG_LEVEL_WARNING
} from '../cubismframeworkconfig';
import { CubismFramework, LogLevel } from '../live2dcubismframework';

View File

@ -12,7 +12,7 @@ import {
JsonMap,
JsonNullvalue,
JsonString,
Value,
Value
} from './cubismjson';
/**