用负数翻转没有比例的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
沿x
、y
和z
轴产生非均匀缩放。这三个参数指示沿三个轴中的每一个轴的所需比例因子。 当前矩阵(见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绘图的主要内容,如果未能解决你的问题,请参考以下文章