1

Qtフレームワーク(4.7.4)を使用して、新しいピクセルデータが画面の最初の行に追加され、前のピクセルが更新ごとに1ピクセル下にスクロールされるスライド表示を実証しようとしています。

1 秒あたり 20 回更新され、更新のたびにランダムな緑色の点 (ピクセル) が黒い背景に描画されます。

問題は; リフレッシュするたびにちらつきが非常に目立ちます。Web で調査し、コードを可能な限り最適化しました。QPainter (QWidget 上) と QGraphicsScene (QGraphicsView 上) の両方でラスター レンダリングを使用しようとしましたが、QGLWidget で OpenGL レンダリングを使用しようとしました。ただし、最後にはまだ同じちらつきの問題があります。

このちらつきの原因は何ですか? LCD モニターが、黒から緑への遷移のためにディスプレイをリフレッシュできないのではないかと疑い始めました。また、黒の代わりに灰色の背景を選択すると、ちらつきが発生しないことにも気付きました。

4

2 に答える 2

1

あなたが見ている効果は、純粋に精神視覚的なものです。これはソフトウェアの欠陥ではなく、人間の欠陥です。私は真剣です。の値を修正することで確認できxます-ウィンドウ上のピックスマップ全体を引き続き再描画しますが、ちらつきはありません-ちらつき自体がないためです。

視覚的なちらつきは、スクロール レートがリアルタイムの経過に関連付けられていない場合に発生します。CPU の負荷やシステム タイマーの不正確さが原因で、更新の間隔が時折異なる場合、ビジュアル システムは 2 つの画像を統合し、全体的な明るさが変化したように見えます。

背景を灰色に設定して画像のコントラスト比を下げると、知覚されるちらつきが減少することが正しくわかりました。これは、効果が精神視覚的であるという追加の手がかりです。

以下は、この影響を防ぐ方法です。スクロール距離がどのように時間に関連付けられているかに注意してください (ここでは 1ms = 1 ピクセル)。

#include <QElapsedTimer>
#include <QPaintEvent>
#include <QBasicTimer>
#include <QApplication>
#include <QPainter>
#include <QPixmap>
#include <QWidget>
#include <QDebug>

static inline int rand(int range) { return (double(qrand()) * range) / RAND_MAX; }

class Widget : public QWidget
{
    float fps;
    qint64 lastTime;
    QPixmap pixmap;
    QBasicTimer timer;
    QElapsedTimer elapsed;
    void timerEvent(QTimerEvent * ev) {
        if (ev->timerId() == timer.timerId()) update();
    }
    void paintEvent(QPaintEvent * ev) {
        qint64 time = elapsed.elapsed();
        qint64 delta = time - lastTime;
        lastTime = time;
        if (delta > 0) {
            const float weight(0.05);
            fps = (1.0-weight)*fps + weight*(1E3/delta);

            if (pixmap.size() != size()) {
                pixmap = QPixmap(size());
                pixmap.fill(Qt::black);
            }
            int dy = qMin((int)delta, pixmap.height());
            pixmap.scroll(0, dy, pixmap.rect());
            QPainter pp(&pixmap);
            pp.fillRect(0, 0, pixmap.width(), dy, Qt::black);
            for(int i = 0; i < 30; ++i){
                int x = rand(pixmap.width());
                pp.fillRect(x, 0, 3, dy, Qt::green);
            }
        }
        QPainter p(this);
        p.drawPixmap(ev->rect(), pixmap, ev->rect());
        p.setPen(Qt::yellow);
        p.fillRect(0, 0, 100, 50, Qt::black);
        p.drawText(rect(), QString("FPS: %1").arg(fps, 0, 'f', 0));
    }

public:
    explicit Widget(QWidget *parent = 0) : QWidget(parent), fps(0), lastTime(0), pixmap(size())
    {
        timer.start(1000/60, this);
        elapsed.start();
        setAttribute(Qt::WA_OpaquePaintEvent);
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}
于 2013-09-10T17:24:44.947 に答える
-1

ピックスマップをその場でスクロールするのではなく、2 つ目のピックスマップを作成しdrawPixmap()、1 行を除くすべてをピックスマップ 1 からピックスマップ 2 に (スクロール オフセットを使用して) コピーするために使用することをお勧めします。次に、ピックスマップ 2 の描画を続けます。フレームの後、両方のピックスマップへの参照を交換し、最初からやり直します。

理論的根拠は、あるメモリ領域から別のメモリ領域へのコピーは、1 つのメモリ領域をその場で変更するよりも簡単に最適化できるということです。

于 2012-04-16T11:55:23.843 に答える