Qt3D曲面正反面贴图例程

发布时间 2023-09-06 20:29:02作者: 兜尼完

主要利用GLSL中的内置变量gl_FrontFacing区分正反面。下面是正面反面效果图:

头文件:

class QOpenGLShaderProgram;
class QOpenGLTexture;

//---------------------------------------------------------------------------------------
// 显示图片
//---------------------------------------------------------------------------------------
class MzOpenGLWidget : public QOpenGLWidget, private QOpenGLFunctions
{
    Q_OBJECT
    Q_PROPERTY(float rotate READ rotate WRITE setRotate)

public:
    MzOpenGLWidget(QWidget* parent = 0);
    ~MzOpenGLWidget();
    float rotate() const;
    void setRotate(float value);

private:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int w, int h) override;
    float calcRawRatio();

private:
    QOpenGLShaderProgram* program;
    QOpenGLTexture *textureFr;
    QOpenGLTexture *textureBk;
    float angle;
};

CPP文件:

MzOpenGLWidget::MzOpenGLWidget(QWidget* parent) :
    QOpenGLWidget(parent), angle(0)
{
    QPropertyAnimation* ani = new QPropertyAnimation(this, "rotate", this);
    ani->setStartValue(0.0);
    ani->setEndValue(360.0);
    ani->setLoopCount(-1);
    ani->setDuration(4000);
    ani->start(QAbstractAnimation::DeleteWhenStopped);
}

MzOpenGLWidget::~MzOpenGLWidget()
{
    delete textureFr;
    delete textureBk;
}

void MzOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glEnable(GL_DEPTH_TEST);
    glClearColor(0.1, 0.1, 0.1, 1.0);

    program = new QOpenGLShaderProgram(this);
    const char* vsrc = R"(
        in vec4 pos;
        in vec2 itextCoor;
        varying vec2 otextCoor;
        uniform mat4 trans;
        void main() {
            gl_Position = trans * pos;
            otextCoor = itextCoor;
        })";
    program->addShaderFromSourceCode(QOpenGLShader::Vertex, vsrc);
    const char* fsrc = R"(
        uniform sampler2D imageFr;
        uniform sampler2D imageBk;
        varying vec2 otextCoor;
        void main() {
            gl_FragColor = gl_FrontFacing ? texture2D(imageFr, otextCoor) : texture2D(imageBk, otextCoor);
        })";
    program->addShaderFromSourceCode(QOpenGLShader::Fragment, fsrc);

    QImage frImage(240, 240, QImage::Format_RGB888);
    frImage.fill(Qt::red);
    textureFr = new QOpenGLTexture(frImage);
    textureFr->setMinificationFilter(QOpenGLTexture::Linear); /* 缩小图片插值方法 */
    textureFr->setMagnificationFilter(QOpenGLTexture::Nearest); /* 放大图片插值方法 */
    textureFr->setWrapMode(QOpenGLTexture::Repeat);

    QImage bkImage(240, 240, QImage::Format_RGB888);
    bkImage.fill(Qt::blue);
    textureBk = new QOpenGLTexture(bkImage);
    textureBk->setMinificationFilter(QOpenGLTexture::Linear); /* 缩小图片插值方法 */
    textureBk->setMagnificationFilter(QOpenGLTexture::Nearest); /* 放大图片插值方法 */
    textureBk->setWrapMode(QOpenGLTexture::Repeat);

    program->link();
    program->bind();
}

void MzOpenGLWidget::paintGL()
{
    GLfloat vertices[] =
    {
        -0.8f, 0.8f,
        -0.8f, -0.8f,
        0.8f, 0.8f,
        0.8f, -0.8f,
    };
    GLfloat coors[] = /* 此数组和vertices数组一一对应 */
    {
        0.0f, 0.0f,
        0.0f, 1.0f,
        1.0f, 0.0f,
        1.0f, 1.0f,
    };

    QMatrix4x4 matrix;
    matrix.perspective(53.1300964f, 1.0f, 0.1f, 100.0f);
    matrix.translate(0, 0, -2);
    matrix.rotate(angle, 0, 1, 0);
    program->setUniformValue("trans", matrix);
    program->enableAttributeArray("trans");

    program->setAttributeArray("pos", vertices, 2);
    program->enableAttributeArray("pos");
    program->setAttributeArray("itextCoor", coors, 2);
    program->enableAttributeArray("itextCoor");
    program->setUniformValue("imageFr", 0);
    program->setUniformValue("imageBk", 1);
    textureFr->bind(0);
    textureBk->bind(1);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

void MzOpenGLWidget::resizeGL(int w, int h)
{
}

float MzOpenGLWidget::rotate() const
{
    return angle;
}

void MzOpenGLWidget::setRotate(float value)
{
    angle = value;
    update();
}

float MzOpenGLWidget::calcRawRatio()
{
    float a = 50, b = 55; /* f(a) < 1, f(b) > 1 */
    while (fabs(a - b) >= 0.00001f)
    {
        float c = (a + b) / 2;
        QMatrix4x4 matrix;
        matrix.perspective(c, 1.0f, 0.1f, 100.0f);
        matrix.translate(0, 0, -2);
        matrix.rotate(0, 0, 1, 0);
        QRectF destRect = matrix.mapRect(QRectF(0, 0, 100, 100));
        qreal rate = 100.0 / destRect.width(); /* 大于1缩小 */
        if (rate > 1.0)
        {
            b = c;
        }
        else
        {
            a = c;
        }
    }
    return a;
}