六、模型显示位置与放缩
参考文档
# 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);
#endif
LAppDelegate::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 不触发 logicalDotsPerInchChanged
QScreen *screen = qApp->primaryScreen();
connect(screen,&QScreen::physicalDotsPerInchChanged,this,&MainWindow::onPhysicalDotsPerInchChanged);
// 平移、放缩 Debug
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);
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);
}