【问题标题】:OpenGL - Qt : translate instable with rotation and scalingOpenGL - Qt:旋转和缩放转换不稳定
【发布时间】:2015-01-18 00:27:01
【问题描述】:

我已经实现了一个程序,可以在 openGL 中平移、旋转和调整 2D 纹理。 这 3 个转换本身就很好,但是当我把翻译和其他人一起扔时,事情就变得古怪了。

对于缩放,当比例高于 1.0 时,一切似乎都很好,但一旦我低于,纹理就会离开屏幕。 轮换的同样悲伤的故事。当角度很小,但在20°以上或什么的时候,没有明显的问题,在两边,事情变得奇怪。

这是我的代码。有趣的功能在最后。

#include "glwidget.h"

#include <GL/glu.h>
#include <QMouseEvent>
#include <QKeyEvent>
#include <tgmath.h>
#include <QtDebug>
#ifdef WIN32
    #include <GL/glext.h>
       PFNGLACTIVETEXTUREPROC pGlActiveTexture = NULL;
    #define glActiveTexture pGlActiveTexture
#endif //WIN32

GlWidget::GlWidget(QWidget *parent) :
    QGLWidget(QGLFormat(), parent),
    scale(0.5),
    angle(0),
    translate{0,0,0},
    keyLock(false)
{
}

GlWidget::~GlWidget(){}

QSize GlWidget::sizeHint() const
{
    return QSize(640,480);
}

void GlWidget::resizeGL(int w, int h){

    h = (h<=0?1:h);

    pMatrix.setToIdentity();
    pMatrix.perspective(60.0,(float)w /(float)h,2,5);

    glViewport(0,0,w,h);
    glScissor(w*0.8,0,w,h);
    glDisable(GL_SCISSOR_TEST);
}

void GlWidget::initializeGL(){

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    #ifdef WIN32
        glActiveTexture = (PFNGLACTIVETEXTUREPROC) wglGetProcAddress((LPCSTR) "glActiveTexture");
    #endif

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    qglClearColor(QColor(Qt::black));


    shaderProgram.addShaderFromSourceFile(QGLShader::Vertex, ":/vertexShader.vsh");
    shaderProgram.addShaderFromSourceFile(QGLShader::Fragment, ":/fragmentShader.fsh");
    shaderProgram.link();

    vertices << QVector3D(-1,-1,-2) << QVector3D(1,-1,-2) << QVector3D(-1,1,-2)
             << QVector3D(-1,1,-2) << QVector3D(1,-1,-2) << QVector3D(1,1,-2);

    textureCoordinates << QVector2D(0, 0) << QVector2D(1, 0) << QVector2D(0, 1)
                       << QVector2D(0, 1) << QVector2D(1, 0) << QVector2D(1, 1);

    texture = bindTexture(QPixmap(":/icone.png"));
    //mMatrix.setToIdentity();
    mMatrix.scale(scale,scale);


}

void GlWidget::paintGL(){

    qglClearColor(QColor(Qt::white));
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    QMatrix4x4 vMatrix;
    shaderProgram.bind();
    shaderProgram.setUniformValue("mvpMatrix", pMatrix*vMatrix*mMatrix);
    shaderProgram.setUniformValue("texture", 0);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    glActiveTexture(0);

    shaderProgram.setAttributeArray("vertex", vertices.constData());
    shaderProgram.enableAttributeArray("vertex");
    shaderProgram.setAttributeArray("textureCoordinate", textureCoordinates.constData());
    shaderProgram.enableAttributeArray("textureCoordinate");

    glEnable(GL_BLEND);

    glDrawArrays(GL_TRIANGLES,0,vertices.size());

    glDisable(GL_BLEND);

    shaderProgram.disableAttributeArray("vertex");
    shaderProgram.disableAttributeArray("textureCoordinate");
    shaderProgram.release();

    qglClearColor(QColor(Qt::black));
    glEnable(GL_SCISSOR_TEST);
    glClear(GL_COLOR_BUFFER_BIT);
    glDisable(GL_SCISSOR_TEST);

}

void GlWidget::mousePressEvent(QMouseEvent *event){
    if(event->button()==Qt::LeftButton){
        lastPosF = QVector3D(event->pos().x(),event->pos().y(),0);
        lastPos = getModelCoordinates(event->pos());
        //keyLock=true;
    }
    event->accept();
    //update();
}

