Skip to content

Commit

Permalink
[修复OpenGL视图旋转时的宽高比问题并更新文档]
Browse files Browse the repository at this point in the history
- 重构OpenGL视图旋转处理逻辑,通过预计算旋转后纹理尺寸保持宽高比
- 新增`rotatedTextureSize`函数计算旋转后的纹理尺寸
- 使用`rotationAngle`跟踪旋转角度替代直接修改变换矩阵
- 实现`adjustImageToScreen`方法在旋转后自动调整显示比例
- 修改窗口缩放逻辑,将旋转角度纳入缩放因子计算体系
- 更新README文档结构,合并重复的OpenGL界面说明
- 在文档中补充旋转问题解决方案的技术实现细节
- 移除过时的QVulkanWindow问题描述和重复的界面说明章节
  • Loading branch information
RealChuan committed Feb 19, 2025
1 parent 5a6a06d commit 240dfb1
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 47 deletions.
29 changes: 10 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,34 @@
1. 下载`Actions`中的`Artifacts`文件夹,把`kimg_*`的库文件解压到`Qt`打包目录下的`imageformats`文件夹中;
2. 其余部分库文件,需要放在主程序同级目录下,或者主程序可以加载到的地方。

## QRhiWidget
## 使用`QRhiWidget``QVulkanWindow``QOpenGLWidget`窗口,用GPU渲染2D纹理的优缺点

### 问题
### 优点

#### 旋转
1. 性能比使用QGraphicsView的看图界面要好很多,非常流畅,占用极少的CPU资源;

1. 跟OpenGL看图界面类似,在旋转任意角度的时候,纹理的宽高比会变化,导致显示不正常;
### 缺点

## QVulkanWindow
1. 在旋转任意角度的时候,纹理的宽高比会变化,导致显示不正常;
1. 这个问题在[openglview](src/gpugraphics/openglview.cc)中有一种不太完美的解决方法,可以在任意旋转角度的时候,保持原图的宽高比不变,但是旋转时,需要舍弃原来的缩放比例,调整为适应窗口或者原图大小。
2. 具体实现见[openglview](src/gpugraphics/openglview.cc)中的`rotatedTextureSize``rotateNinetieth``anti_rotateNinetieth`函数。

### 问题
## QVulkanWindow

#### 编译
### 编译问题

1. [cmake](.github/workflows/cmake.yml):在MacOS下会找不到QVulkanWindow相关的头文件,编译无法通过;
2. [qmake](.github/workflows/qmake.yml)
1. 在MacOS下会找不到QVulkanWindowRenderer相关的头文件,编译无法通过;
2. 在Ubuntu下会找不到QVulkanInstance相关的头文件,编译无法通过:

#### 旋转

1. 跟OpenGL看图界面类似,在旋转任意角度的时候,纹理的宽高比会变化,导致显示不正常;
3. 暂时禁止上述情况的编译过程;

## 看图界面

<div align=center>
<img src="docs/ImageView.png" width="90%" height="90%">
</div>

## Opengl看图界面

1. 性能比使用QGraphicsView的看图界面要好很多,非常流畅,占用极少的CPU资源;

### 问题

1. Opengl看图界面,在旋转任意角度的时候,纹理的宽高比会变化,导致显示不正常,这个问题还没解决;

## 马赛克绘制界面(橡皮擦效果)

<div align=center>
Expand Down
72 changes: 44 additions & 28 deletions src/gpugraphics/openglview.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,27 @@ class OpenglView::OpenglViewPrivate
emit q_ptr->scaleFactorChanged(factor);
}

QSize rotatedTextureSize()
{
Q_ASSERT(!image.isNull());
float theta = qDegreesToRadians(rotationAngle);
float cosTheta = qAbs(qCos(theta));
float sinTheta = qAbs(qSin(theta));
float rotatedWidth = image.width() * cosTheta + image.height() * sinTheta;
float rotatedHeight = image.width() * sinTheta + image.height() * cosTheta;
return QSize(rotatedWidth, rotatedHeight);
}

void adjustImageToScreen()
{
auto size = image.size();
if (size.width() > q_ptr->width() || size.height() > q_ptr->height()) {
q_ptr->fitToScreen();
} else {
q_ptr->resetToOriginalSize();
}
}

OpenglView *q_ptr;

QScopedPointer<OpenGLShaderProgram> programPtr;
Expand All @@ -95,6 +116,8 @@ class OpenglView::OpenglViewPrivate

QMatrix4x4 transform;
const qreal scaleFactor = 1.2;
qreal scale = 1.0;
int rotationAngle = 0;
QSize windowSize;

