当前位置: 首页 > article >正文

六、模型显示位置与放缩

参考文档

# 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);
}

二、效果展示


http://www.kler.cn/a/451130.html

相关文章:

  • [C/C++]智能指针是什么?实现原理是什么?
  • Modbus数据网关在制造企业的应用与效果
  • Unity 6 中的新增功能
  • 本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——12使用YOLO-Bin
  • window安装TradingView
  • 个人笔记:ORM数据库框架EFCore使用示例,运行通过,附源码
  • thinkphp6使用MongoDB多个数据,聚合查询的坑
  • 国内RPA产品对比
  • 【k8s】访问etcd
  • linux检测硬盘
  • 数据结构---MapSet
  • 【Java基础面试题035】什么是Java泛型的上下界限定符?
  • 批量多线程给TXT文档插入相关腾讯AI【高质量无水印无版权】原创图片
  • 本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——14Controller
  • 15.3、陷阱技术 入侵容忍 隐私保护技术
  • Apache Log4j漏洞复现
  • 对文件内的文件名生成目录,方便查阅
  • es快速扫描
  • 功能全面的跨平台笔记应用:Joplin,开源替代印象笔记与 OneNote
  • CentOS下,离线安装vscode的步骤;
  • Unity开发哪里下载安卓Android-NDK-r21d,外加Android Studio打包实验
  • 创建vue2项目或vue3项目超详细!
  • Spring Boot教程之三十一:入门 Web
  • [机器学习]XGBoost(2)——目标函数(公式详解)
  • Elasticsearch-脚本查询
  • 从测试服务器手动热部署到生产环境的实现