void GlWidget::mouseMoveEvent(QMouseEvent *event){
    if(!event->buttons().testFlag(Qt::LeftButton)) return;
    currentPosF = QVector3D(event->pos().x(),event->pos().y(),0);
    QVector3D currentPos(getModelCoordinates(event->pos()));

    //qDebug()<<currentPos;

    if(keysPressed.contains(Qt::Key_Control) && !keysPressed.contains(Qt::Key_Shift)){
        resizeTexture(currentPos);
    }
    else if(!keysPressed.contains(Qt::Key_Control) && keysPressed.contains(Qt::Key_Shift)){
        rotateTexture(currentPos);
    }
    else if(!keysPressed.contains(Qt::Key_Control) && !keysPressed.contains(Qt::Key_Shift)){
        dragTexture(currentPos);
    }

    mMatrix.setToIdentity();
    mMatrix.translate(translate);
    mMatrix.scale(scale,scale);
    mMatrix.rotate(angle,0,0,1);

    //lastPos = currentPos;
    update();

}

void GlWidget::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton)
        keyLock=false;

}

void GlWidget::keyPressEvent(QKeyEvent *event){
    if(!keyLock) keysPressed.append(event->key());

}

void GlWidget::keyReleaseEvent(QKeyEvent *event){
    if(!keyLock) keysPressed.remove(keysPressed.lastIndexOf(event->key()));
}

QVector3D GlWidget::getModelCoordinates(QPoint mousePos){
    QVector3D modelPos;

    double X,Y,Z;
    GLdouble modelMat[16],projMat[16];
    GLint viewport[4]={0,0,this->width(),this->height()};
    //glGetDoublev(GL_MODELVIEW_MATRIX ,modelMat);
    //glGetDoublev(GL_PROJECTION_MATRIX,projMat);
    //glGetIntegerv(GL_VIEWPORT,viewport);
    for(int i=0; i<4;i++){
        modelMat[i*4]=(double)mMatrix.column(i).x();
        modelMat[1+i*4]=(double)mMatrix.column(i).y();
        modelMat[2+i*4]=(double)mMatrix.column(i).z();
        modelMat[3+i*4]=(double)mMatrix.column(i).w();
    }
    for(int i=0; i<4;i++){
        projMat[i*4]=(double)pMatrix.column(i).x();
        projMat[1+i*4]=(double)pMatrix.column(i).y();
        projMat[2+i*4]=(double)pMatrix.column(i).z();
        projMat[3+i*4]=(double)pMatrix.column(i).w();
    }
    //GLdouble z;

    gluUnProject((double)mousePos.x(),(double)viewport[3]-(double)mousePos.y(),0,modelMat,projMat,viewport,&X,&Y,&Z);
    modelPos.setX(fabs(X)<1e-8?1e-8:static_cast<float>(X));
    modelPos.setY(static_cast<float>(Y));
    modelPos.setZ(static_cast<float>(Z));

    qDebug();
    qDebug()<<"first :"<<lastPos<<" - Now :"<<modelPos;


    return modelPos;
}

void GlWidget::resizeTexture(QVector3D currentPos)
{
    float diff = sqrt(pow(currentPos.x(),2)+pow(currentPos.y(),2)) / sqrt(pow(lastPos.x(),2)+pow(lastPos.y(),2));
    //diff=diff>1?1:diff;
    //diff /= sqrt(pow(lastPos.x(),2)+pow(lastPos.y(),2));
    scale*= diff;
    scale=scale<0?-scale:scale;
    qDebug()<<"diff : "<<diff<<"  - scale : "<<scale;
    /*mMatrix.setToIdentity();
    mMatrix.scale(scale,scale);
    mMatrix.rotate(angle,0,0,1);*/
}

