第一回 Cubism SDK ワークショップ 設問・解答

開催:2021/08/28(土) 17:00~19:00

第1問 ホーム画面へモデルを表示する

ホーム画面へLive2Dモデルを表示させるために、下記の箇所に処理を追加・修正してください

1. JniBridgeC.cpp
1.1:nativeOnSurfaceCreated 関数

JNIEXPORT void JNICALL
Java_com_live2d_demo_JniBridgeJava_nativeOnSurfaceCreated
(JNIEnv *env, jclass type)
{

}

1.2:nativeOnSurfaceChanged 関数

JNIEXPORT void JNICALL
Java_com_live2d_demo_JniBridgeJava_nativeOnSurfaceChanged(JNIEnv *env, jclass type, jint width, jint height)
{

}

1.3:nativeOnDrawFrame 関数

JNIEXPORT void JNIC Java_com_live2d_demo_JniBridgeJava_nativeOnDrawFrame(JNIEnv *env, jclass type)
{

}


2. LWallpaperDelegate.cpp
2.1:Run 関数内「画面の初期化処理」の下のコメントアウトされている処理を動作する状態に

void LWallpaperDelegate::Run()
{
   // 時間更新
   LWallpaperPal::UpdateTime();

   // 画面の初期化
   //glClearColor(_r, _g, _b, 1.0f);
   //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   //glClearDepthf(1.0f);

   //描画更新
   if (_view)
   {
       _view->Render();
   }
}


ヒント

・JniBridgeC.cpp は LWallpaperDelegate クラスの関数の呼び出しを行い、JNIを利用してJavaと接続するクラスです。
・グラフィックAPIは OpenGL を利用しています。
    ・画面の初期化処理はすなわち、 OpenGL の初期化です。
    必要な処理は色情報の初期化、バッファの初期化、
    深度情報の初期化です。


想定解答

1.1:

JNIEXPORT void JNICALL
Java_com_live2d_demo_JniBridgeJava_nativeOnSurfaceCreated
(JNIEnv *env, jclass type)
{
   LWallpaperDelegate::GetInstance()->OnSurfaceCreate();
}

1.2:

JNIEXPORT void JNICALL
Java_com_live2d_demo_JniBridgeJava_nativeOnSurfaceChanged(JNIEnv *env, jclass type, jint width, jint height)
{
   LWallpaperDelegate::GetInstance()->OnSurfaceChanged(width, height);
}

1.3:

JNIEXPORT void JNIC Java_com_live2d_demo_JniBridgeJava_nativeOnDrawFrame(JNIEnv *env, jclass type)
{
   LWallpaperDelegate::GetInstance()->Run();
}

2.1:

void LWallpaperDelegate::Run()
{
   // 時間更新
   LWallpaperPal::UpdateTime();

   // 画面の初期化
   glClearColor(_r, _g, _b, 1.0f);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glClearDepthf(1.0f);

   //描画更新
   if (_view)
   {
       _view->Render();
   }
}


第2問 スクリーン起動時にランダムなモーションを再生する

●モデルにモーションをさせるための処理とその処理を利用する部分を下記の箇所に追加してください

1. LWallpaperModel クラスの StartMotion 関数内
1.1:476行目

//ex) idle_0
csmString name = Utils::CubismString::GetFormatedString("%s_%d", group, no);
CubismMotion* motion; [476行目]
csmBool autoDelete = false;

1.2:484行目

if (!motion)
{
   csmString path = fileName;
   path = csmString(_currentModelDirectory.c_str()) + path;


[484行目]


csmFloat32 fadeTime = _modelJson->GetMotionFadeInTimeValue(group, no);

1.3:499行目

    autoDelete = true; // 終了時にメモリから削除


   [499行目]
}

motion->SetFinishedMotionHandler(onFinishedMotionHandler);


2. JniBridgeC.cpp
2.1:nativeStartRandomMotion 関数

JNIEXPORT void JNICALL
Java_com_live2d_demo_JniBridgeJava_nativeStartRandomMotion(JNIEnv *env, jclass type)
{

}