QMenu *menu;
Expand Down Expand Up @@ -132,17 +155,14 @@ void OpenglView::setImageUrl(const QString &imageUrl)
}

d_ptr->image = image.convertedTo(QImage::Format_RGBA8888_Premultiplied);
auto size = d_ptr->image.size();
if (size.width() > width() || size.height() > height()) {
fitToScreen();
} else {
resetToOriginalSize();
}
d_ptr->scale = 1.0;
d_ptr->rotationAngle = 0;
d_ptr->adjustImageToScreen();

d_ptr->uploadTexture();

emit imageUrlChanged(imageUrl);
emit imageSizeChanged(size);
emit imageSizeChanged(d_ptr->image.size());
}

void OpenglView::resetToOriginalSize()
Expand All @@ -151,11 +171,13 @@ void OpenglView::resetToOriginalSize()
return;
}

auto size = d_ptr->image.size();
auto factor_w = static_cast<qreal>(size.width()) / width();
auto factor_h = static_cast<qreal>(size.height()) / height();
auto rotatedSize = d_ptr->rotatedTextureSize();

auto factor_w = static_cast<qreal>(rotatedSize.width()) / width();
auto factor_h = static_cast<qreal>(rotatedSize.height()) / height();
d_ptr->transform.setToIdentity();
d_ptr->transform.scale(factor_w, factor_h, 1.0);
d_ptr->transform.rotate(d_ptr->rotationAngle, 0, 0, 1);
d_ptr->emitScaleFactor();

QMetaObject::invokeMethod(this, [this] { update(); }, Qt::QueuedConnection);
Expand All @@ -167,31 +189,30 @@ void OpenglView::fitToScreen()
return;
}

auto size = d_ptr->image.size();
auto factor_w = static_cast<qreal>(width()) / size.width();
auto factor_h = static_cast<qreal>(height()) / size.height();
auto rotatedSize = d_ptr->rotatedTextureSize();
auto factor_w = static_cast<qreal>(width()) / rotatedSize.width();
auto factor_h = static_cast<qreal>(height()) / rotatedSize.height();
auto factor = qMin(factor_w, factor_h);
d_ptr->transform.setToIdentity();
d_ptr->transform.scale(factor / factor_w, factor / factor_h, 1.0);
d_ptr->transform.rotate(d_ptr->rotationAngle, 0, 0, 1);
d_ptr->emitScaleFactor();

QMetaObject::invokeMethod(this, [this] { update(); }, Qt::QueuedConnection);
}

void OpenglView::rotateNinetieth()
{
d_ptr->transform.rotate(90, 0, 0, 1);
d_ptr->updateTransform();

QMetaObject::invokeMethod(this, [this] { update(); }, Qt::QueuedConnection);
d_ptr->rotationAngle += 90;
d_ptr->rotationAngle %= 360;
d_ptr->adjustImageToScreen();
}

void OpenglView::anti_rotateNinetieth()
{
d_ptr->transform.rotate(-90, 0, 0, 1);
d_ptr->updateTransform();

QMetaObject::invokeMethod(this, [this] { update(); }, Qt::QueuedConnection);
d_ptr->rotationAngle -= 90;
d_ptr->rotationAngle %= 360;
d_ptr->adjustImageToScreen();
}

void OpenglView::initializeGL()
Expand Down Expand Up @@ -224,15 +245,9 @@ void OpenglView::resizeGL(int w, int h)
glViewport(0, 0, w * ratioF, w * ratioF);

if (d_ptr->windowSize.isValid()) {
auto factor_w = static_cast<qreal>(d_ptr->windowSize.width()) / w;
auto factor_h = static_cast<qreal>(d_ptr->windowSize.height()) / h;
d_ptr->transform.scale(factor_w, factor_h, 1.0);
//qDebug() << "resizeGL" << factor_w << factor_h;
d_ptr->emitScaleFactor();
d_ptr->adjustImageToScreen();
}
d_ptr->windowSize = QSize(w, h);

QMetaObject::invokeMethod(this, [this] { update(); }, Qt::QueuedConnection);
}

void OpenglView::paintGL()
Expand Down Expand Up @@ -261,6 +276,7 @@ void OpenglView::wheelEvent(QWheelEvent *event)
}

qreal factor = qPow(d_ptr->scaleFactor, event->angleDelta().y() / 240.0);
d_ptr->scale *= factor;
d_ptr->transform.scale(factor, factor, 1.0);
d_ptr->emitScaleFactor();

Expand Down

0 comments on commit 240dfb1

Please sign in to comment.