hy clear Blog

【Android】Live2D Cubism SDK for Javaのカスタマイズ集

2024/07/19

2024/07/22

📰 アフィリエイト広告を利用しています

はじめに

OpenGLやLive2Dに関する知識はないので、使用するときは自己責任でお願いします。

使用した元のコードは以下のコード参照。忘れたときようのメモ

背景を透明にする

GLSurfaceViewの設定とLAppDelegateのrun()関数を修正する

MainActivity.kt
_glSurfaceView = GLSurfaceView(applicationContext)
_glSurfaceView.setEGLContextClientVersion(2)        
_glSurfaceView.apply {
    setEGLConfigChooser(8, 8, 8, 8, 16, 0)
    holder.setFormat(android.graphics.PixelFormat.TRANSLUCENT)
    setZOrderOnTop(true)
}
LAppDelegate.java
public void run() {
    // ....

    // glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // 透明な背景を指定
}

表示倍率を変更

表示範囲内でモデルのサイズの縮小・拡大

LAppLive2DManager
public void changeScene(int index) {
    // ...

    // 大きさを3倍
    models.get(0).getModelMatrix().scaleRelative(3.0f, 3.0f);

}

表示位置の変更

3倍表示の時1.0fの設定で画面に行ってしまったので値は小さな値で確認する。

LAppLive2DManager
public void changeScene(int index) {
    // ...

    // 表示位置を移動   
    models.get(0).getModelMatrix().translateRelative(0f, -0.7f);

}

モーションの実行

現在のモデルを取得し、モーションを再生させる。

val currentModelId = LAppLive2DManager.getInstance().currentModel
val model: LAppModel = LAppLive2DManager.getInstance().getModel(currentModelId)
model.startMotion("LipSync", 0, 100)

リップシンク

以下のvolume変数を変えると口の開き具合が変わる。
範囲は0.0fから1.0f

LAppModel.java
public void update(){
    // ...
    // 160行目
    float value = 0.0f;
}

MediaPlayerとVisualizerを使って再生している音声にシンクする。
LipSyncを作成

LipSync.kt
class LipSync(private val mediaPlayerId: Int) {
    private var visualizer: Visualizer? = null
    fun start() {
        visualizer = Visualizer(mediaPlayerId)
        visualizer?.setCaptureSize(Visualizer.getCaptureSizeRange()[1])

        val model = LAppLive2DManager.getInstance().getModel(0)
        visualizer?.setDataCaptureListener(object : Visualizer.OnDataCaptureListener {
            override fun onWaveFormDataCapture(
                visualizer: Visualizer,
                bytes: ByteArray,
                samplingRate: Int
            ) {
                // 波形データの平均値を計算
                var sum = 0L
                bytes.forEach { value ->
                    sum += kotlin.math.abs(value.toInt()) // 波形データの絶対値を取得し、合計に加算
                }
                val average = sum / bytes.size.toDouble() // 平均値を計算
                // 平均値を音声の大きさとして利用
                var volume =
                    1 - (average / Byte.MAX_VALUE) // 波形データはバイト型の範囲で表現されるため、最大値で割って正規化する
                // 音声の大きさを利用して必要な処理を行う
                volume *= 2
                if (volume > 1) {
                    volume = 1.0
                }
                model.volume = volume.toFloat()
            }

            override fun onFftDataCapture(
                visualizer: Visualizer,
                bytes: ByteArray,
                samplingRate: Int
            ) {
            }
        }, Visualizer.getMaxCaptureRate(), true, true)
        visualizer?.setEnabled(true);
    }

    fun dispose() {
        visualizer?.release()
        val model = LAppLive2DManager.getInstance().getModel(0)
        model.volume = 0.0f
    }
}

リップシンクを設定して音声を再生する。

var mediaPlayer = MediaPlayer.create(context, R.row.audio_file).apply {
            setAudioAttributes(
                AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                    .setUsage(AudioAttributes.USAGE_MEDIA)
                    .build()
            )
        }
        val lipSync = LipSync(mediaPlayer.audioSessionId)
        lipSync.start()
        mediaPlayer.setOnCompletionListener {
            mediaPlayer.release()
            mediaPlayer = null
            lipSync.dispose()
        }
        mediaPlayer.start()