ヒント

・モデルのセットアップ時に_motionsへモーションがグループ名+番号で登録されています。
・変数 motion に代入する場合、明示的・静的なキャストが必要です。
・1.2と1.3ではバッファの作成・削除を行う必要があります。必要な場合はPreloadMotionGroup 関数の処理を確認してください。


●想定解答

1.1:

//ex) idle_0
csmString name = Utils::CubismString::GetFormatedString("%s_%d", group, no);
CubismMotion* motion = static_cast<CubismMotion*>(_motions[name.GetRawString()]);
csmBool autoDelete = false;

1.2:

if (!motion)
{
   csmString path = fileName;
   path = csmString(_currentModelDirectory.c_str()) + path;


   csmByte* buffer;
   csmSizeInt size;
   buffer = CreateBuffer(path.GetRawString(), &size);
   motion = static_cast<CubismMotion*>(LoadMotion(buffer, size, nullptr));

csmFloat32 fadeTime = _modelJson->GetMotionFadeInTimeValue(group, no);

1.3:

    autoDelete = true; // 終了時にメモリから削除


   DeleteBuffer(buffer, path.GetRawString());
}

motion->SetFinishedMotionHandler(onFinishedMotionHandler);

2.1:

JNIEXPORT void JNICALL
Java_com_live2d_demo_JniBridgeJava_nativeStartRandomMotion(JNIEnv *env, jclass type)
{
   LWallpaperDelegate::GetInstance()->StartRandomMotion();
}


第3問 視線追従・ボディをタップ時にモーションを再生

●画面をタップ・ドラッグした際に機能するように下記の箇所に処理を追加してください。

1. LWallpaperView.cpp
1.1:OnTouchesBegan 関数

void LWallpaperView::OnTouchesBegan(float pointX, float pointY) const
{

}

1.2:OnTouchesMoved 関数

void LWallpaperView::OnTouchesMoved(float pointX, float pointY) const
{

}

1.3:OnTouchesEnded 関数内「シングルタップ」コメントの下

Csm::CubismVector2 LWallpaperView::OnTouchesEnded(float pointX, float pointY)
{
   // タッチ終了
   LWallpaperLive2DManager* live2DManager = LWallpaperLive2DManager::GetInstance();
   live2DManager->OnDrag(0.0f, 0.0f);

   // シングルタップ
   float x=0.0f; // 論理座標変換した座標を取得。
   float y=0.0f; // 論理座標変換した座標を取得。

   return {x,y};
}


●ヒント

・変数 _touchManager はデバイス座標に対するアクションを包括するクラスのインスタンスを保持しています。
・OnTouchesBegan 関数、OnTouchesMoved 関数、OnTouchesEnded 関数の引数はデバイス座標です。
・ドラッグ時にはビュー座標を、タップ終了時にはスクリーン座標を利用した処理が必要となります。


●想定解答

1.1:

void LWallpaperView::OnTouchesBegan(float pointX, float pointY) const
{
   _touchManager->TouchesBegan(pointX, pointY);
}

1.2:

void LWallpaperView::OnTouchesMoved(float pointX, float pointY) const
{
   float viewX = this->TransformViewX(_touchManager->GetX());
   float viewY = this->TransformViewY(_touchManager->GetY());

   _touchManager->TouchesMoved(pointX, pointY);
   LWallpaperLive2DManager::GetInstance()->OnDrag(viewX, viewY);

}

1.3:

Csm::CubismVector2 LWallpaperView::OnTouchesEnded(float pointX, float pointY)
{
   // タッチ終了
   LWallpaperLive2DManager* live2DManager = LWallpaperLive2DManager::GetInstance();
   live2DManager->OnDrag(0.0f, 0.0f);

   // シングルタップ
   float x=0.0f; // 論理座標変換した座標を取得。
   float y=0.0f; // 論理座標変換した座標を取得。

   float x = _deviceToScreen->TransformX(_touchManager->GetX());
   float y = _deviceToScreen->TransformY(_touchManager->GetY());

   live2DManager->OnTap(x, y);

   return {x,y};
}


