用负数翻转没有比例的Opengl绘图

Posted

技术标签:

【中文标题】用负数翻转没有比例的Opengl绘图【英文标题】:Flipping Opengl drawing without scale by negative numbers 【发布时间】:2018-03-05 12:06:16 【问题描述】:

我正在尝试绘制两个彼此相对的 2D 钻石。 所以我画了第一颗钻石,然后在使用后画了第二颗钻石:

glTranslated(0, -150, 0);

所以它可以正好出现在我的第一颗钻石下方。 但是,我遇到了一个问题,我无法翻转第二颗钻石,让它看起来像一面镜子。

这是我想要做的:

我在网上搜索了解决方案,他们都提到我应该 使用

glScalef(1.0f,-1.0f,1.0f); 

但每次我使用它时,绘图都会消失。

功能

glRotatef(angle,x,y,z); 

引起了我的注意,但我无法正确使用它,导致方向错误。

这是没有glRotate()时我的图像现在的样子:

所以我认为我需要适当的技术来使用这些功能。

注意:我使用了很多线循环和顶点来绘制。

  #include <windows.h>  // For MS Windows
  #include <GL/glut.h>   // (or others, depending on the system in use)
  void init(void)
  
     glClearColor(1.0, 1.0, 1.0, 0.0);  // Set display-window color to 
      white.
    glMatrixMode(GL_PROJECTION);       // Set projection parameters.
    gluOrtho2D(0.0, 400.0, 0.0, 400.0);
  
  void drawDiamond()
     
  glBegin(GL_LINE_LOOP);
  glVertex2f(125, 350);
  glVertex2f(245, 350);
  glVertex2f(290, 300);
  glVertex2f(182, 200);
  glVertex2f(75, 300);
  glEnd();


 glBegin(GL_LINE_LOOP);
 glVertex2f(109, 333);
 glVertex2f(138, 350);
 glVertex2f(159, 337);
 glVertex2f(123, 300);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(109, 333);
glVertex2f(123, 300);
glVertex2f(154, 225);
glVertex2f(92, 300);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(290, 300);
glVertex2f(75, 300);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(123, 300);
glVertex2f(159, 337);
glVertex2f(154, 300);
glVertex2f(171, 225);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(181, 300);
glVertex2f(159, 337);
glVertex2f(181, 350);
glVertex2f(209, 337);
glVertex2f(181, 300);
glVertex2f(171, 225);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(181, 300);
glVertex2f(209, 337);
glVertex2f(219, 300);
glVertex2f(195, 225);
glVertex2f(181, 300);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2f(209, 337);
glVertex2f(243, 300);
glVertex2f(195, 225);
glVertex2f(219, 300);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(209, 337);
glVertex2f(229, 350);
glVertex2f(260, 333);
glVertex2f(243, 300);
glVertex2f(209, 337);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(260, 333);
glVertex2f(278, 300);
glVertex2f(210, 225);
glVertex2f(243, 300);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(195, 225);
glVertex2f(182, 200);
glEnd();

glBegin(GL_LINE_LOOP);
glVertex2f(171, 225);
glVertex2f(182, 200);
glEnd();



void display()

glClear(GL_COLOR_BUFFER_BIT);  // Clear display window.
glColor3f(0.0, 0.0, 0.0);      // Set line segment color to blue.

                               // your code goes here
drawDiamond();
glTranslatef(0.0f, -150, 0.0f);
drawDiamond();
glFlush();     // Process all OpenGL routines as quickly as possible.


void main(int argc, char** argv)

glutInit(&argc, argv);                         // Initialize GLUT.
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);   // Set display mode.
glutInitWindowPosition(50, 100);   // Set top-left display-window 
position.
glutInitWindowSize(400, 400);      // Set display-window width and 
height. 
glutCreateWindow("Diamond Project"); // Create display window. 

init();                            // Execute initialization procedure. 
glutDisplayFunc(display);       // Send graphics to display window. 


glutMainLoop();                    // Display everything and wait.      

【问题讨论】:

从外观上看,您使用的是旧版 OpenGL 1.0;如果可以的话,我建议使用现代 OpenGL 3.3+ 版并使用着色器。从那里您可以使用模型视图投影矩阵来执行所有需要的转换。还使用 GLM 数学库使事情变得更容易。 在我对SO: OpenGl draw a cylinder with 2 points glRotated 的回答中,我提到了glRotatef()。顺便提一句。旋转约 180 度。和镜像不一样。如果旋转的项目是对称的,它看起来很相似。 您只需要围绕其中一个轴旋转对象并学习如何使用glRotatef 函数。 如果你镜像事物(例如使用glScalef(1, -1, 1)),这会影响三角形的方向。 (您的模型被翻过来了。)因此,可能有必要将背面剔除反转为正面剔除(反之亦然)。 编辑minimal reproducible example。 【参考方案1】:

您要做的是围绕一个轴镜像(翻转)对象,该轴平行于 X 轴,并穿过对象的底部边界(菱形)。

为此,必须找到底部 Y 坐标 (bottomY),并且必须将对象向 相反 方向平移。注意模型坐标(顶点)的底部和不是视口上最终坐标的底部:

float bottomY = 200.0f;
glTranslatef( 0.0f, -bottomY , 0.0f );

接下来必须翻转对象。这可以通过

glRotatef(180.0f, 1.0f, 0.0f, 0.0f);

或通过

glScalef(1.0f, -1.0f, 0.0f)

注意,这两个操作产生相同的变换矩阵,因为 cos(90°) = cos(-90°), sin(90°) = -sin(90°) .

那么bottomY 的翻译必须反转:

glTranslatef( 0.0f, bottomY, 0.0f );

但请注意,OpenGL 固定函数管道堆栈的操作顺序相反,因为当前矩阵乘以新操作指定的矩阵。

翻译:见glTranslate的文档:

glTranslate 通过x y z 生成翻译。当前矩阵(见glMatrixMode)乘以这个平移矩阵,乘积替换当前矩阵。

轮换:见glRotate的文档:

glRotate 产生围绕向量 x y z 的角度旋转。当前矩阵(参见glMatrixMode)乘以旋转矩阵,乘积替换当前矩阵。

缩放:见glScale的文档:

glScale沿xyz 轴产生非均匀缩放。这三个参数指示沿三个轴中的每一个轴的所需比例因子。 当前矩阵(见glMatrixMode)乘以这个比例矩阵。

这意味着以下应该做你想做的事:

float bottomY = 200.0f;

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();

drawDiamond();

glTranslatef( 0.0f, bottomY , 0.0f );
glRotatef( 180.0f, 1.0f, 0.0f, 0.0f );
glTranslatef( 0.0f, -bottomY , 0.0f );

drawDiamond();

和是一样的:

glTranslatef( 0.0f, bottomY , 0.0f );
glScalef( 1.0f, -1.0f, 1.0f );
glTranslatef( 0.0f, -bottomY , 0.0f );  

【讨论】:

第二个模型的 minY 为 50,但模型仍然消失,因为 scale f(x,y,z) 将顶点值乘以参数,这将导致我无法绘制负顶点(我只能画0及以上)。 我将编辑我的帖子并输入我的代码,这样我的问题就会更清楚, 成功了!!!我非常感谢您的帮助。现在问题更清楚了,因此将其移至 x 轴,然后将其旋转 180 度,然后我们移至正确的位置。谢谢。【参考方案2】:

根据您的顶点设置方式以及是否启用了背面剔除,您可能需要将菱形或(模型的)中心点更改为从那里开始的底部尖端,然后您可以简单地围绕提供的 X 轴旋转您将其声明为水平轴。这样做不应该那么难。它看起来像:

glRotatef( 180.0f, 1, 0, 0 );

如果您以度数而不是弧度为单位旋转。

【讨论】:

所以根据我的理解我应该翻译直到它合适(在底部提示)然后我可以简单地旋转 但是,我不知道新的中心点应该在哪里才能使用 glRotate()。 @MKH 与其说是翻译,不如说是翻译;您不想将网格作为一个整体进行平移,因为它会在世界空间(屏幕空间)中移动它的位置。您想将对象焦点设置到尖端然后旋转。或者您可以旋转 x 180 度,然后将其向下平移您需要的距离;但是当您开始进行仿射变换时,顺序很重要,具体取决于坐标系的惯用手。通过(平移、旋转和缩放)排序,顺序很重要!【参考方案3】:

对于每个顶点(我假设您使用立即模式来指定顶点),您可以glVertex2i(myVertex.x, symmetryLine - myVertex.y, 0) 其中 myVertex 是您之前使用的 x 和 y 值,symbolicLine 是您希望镜像的值。最好的方法是使用否定的glScale。你的钻石是旋转对称的glRotate 也可以,但你知道,这不是一种非常优雅的方式。

【讨论】:

'symmetryLine - my vertex.y' 将产生负数,不会使顶点出现在屏幕上。 不,这取决于您选择的价值。应该选择最下方的菱形顶点的y坐标作为symmetryLine值,才能得到这个镜像。

以上是关于用负数翻转没有比例的Opengl绘图的主要内容,如果未能解决你的问题,请参考以下文章

opengl翻转后为啥出现两个图像

在 openGL 绘图调用之后会发生啥?

用于包装 SDL 和 OpenGL 绘图方法的虚拟函数的替代方案

qt opengl的图形怎么刷新

OpenGL - 快速精灵绘图 - 需要一些指导

OpenGL:如何最小化绘图?