void GlWidget::rotateTexture(QVector3D currentPos)
{
    float angle1 = atan((float)currentPos.y()/(float)currentPos.x());
    float angle2 = atan((float)lastPos.y()/(float)lastPos.x());
    float delta =angle1-angle2*(angle1*angle2>=0?1:-1);
    delta*=180/M_PI;
    angle+=delta;
    while(angle>360|| angle < 0){
        angle = (angle>360?angle-360:angle);
        angle = (angle<0?angle+360:angle);
    }
    qDebug()<<"angle 1 : "<<atan((float)lastPos.y()/(float)lastPos.x())
           << "angle 2 : "<<atan((float)currentPos.y()/(float)currentPos.x());
    qDebug()<<"delta : "<<delta<<" - Angle : "<<angle;
    //qDebug()<<angle;
    /*mMatrix.setToIdentity();
    mMatrix.scale(scale,scale);
    mMatrix.rotate(angle,0,0,1);*/
    //lastPos = currentPos;
}

void GlWidget::dragTexture(QVector3D currentPos)
{
    if(lastPos.x() > 1.0 || lastPos.x() < -1.0 || lastPos.y() > 1.0 || lastPos.y() < -1.0)
        return;
    translate += (currentPos-lastPos);
    /*mMatrix.setToIdentity();
    mMatrix.translate(translate);*/
    //translate += currentPosF-lastPosF;
    lastPosF=currentPosF;
    qDebug()<<translate;
}

这是我的顶点和片段着色器:

#version 330

uniform mat4 mvpMatrix;

in vec4 vertex;
in vec2 textureCoordinate;

out vec2 varyingTextureCoordinate;

void main(void)
{
    varyingTextureCoordinate = textureCoordinate;
    gl_Position = mvpMatrix * vertex;
}


#version 330

uniform sampler2D texture;

in vec2 varyingTextureCoordinate;

out vec4 fragColor;

void main(void)
{
    fragColor = texture2D(texture, varyingTextureCoordinate);
}

感谢您的回答。

【问题讨论】:

  • 我想你会发现顺序很重要。我通常旋转->翻译->缩放。
  • 当我在另一个变换之后翻译时,翻译并没有受到这个变换的阻碍,但是这个变换不是围绕模型的中心进行的,而是围绕着原来的0,0,0。
  • 我不确定我是否理解您的评论,但如果您旋转-> 平移,对象将围绕它自己的轴旋转然后平移。如果你 translate->rotate,对象将首先被平移,然后围绕原点旋转。
  • 我是在实验后这样说的:当我旋转->翻译(在代码中)时,翻译按预期工作,但旋转是围绕纹理的原始中心完成的,而不是之后的那个翻译。当我以另一种方式进行时,旋转按预期工作,但是当我将图像旋转超过某个角度时,平移变得疯狂。
  • 对不起,如果我不在基地;我来自不同语言的经验,但 OpenGL 是 OpenGL。它从您的陈述中看起来 mMatrix.rotate(angle,0,0,1);您定义的旋转是四元数(角度和要旋转的矢量,在本例中是围绕 z 轴)。四元数角度通常指定为弧度,而不是度数。这可能是度数与弧度的问题吗?

标签: rotation translation scaling qtopengl


【解决方案1】:

对于围绕 z 轴旋转 15 度,您的旋转矩阵应该是:

0.965926, -0.258819, 0.0, 0.0
0.258819, 0.965926, 0.0, 0.0
0.0, 0.0, 1.0, 0.0
0.0, 0.0, 0.0, 1.0

这些矩阵都是 4 X 4 矩阵。 翻译矩阵如下:

1.0、0.0、0.0、transX
0.0、1.0、0.0、transY
0.0, 0.0, 1.0, 反Z
0.0, 0.0, 0.0, 1.0

比例矩阵如下:

scaleX, 0.0, 0.0, 0.0
0.0, scaleY, 0.0, 0.0
0.0, 0.0, scaleZ, 0.0
0.0, 0.0, 0.0, 1.0

按顺序将这些矩阵相乘,以获得您想要的效果,但请记住顺序很重要。

【讨论】:

  • 我看它的方式,对于翻译,我必须计算翻译向量,用一个 2*2 矩阵旋转它,看起来像你给我的那个,将它添加到总翻译中矢量,这应该可以纠正旋转+平移的问题。我看看情况如何。
  • 天哪!有用!接下来是调整大小,仍然存在错误。
  • 好的,我只需要将平移向量乘以比例因子。旋转后轻松!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-15
  • 1970-01-01
  • 2011-07-28
  • 1970-01-01
  • 2012-03-20
相关资源
最近更新 更多