第4問 ホームボタンorマルチタスクボタン押下時に背景色の変更・背景画像の表示切り替え

●背景色の変更の処理と背景画像が表示・非表示を切り替えられるような処理を下記の箇所に追加してください。

1. LWallpaperDelegate.cpp
1.1:SetClearColor 関数

void LWallpaperDelegate::SetClearColor(float r, float g, float b)
{
   //カラー情報を設定

}

1.2:SetBackGroundSpriteAlpha 関数

void LWallpaperDelegate::SetBackGroundSpriteAlpha(float a)
{

}

2. LWallpaperView.cpp
2.1:SetBackGroundSpriteColor 関数

void LWallpaperView::SetBackGroundSpriteColor(float r, float g, float b, float a)
{

}

2.2:116行目

LWallpaperTextureManager* textureManager = LWallpaperDelegate::GetInstance()->GetTextureManager();


const string resourcesPath = ResourcesPath;

string imageName = BackImageName;
[116行目]

float x = width * 0.5f;
float y = height * 0.5f;

2.3:123行目

float x = width * 0.5f;
float y = height * 0.5f;
float fWidth = width;
float fHeight = height;

[123行目]

// 画面全体を覆うサイズ
x = width * 0.5f;
y = height * 0.5f;

2.4:152行目

void LWallpaperView::Render()
{
   LWallpaperLive2DManager* Live2DManager = LWallpaperLive2DManager::GetInstance();

[152行目]

   // Cubism更新・描画
   Live2DManager->OnUpdate();


●ヒント

・色情報を保存する変数として_r,_g,_bを用意しています。
・背景画像の情報を保持する変数として_backgroundImageを用意しています。
・背景画像の色情報を変える必要はありません。
・画像を読み込む場合はLWallpapaerTextureManagerクラスのCreateTextureFromPngFile関数を利用します
・画像を実際に利用するにはLWallpapaerSprite型の実体を作成する必要があります


●想定解答

1.1:

void LWallpaperDelegate::SetClearColor(float r, float g, float b)
{
   //カラー情報を設定
   _r = r;
   _g = g;
   _b = b;
}

1.2:

void LWallpaperDelegate::SetBackGroundSpriteAlpha(float a)
{
   if (_view)
   {
       _view->SetBackGroundSpriteColor(1.0f,1.0f,1.0f,a);
   }
}

2.1:

void LWallpaperView::SetBackGroundSpriteColor(float r, float g, float b, float a)
{
  if (_backgroundImage)
  {
      _backgroundImage->SetColor(r, g, b, a);
  }
}

2.2:

LWallpaperTextureManager* textureManager = LWallpaperDelegate::GetInstance()->GetTextureManager();


const string resourcesPath = ResourcesPath;

string imageName = BackImageName;
LWallpaperTextureManager::TextureInfo* backgroundTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);

float x = width * 0.5f;
float y = height * 0.5f;

2.3:

float x = width * 0.5f;
float y = height * 0.5f;
float fWidth = width;
float fHeight = height;

if(_backgroundImage == NULL)
{
   _backgroundImage = new LWallpaperSprite(x, y, fWidth, fHeight, backgroundTexture->id, _programId);
}
else
{
   _backgroundImage->ReSize(x, y, fWidth, fHeight);
}

_backgroundImage->SetColor(1.0f, 1.0f, 1.0f, 0.0f);

// 画面全体を覆うサイズ
x = width * 0.5f;
y = height * 0.5f;

2.4:

