I am fairly new to OpenGL and I am trying to handle a window resizing event using glm::ortho. I am displaying a simple triangle on screen and I am trying to make it so it keeps the same width/height ratio upon window resizing. However, when I resize the window, the triangle just disappears.
Here is my window resizing handling function:
int width = 800, height = 800;
void windowResized(GLFWwindow* window, int width2, int height2) {
width = width2;
height = height2;
glViewport(0, 0, width, height);
proj_matrix = glm::ortho(0.0f, (float)width, (float)height, 0.0f);
}
Cheers!
Related
I add a toolbutton on the top of my qglwidget. The icon image of the toolbutton is round except the transparent edge.But after coding and showing the widget, the side of the buttong is black.
my result
What work should I do to make the edge transparent? My platform is Qt 5.3.2 MSVC2010. I want to get this example as my final target
MyQGLWidget.cpp:
void WorldView::initializeGL()
{
loadGLTexture();
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH); // 启用阴影平滑
glClearColor(0.0f, 0.0f, 1.0f, 0.0f); // 蓝色背景
glClearDepth(1.0f); // 设置深度缓存
glEnable(GL_DEPTH_TEST); // 启用深度测试
glDepthFunc(GL_LEQUAL); // 所作深度测试的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 告诉系统对透视进行修正
}
void WorldView::resizeGL(int width, int height)
{
if (height == 0) { // 防止被零除
height = 1; // 将高设为1
}
glViewport(0, 0, width, height); //重置当前的视口
glMatrixMode(GL_PROJECTION);// 选择投影矩阵
glLoadIdentity();// 重置投影矩阵
//设置视口的大小
gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f); //透视投影
glMatrixMode(GL_MODELVIEW); //选择模型观察矩阵
glLoadIdentity(); // 重置模型观察矩阵
}
void WorldView::paintGL()
{
// is empty
}
MyMainWindow:
void MyMainWindow::createUiElements()
{
int nXStart, nYStart;
int nWidth, nHeight;
// set main window size
nXStart = (QApplication::desktop()->width() - WIN1_WIDTH)/2;
nYStart = (QApplication::desktop()->height() - WIN1_HEIGHT)/2;
setGeometry(nXStart,nYStart,1024,768);
// add opengl widget to ui
mpWorldView = new WorldView(this);
mpWorldView->setGeometry(0,0,WIN1_WIDTH,WIN1_HEIGHT);
// add more options button to ui
mpBtnMoreOptions = new QToolButton(this);
nWidth = 56;
nHeight = 56;
nXStart = this->width() - nWidth - 20;
nYStart = this->height() - nHeight - 20;
mpBtnMoreOptions->setGeometry(nXStart, nYStart, nWidth, nHeight);
mpBtnMoreOptions->setIconSize(QSize(56,56));
mpBtnMoreOptions->setIcon(QIcon("./icons/ic_more.png"));
mpBtnMoreOptions->setAutoRaise(true);
}
You might be able to be explicit about the elliptical geometry you want using QWidget::setMask (which QToolButton inherits), I haven't tested it alongside setIcon but it works without so it might be worth a shot. You could do it with something like
QRect rect(nXStart, nYStart, nWidth, nHeight);
QRegion region(rect, QRegion::Ellipse);
mpBtnMoreOptions -> setMask(region);
I have not tested this though so no guarantees.
Edit
Here is a more complete example, with some corrections to get the region geometry right
QMainWindow* main = new QMainWindow;
QWidget *central = new QWidget;
QToolButton* tool = new QToolButton(central);
int nWidth = 100;
int nHeight = 100;
int nXStart = 10;
int nYStart = 10;
QRect rect(nXStart, nYStart, nWidth/2, nHeight/2);
tool->setGeometry(rect);
rect.setRect(0, 0, nWidth/2, nHeight/2); // Region needs to start at (0,0)
QRegion region(rect, QRegion::Ellipse);
tool->setMask(region);
tool->setIconSize(QSize(100, 100));
tool->setIcon(QIcon(":/Test/icon"));
tool->setAutoRaise(true);
main->setCentralWidget(central);
main->resize(600, 400);
main->show();
Output
I'm just setting up a simple renderer using LWJGL 3 and when it runs on my external display it looks like I expect but when resize it on my Macbook it shrinks the viewport. Then if I move the window it fixes it. Here's the code that I run when I init my GL stuff and on window resize.
public void resize(int width, int height)
{
val near = 0.1
val far = 100.0
GL11.glViewport(0, 0, width, height);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
float aspect = width / (float)height
float fov = (float)(45.0 / 360.0 * Math.PI)
float fH = Math.tan(fov) * near
float fW = fH * aspect
GL11.glFrustum(-fW, fW, -fH, fH, near, far);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glLoadIdentity();
}
Here's what I'm seeing
Wrong
Right
If I'm running it on my external display it doesn't change, it's always right.
Reading the size of the frame buffer was the answer here. I create the window with the pixel size the user passes in and then read the frameBuffer size to pass to glViewport.
public Window(String title, int width, int height)
{
_errorCallback = GLFWErrorCallback.createPrint(System.err);
GLFW.glfwSetErrorCallback(_errorCallback);
if (GLFW.glfwInit() != GLFW.GLFW_TRUE)
{
throw IllegalStateException("Unable to initialize GLFW");
}
GLFW.glfwDefaultWindowHints();
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, GLFW.GLFW_TRUE);
_window = GLFW.glfwCreateWindow(width, height, title ?: "", 0, 0);
if (_window == 0L)
{
throw RuntimeException("Failed to create window");
}
// Setup Callbacks
// Get the resolution of the primary monitor
GLFWVidMode vidmode = GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor());
// Center our window
GLFW.glfwSetWindowPos(_window, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);
// Make the OpenGL context current
GLFW.glfwMakeContextCurrent(_window);
// Enable v-sync
GLFW.glfwSwapInterval(1);
// Make the window visible
GLFW.glfwShowWindow(_window);
}
Then I read the frame buffer size to pass into glViewport and glFrustum.
public Vector2 frameBufferSize()
{
IntBuffer bufferWidth = BufferUtils.createIntBuffer(4);
IntBuffer bufferHeight = BufferUtils.createIntBuffer(4);
GLFW.glfwGetFramebufferSize(_window, bufferWidth, bufferHeight);
return Vector2(bufferWidth.get(0), bufferHeight.get(0));
}
I am trying to setup my OpenGL views for some texture rendering. Following some advice on the forum, I set up my viewport and ortho matrix as follows:
First I try to compute the screen width and height that I can use while maintaining the aspect ratio of my image:
void resize(int w, int h)
{
float target_aspect_ratio = image_width / image_height;
width = w;
height = (int)(width / target_aspect_ratio + 0.5f);
if (height > h) {
height = h;
width = (int)(height * target_aspect_ratio + 0.5f);
}
off_x = (w - width)/2.f;
off_y = (h - height)/2;
// I want to center my image. So I have these offsets
glViewport(off_x, off_y, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height, 0.0f, 1.0f);
Now when I want to render my texture I do:
void paint()
{
// texture binding etc.
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(1, 0); glVertex2f(width, 0);
glTexCoord2f(1, 1); glVertex2f(width, height);
glTexCoord2f(0, 1); glVertex2f(0, height);
}
However, this does not show the image as expected. It does not maintain the aspect ratio as I size the screen. It is almost like the glViewport has no effect and I can verify this function gets called every time my window is resized.
Update:
It is strange. Almost as if these calls have no effect. I even did something as:
_off_x = _off_y = 0;
_width = 500;
_height = 500;
So I expected the viewport to be lower left box of my screen but the image is being drawn as before basically using the whole screen as the viewport.
Update 2:
Ok, so if I call
glViewport(_off_x, _off_y, _width, _height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, _width, 0, _height, 0, 1);
in my paint events, it works as expected! However, I thought it was enough to put this in the resize event handler.
Before start drawing, you need to switch your Matrix mode to GL_MODELVIEW. You don't need to set your projection matrix inside your render function at each frame.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Here is a detailed analysis that I wrote about glMatrixMode() function modes :
OpenGL glMatrixMode(GL_PROJECTION) vs glMatrixMode(GL_MODELVIEW)
I have a shape that is centered on the window screen. For now on window resize it remains the same (same width and height).
What is the best way to fit it to the window on resize, and also keep it's aspect ratio?
const int WIDTH = 490;
const int HEIGHT = 600;
/**
* render scene
*/
void renderScene(void)
{
//clear all data on scene
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//set white bg color
glClearColor(1, 1, 1, 1);
glColor3ub(153, 153, 255);
glBegin(GL_POLYGON);
glVertex2f(60, 310);
glVertex2f(245, 50);
glVertex2f(430, 310);
glVertex2f(245, 530);
glEnd();
glutSwapBuffers();
}
/**
* reshape scene
*/
void reshapeScene(GLint width, GLint height)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, width, height);
gluOrtho2D(0, width, height, 0);
glMatrixMode(GL_MODELVIEW);
glutPostRedisplay();
}
/**
* entry point
*/
int main(int argc, char **argv)
{
//set window properties
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(WIDTH, HEIGHT);
glutInitWindowPosition((glutGet(GLUT_SCREEN_WIDTH)-WIDTH)/2, (glutGet(GLUT_SCREEN_HEIGHT)-HEIGHT)/2);
glutCreateWindow("Test Window");
//paste opengl version in console
printf((const char*)glGetString(GL_VERSION));
//register callbacks
glutDisplayFunc(renderScene);
glutReshapeFunc(reshapeScene);
//start animation
glutMainLoop();
return 0;
}
Thanks
At the top:
const int WIDTH = 490;
const int HEIGHT = 600;
const float ASPECT = float(WIDTH)/HEIGHT; // desired aspect ratio
Then reshapeScene:
void reshapeScene(GLint width, GLint height)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
int w = height * ASPECT; // w is width adjusted for aspect ratio
int left = (width - w) / 2;
glViewport(left, 0, w, height); // fix up the viewport to maintain aspect ratio
gluOrtho2D(0, WIDTH, HEIGHT, 0); // only the window is changing, not the camera
glMatrixMode(GL_MODELVIEW);
glutPostRedisplay();
}
Because you are not constraining the window resize to a particular aspect ratio, you need to pick one of the two dimensions (height, here) to drive the viewport reshape and calculate an adjusted width based on that height and the desired aspect ratio. See adjusted glViewport call above.
Also, gluOrtho2D is your camera, essentially. Since you aren't moving the camera or the object so much, you don't need to change that (so it just uses the initial WIDTH and HEIGHT).
When my window is resized, i don't want the contents to scale but just to increase the view port size. I found this while searching on stackoverflow (http://stackoverflow.com/questions/5894866/resize-viewport-crop-scene) which is pretty much the same as my problem. However I'm confused as to what to set the Zoom to and where, i tried it with 1.0f but then nothing was shown at all :s
This is resize function code at the moment which does scaling:
void GLRenderer::resize() {
RECT rect;
int width, height;
GLfloat aspect;
GetClientRect(hWnd, &rect);
width = rect.right;
height = rect.bottom;
if (height == 0) {
height = 1;
}
aspect = (GLfloat) width / height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, aspect, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
}
And my function to render a simple triangle:
void GLRenderer::render() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslated(0, 0, -20);
glBegin(GL_TRIANGLES);
glColor3d(1, 0, 0);
glVertex3d(0, 1, 0);
glVertex3d(1, -1, 0);
glVertex3d(-1, -1, 0);
glEnd();
SwapBuffers(hDC);
}
You can change the zoom in y (height) with the "field of view" parameter to gluPerspective. The one that is 45 degrees in your code. As it is currently always 45 degrees, you will always get the same view angle (in y). How to change this value as a function of the height of the window is not obvious. A linear relation would fail for big values (180 degrees and up). I would try to use arctan(height/k), where 'k' is something like 500.
Notice also that when you extend the window in x, you will already get what you want (the way your source code currently is). That is, you get a wider field of view. That is because you change the aspect (second argument) to a value depending on the ratio between x and y.
Height and Width is measured in pixels, so a value of 1 is not good.
Notice that you are using deprecated legacy OpenGL. See Legacy OpenGL for more information.