参考文档
# https://docs.live2d.com/zh-CHS/cubism-sdk-manual/layout/
查看 LAppLive2DManager.cpp 中的 ChangeScene 方法,
void LAppLive2DManager::ChangeScene(Csm::csmInt32 index)
{_sceneIndex = index;if (DebugLogEnable){LAppPal::PrintLog("[APP]model index: %d", _sceneIndex);}// ModelDir[]に保持したディレクトリ名から// model3.jsonのパスを決定する.// ディレクトリ名とmodel3.jsonの名前を一致させておくこと.std::string model = ModelDir[index];std::string modelPath = ResourcesPath + model + "/";std::string modelJsonName = ModelDir[index];modelJsonName += ".model3.json";ReleaseAllModel();_models.PushBack(new LAppModel());_models[0]->LoadAssets(modelPath.c_str(), modelJsonName.c_str());/** モデル半透明表示を行うサンプルを提示する。* ここでUSE_RENDER_TARGET、USE_MODEL_RENDER_TARGETが定義されている場合* 別のレンダリングターゲットにモデルを描画し、描画結果をテクスチャとして別のスプライトに張り付ける。*/{
#if defined(USE_RENDER_TARGET)// LAppViewの持つターゲットに描画を行う場合、こちらを選択LAppView::SelectTarget useRenderTarget = LAppView::SelectTarget_ViewFrameBuffer;
#elif defined(USE_MODEL_RENDER_TARGET)// 各LAppModelの持つターゲットに描画を行う場合、こちらを選択LAppView::SelectTarget useRenderTarget = LAppView::SelectTarget_ModelFrameBuffer;
#else// デフォルトのメインフレームバッファへレンダリングする(通常)LAppView::SelectTarget useRenderTarget = LAppView::SelectTarget_None;
#endif#if defined(USE_RENDER_TARGET) || defined(USE_MODEL_RENDER_TARGET)// モデル個別にαを付けるサンプルとして、もう1体モデルを作成し、少し位置をずらす_models.PushBack(new LAppModel());_models[1]->LoadAssets(modelPath.c_str(), modelJsonName.c_str());_models[1]->GetModelMatrix()->TranslateX(0.2f);
#endifLAppDelegate::GetInstance()->GetView()->SwitchRenderingTarget(useRenderTarget);// 別レンダリング先を選択した際の背景クリア色float clearColor[3] = { 1.0f, 1.0f, 1.0f };LAppDelegate::GetInstance()->GetView()->SetRenderTargetClearColor(clearColor[0], clearColor[1], clearColor[2]);}
}
我们可以通过调整 ModelMatrix 成员属性来进行平移或者放缩,
_models[0]->GetModelMatrix()->ScaleRelative(0.5f,0.5f);
_models[0]->GetModelMatrix()->TranslateX(1.15f);
_models[0]->GetModelMatrix()->TranslateY(-0.40f);
/**
* @brief 現在のシーンで保持しているモデルを返す
*
* @param[in] no モデルリストのインデックス値
* @return モデルのインスタンスを返す。インデックス値が範囲外の場合はNULLを返す。
*/
LAppModel* GetModel(Csm::csmUint32 no) const;
一、平移、放缩实现
我们创建一个全屏、透明、无边框且始终在最前端的主窗口作为示例:窗口包含一个自定义的OpenGL小部件作为中心部件,并添加了三个滑块用于调试平移和缩放功能。这些滑块分别控制缩放、X轴平移和Y轴平移,并通过信号和槽机制将滑块值变化与相应的槽函数连接起来。
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);setGeometry(QRect(-1,-1,QGuiApplication::primaryScreen()->size().width() + 2, QGuiApplication::primaryScreen()->size().height() + 2));setAttribute(Qt::WA_TranslucentBackground);setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);myopengl = new MyOpenGL(this);setCentralWidget(myopengl);// 切换缩放比时,EnableHighDpiScaling 会触发 physicalDotsPerInchChanged// 此时 Qt6 不触发 logicalDotsPerInchChangedQScreen *screen = qApp->primaryScreen();connect(screen,&QScreen::physicalDotsPerInchChanged,this,&MainWindow::onPhysicalDotsPerInchChanged);// 平移、放缩 Debugint availableWidth = QGuiApplication::primaryScreen()->availableGeometry().width();int availableHeight = QGuiApplication::primaryScreen()->availableGeometry().height();QSlider *scaleSlider = new QSlider(this);scaleSlider->setOrientation(Qt::Horizontal);scaleSlider->setMaximum(200);scaleSlider->setMinimum(-200);scaleSlider->setSingleStep(10);scaleSlider->setGeometry((availableWidth - 100)/2, (availableHeight - 50)/2, 100, 50);connect(scaleSlider,&QSlider::valueChanged,this,&MainWindow::onScaleValueChanged);QSlider *translateXSlider = new QSlider(this);translateXSlider->setOrientation(Qt::Horizontal);translateXSlider->setMaximum(200);translateXSlider->setMinimum(-200);translateXSlider->setSingleStep(10);translateXSlider->setGeometry((availableWidth - 100)/2, (availableHeight - 50)/2 - 100, 100, 50);connect(translateXSlider,&QSlider::valueChanged,this,&MainWindow::onTranslateXValueChanged);QSlider *translateYSlider = new QSlider(this);translateYSlider->setOrientation(Qt::Horizontal);translateYSlider->setMaximum(200);translateYSlider->setMinimum(-200);translateYSlider->setSingleStep(10);translateYSlider->setGeometry((availableWidth - 100)/2, (availableHeight - 50)/2 - 200, 100, 50);connect(translateYSlider,&QSlider::valueChanged,this,&MainWindow::onTranslateYValueChanged);
}
以下是代码的详细解析,
设置窗口属性
ui->setupUi(this)
:设置用户界面。setGeometry(QRect(-1, -1, QGuiApplication::primaryScreen()->size().width() + 2, QGuiApplication::primaryScreen()->size().height() + 2))
:- 设置窗口的几何形状,使其覆盖整个屏幕。
setAttribute(Qt::WA_TranslucentBackground)
:- 设置窗口背景为透明。
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint)
:- 设置窗口无边框,并始终保持在最前端。
创建和设置OpenGL小部件
myopengl = new MyOpenGL(this)
:- 创建一个自定义的OpenGL小部件。
setCentralWidget(myopengl)
:- 将OpenGL小部件设置为主窗口的中心部件。
处理高DPI缩放
QScreen *screen = qApp->primaryScreen()
:- 获取主屏幕对象。
connect(screen, &QScreen::physicalDotsPerInchChanged, this, &MainWindow::onPhysicalDotsPerInchChanged)
:- 连接信号
physicalDotsPerInchChanged
到槽函数onPhysicalDotsPerInchChanged
,当物理DPI变化时触发。
- 连接信号
调试平移和缩放功能
- 获取可用屏幕宽度和高度:
int availableWidth = QGuiApplication::primaryScreen()->availableGeometry().width()
int availableHeight = QGuiApplication::primaryScreen()->availableGeometry().height()
创建并配置缩放滑块
QSlider *scaleSlider = new QSlider(this)
:- 创建一个水平滑块用于缩放。
- 设置滑块属性:
scaleSlider->setOrientation(Qt::Horizontal)
scaleSlider->setMaximum(200)
scaleSlider->setMinimum(-200)
scaleSlider->setSingleStep(10)
scaleSlider->setGeometry((availableWidth - 100)/2, (availableHeight - 50)/2, 100, 50)
- 连接滑块值变化信号到槽函数:
connect(scaleSlider, &QSlider::valueChanged, this, &MainWindow::onScaleValueChanged)
创建并配置X轴平移滑块
QSlider *translateXSlider = new QSlider(this)
:- 创建一个水平滑块用于X轴平移。
- 设置滑块属性:
translateXSlider->setOrientation(Qt::Horizontal)
translateXSlider->setMaximum(200)
translateXSlider->setMinimum(-200)
translateXSlider->setSingleStep(10)
translateXSlider->setGeometry((availableWidth - 100)/2, (availableHeight - 50)/2 - 100, 100, 50)
- 连接滑块值变化信号到槽函数:
connect(translateXSlider, &QSlider::valueChanged, this, &MainWindow::onTranslateXValueChanged)
创建并配置Y轴平移滑块
QSlider *translateYSlider = new QSlider(this)
:- 创建一个水平滑块用于Y轴平移。
- 设置滑块属性:
translateYSlider->setOrientation(Qt::Horizontal)
translateYSlider->setMaximum(200)
translateYSlider->setMinimum(-200)
translateYSlider->setSingleStep(10)
translateYSlider->setGeometry((availableWidth - 100)/2, (availableHeight - 50)/2 - 200, 100, 50)
- 连接滑块值变化信号到槽函数:
connect(translateYSlider, &QSlider::valueChanged, this, &MainWindow::onTranslateYValueChanged)
void MainWindow::onPhysicalDotsPerInchChanged(qreal dpi)
{//resize(QGuiApplication::primaryScreen()->availableGeometry().size());resize(QGuiApplication::primaryScreen()->size().width() + 2, QGuiApplication::primaryScreen()->size().height() + 2);
}void MainWindow::onScaleValueChanged(int value)
{// Scale [0,1]qDebug() << "Scale Value " << value * 0.01f;LAppLive2DManager::GetInstance()->GetModel(0)->GetModelMatrix()->Scale(value*0.01f,value*0.01f);}void MainWindow::onTranslateXValueChanged(int value)
{// TranslateX [-2,2]qDebug() << "TranslateX Value " << value * 0.01f;LAppLive2DManager::GetInstance()->GetModel(0)->GetModelMatrix()->TranslateX(value*0.01f);}
void MainWindow::onTranslateYValueChanged(int value)
{// TranslateY [-2,2]qDebug() << "TranslateY Value " << value * 0.01f;LAppLive2DManager::GetInstance()->GetModel(0)->GetModelMatrix()->TranslateY(value*0.01f);
}