void LWallpaperView::Render()
{
   LWallpaperLive2DManager* Live2DManager = LWallpaperLive2DManager::GetInstance();

   _backgroundImage->Render();

   // Cubism更新・描画
   Live2DManager->OnUpdate();


第5項 重力加速度の値・向きに応じたパラメータ変更とモデル位置変更

●重力加速度の値と方向(X方向のみ)に応じてモデルの位置やパラメータを変化させられるように処理を下記の箇所に追加してください。

1. LWallpaperModel.cpp
1.1:Update 関数
  「// 重力加速度を-1~1の範囲になるよう正規化」以下

void LWallpaperModel::Update()
{
   const csmFloat32 deltaTimeSeconds = LWallpaperPal::GetDeltaTime();
   _userTimeSeconds += deltaTimeSeconds;

   _dragManager->Update(deltaTimeSeconds);
   _dragX = _dragManager->GetX();
   _dragY = _dragManager->GetY();

   LWallpaperDelegate* delegateInstance = LWallpaperDelegate::GetInstance();
   delegateInstance->ParameterResetCount();

   // 重力加速度を-1~1の範囲になるよう正規化


   // モーションによるパラメータ更新の有無
   csmBool motionUpdated = false;

1.2:Update 関数 「// 重力加速度による向きと位置の調整」内

// 重力加速度による向きと位置の調整
{
   // 10倍した値を設定


   // 顔の向きの調整
   // -10から10の値を加える

   // 体の向きの調整
   // -10から10の値を加える

   // 目の向きの調整
   // -1から1の値を加える

   // 範囲を超えないように設定

   //モデルの位置を設定

}

_model->SaveParameters(); // 状態を保存

1.3:SetGravitationalAccelerationX 関数

void LWallpaperModel::SetGravitationalAccelerationX(Csm::csmFloat32 gravity)
{

}


●ヒント

重力加速度(X方向)の大きさを保存する変数として_gravitationalAccelerationX を用意しています。
・重力加速度の大きさの最大値として定数 gravityMaxValue を用意しています。
・正規化された重力加速度の大きさの範囲制限用の定数としてgravitationalAccelerationRange を用意しています。
・範囲制限は CubismMath::RangeF 関数を利用することで実装出来ます。
・モデルの位置を設定したい場合は ModelMatrix クラスのインスタンスを保持する変数 _modelMatrixを利用してください。

・想定解答
1.1:

void LWallpaperModel::Update()
{
   const csmFloat32 deltaTimeSeconds = LWallpaperPal::GetDeltaTime();
   _userTimeSeconds += deltaTimeSeconds;
   _dragManager->Update(deltaTimeSeconds);
   _dragX = _dragManager->GetX();
   _dragY = _dragManager->GetY();
   LWallpaperDelegate* delegateInstance = LWallpaperDelegate::GetInstance();
   delegateInstance->ParameterResetCount();
   // 重力加速度を-1~1の範囲になるよう正規化
   _gravitationalAccelerationX = _gravitationalAccelerationX / gravityMaxValue;
   // モーションによるパラメータ更新の有無
   csmBool motionUpdated = false;


1.2:

// 重力加速度による向きと位置の調整
{
   // 10倍した値を設定
   csmFloat32 accelValue = _gravitationalAccelerationX * calculationReferenceNumber;
   // 顔の向きの調整
   _model->AddParameterValue(_idParamAngleX, accelValue); // -10から10の値を加える
   // 体の向きの調整
   _model->AddParameterValue(_idParamBodyAngleX, accelValue); // -10から10の値を加える
   // 目の向きの調整
   _model->AddParameterValue(_idParamEyeBallX, -_gravitationalAccelerationX); // -1から1の値を加える
   // 範囲を超えないように設定
   _gravitationalAccelerationX = CubismMath::RangeF(_gravitationalAccelerationX,-gravitationalAccelerationRange,gravitationalAccelerationRange);
   //モデルの位置を設定
   _modelMatrix->SetX(-_gravitationalAccelerationX / 2.0f);
}
_model->SaveParameters(); // 状態を保存


1.3:

void LWallpaperModel::SetGravitationalAccelerationX(Csm::csmFloat32 gravity)
{
   _gravitationalAccelerationX = gravity;
}


・開催後アンケート
https://docs.google.com/forms/d/e/1FAIpQLScrgWZX4N20VhnI3w8gP7nOftgL2fh1QMAvAvAj4bzedyKGFQ/viewform


この記事が気に入ったらサポートをしてみませんか?