My issue is that I'm trying to do the glScissors call to cut off the screen draw area, but the center of coordinate system for this function in window space is bottom left corner of the screen.
Is there a way to change the origin of the center? I want the function to work in relation to the top left corner of the screen.
No, but you can make a function that transforms from one corrdinate system to another
void scissorTopLeft(int x, int y, int w, int h, int screenHeight)
{
glScissor(x, screenHeight-h-y, w, h);
}
Related
I'm trying to make a 2D game using DirectX 11 and I get distortion issues when I rotate the camera
By rotating the camera I mean rotating it about its Z axis with the X axis being left/right on the screen, the Y axis being up/down on the screen, and the Z axis protruding from the screen. so when I rotate the camera, the rest of the world should appear to be orbiting around the center of the screen
Here I have a perfectly square sprite
and when I rotate the camera it becomes stretched
note this doesn't happen when I rotate the sprite itself, only the camera
my current setup with my camera is
void Camera::SetOrthoMatrix(float width, float height, float nearZ, float farZ) //called when initializing the camera
{
orthoMatrix=XMMatrixOrthographicOffCenterLH(0.0f, width, 0.0f, height, nearZ, farZ);
}
void Camera::UpdateMatrix() //called whenever the camera's position or rotation changes
{
worldMatrix = XMMatrixTranslation(-pos.x, -pos.y, 0.0f) * XMMatrixRotationZ(rot);
}
XMMatrix Camera::GetViewMatrix()
{
return orthoMatrix * worldMatrix
}
My sprite class just takes it's own world matrix and multiplies it by camera.GetViewMatrix() and then I draw the sprite. I'm fairly certain that the distortion is caused by the orthographic matrix, but I can't figure out a way to fix it.
I figured it out by changing XMMatrixOrthographicOffCenterLH to XMMatrixOrthograpghicLH. then reordering the matrix multiplication from sprite, orthographic, camera to sprite, camera, orthographic.
this changes the coordinate system a little, before I had 0,0 be the bottom left corner of the screen but with XMMatrixOrthograpghicLH the origin is at the center of the screen. It's not quite what I wanted but it's a minor inconvenience.
I'm trying to make a library that would allow me to draw my overlay on top of the content of a game window that uses OpenGL by intercepting the call to the SwapBuffers function. For interception i use Microsoft Detours.
BOOL WINAPI __SwapBuffers(HDC hDC)
{
HGLRC oldContext = wglGetCurrentContext();
if (!context) // Global variable
{
context = wglCreateContext(hDC);
}
wglMakeCurrent(hDC, context);
// Drawing
glRectf(0.1F, 0.5F, 0.2F, 0.6F);
wglMakeCurrent(hDC, oldContext);
return _SwapBuffers(hDC); // Call the original SwapBuffers
}
This code works, but occasionally, when I move my mouse, my overlay blinks. Why? Some forums have said that such an implementation can significantly reduce FPS. Is there any better alternative? How do I correctly translate a normal position to an OpenGL position? For example, width = 1366. It turns out 1366 = 1, and 0 = -1. How to get the value for example for 738? What about height?
To translate a screen coordinate to normal coordinate you need to know the screen width and screen height, linear mapping from [0, screenwidth] to [-1, 1] / [0, screenheight] to [-1, 1]. It is as simple as follows:
int screenwidth, screenheight;
//...
screenwidth = 1366;
screenheight = 738;
//...
float screenx, screeny;
float x = (screenx/(float)screenwidth)*2-1;
float y = (screeny/(float)screenheight)*2-1;
Problem z=0:
glRect renders to z=0, it is a problem because the plane would be infinitely near. Because opengl considers rendering to world space still. Screen space lies at (x, y, 1) in non transformed world space. OpenGL almost always works with 3D coordinates.
There are two ways to tackle this problem:
You should prefer using functions with a z component, because opengl does not render correctly at z=0. z=1 corresponds to the normalized screen space
or you add a glTranslatef(0,0,1); to get to the normalized screen space
Remember to disable depth testing when rendering 2D on the screen space and resetting the modelview matrix.
I currently have two viewports in my game. One is for the information in the top (health, gold, magic, etc) and the other viewport shows the map area. I created my own custom mouse cursor using an image and I'm displaying that image just like any other and update the position based on my mouse cursor position. My only problem is that I can only draw that image on a viewport. I have it set the show up on the map area, and when I move my mouse to the top; it won't display on the information area. It just leaves the window. So the first thing I did (I knew it wouldn't work, but tested it anyways) was to draw the mouse on both viewports. But that shows two mouse cursors when moving to the top of the screen (LOL). My question is how can I get the mouse image to draw on the screen using screen (or window) coordinates, outside of the viewport. Does that make sense? I want to be able to move the mouse anywhere on the screen so I can click on items in the map viewport as well as the information viewport.
My viewport class is very simple:
Viewport.h
#pragma once
#include <SDL.h>
class Viewport
{
public:
Viewport(int x, int y, int width, int height);
~Viewport();
SDL_Rect GetViewport();
private:
SDL_Rect viewport;
};
Viewport.cpp
#include "Viewport.h"
Viewport::Viewport(int x, int y, int width, int height)
{
viewport.x = x;
viewport.y = y;
viewport.w = width;
viewport.h = height;
}
Viewport::~Viewport()
{
}
SDL_Rect Viewport::GetViewport()
{
return viewport;
}
In my Game class I initialize two variables for each Viewport
Viewport hud;
Viewport arena;
In the constructor I initialize them to the appropriate sizes. Then In my game drawing function I set the viewports accordingly and draw in the appropriate viewport.
// gfx is my Graphics class. Everything that has to do with drawing is inside that class; including setting the viewport for the render.
gfx.SetViewport(hud.GetViewport());
// This is where I would draw stuff on the hud viewport
gfx.SetViewport(arena.GetViewport());
// Where I draw the map, enemies, etc.
my SetViewport function is setup like this:
void Graphics::SetViewport(SDL_Rect viewport)
{
SDL_RenderSetViewport(renderer, &viewport);
}
How can I get my mouse image to be drawn (with the viewport not relavant). Below are some images of what I'm talking about.
Only displaying on the arena and won't show on the hud.
Displays the mouse on both if I draw the mouse on both viewports
Edit: I made a workaround which will work for this game
I'm just worried that it won't be good for performance on a bigger and larger game
I created another viewport that is as large as the screen (window) and I'm drawing the mouse to that viewport.
Super late answer but here it is. Calling SDL_RenderSetViewport(renderer, NULL) will reset the viewport to the entire window.
You should do this before you call SDL_PollEvent as well because if you poll mouse events when a viewport is active the mouse motion event coordinates will be relative to the viewport and not the main window.
I am trying to map screen pixels to openGL coordinates. Basically I have a 3D sphere drawn at position Vector3f(0,0,0) and radius=1 using glut.
glutSolidSphere(radius/*1*/,50,50);
This sphere, rather than appearing at the center of the screen appears in the top left quadrant of the screen. My goal is to convert a mouse click's location to openGL coordinates to find out what object on screen was clicked. I followed the link here to calculate the openGL coordinates using the formula
converted_x = 2.0f/screen_width*mouse_x - 1.0f
converted_y = 2.0f/screen_width*mouse_y - 1.0f
When I try to click on the center of the sphere, I get the click position (converted_x,converted_y) as (-0.62185,-0.607500) i.e., pixel location (mouse_x, mouse_y) is (242, 157). My screen resolution is 1280*800. I am not able to figure how I can use this information to figure out that the sphere was clicked. Any help is much appreciated.
Currently this is the code I have in reshape(), taken from an existing project.
void reshape(int w, int h)
{
// Adjust the viewport if the user resizes the window
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (h==0)
gluPerspective(80,(float)w,1.0,5000.0);
else
gluPerspective (80,( float )w /( float )h,1.0,5000.0 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
When I do this:
SpriteBatch spriteBatch = new SpriteBatch();
spriteBatch.setProjectionMatrix(new Matrix4().setToOrtho(0, 320, 0, 240, -1, 1));
spriteBatch.begin();
spriteBatch.draw(textureRegion, 0, 0);
spriteBatch.end();
SpriteBatch will draw the textureRegion onto the coordinate system 320-240 that I have specified to the whole screen. Say I want to draw with the same coordinate system 320 240 but only on the left half of the screen (which means everything will be scaled down horizontally in the left side, leaving the right half of the screen black), how can I do?
You're going to want to use the ScissorStack. Effectively, you define a rectangle that you want to draw in. All drawing will be in the rectangle that you defined.
Rectangle scissors = new Rectangle();
Rectangle clipBounds = new Rectangle(x,y,w,h);
ScissorStack.calculateScissors(camera, spriteBatch.getTransformMatrix(), clipBounds, scissors);
ScissorStack.pushScissors(scissors);
spriteBatch.draw(...);
spriteBatch.flush();
ScissorStack.popScissors();
This will limit rendering to within the bounds of the rectangle "clipBounds".
It is also possible push multiple rectangles. Only the pixels of the sprites that are within all of the rectangles will be rendered.
From http://code.google.com/p/libgdx/wiki/GraphicsScissors
Before rendering the batch, you can set the viewport to draw on a specific screen area. The important line is:
Gdx.gl.glViewport(x, y, w, h);
The viewport usually starts at x = 0 and y = 0 and extends to the full width and height of the screen. If we want to see only a part of that original viewport, we need to change both the size and the starting position. To draw only on the left half of the screen, use:
x = 0;
y = 0;
w = Gdx.graphics.getWidth()/2;
h = Gdx.graphics.getWidth();
I found the solution here and originally answered this question to a slightly more complicated problem, but the technique is the same.
To focus on any different portion of the viewport, simply choose x, y, w, and h accordingly. If you're going to do any more rendering in the normal fashion, make sure to reset the viewport with the original x, y, w, and h values.
Perhaps I am misunderstanding the question, but could you not just double the viewport width, setting it to 640 instead of 320?
SpriteBatch spriteBatch = new SpriteBatch;
spriteBatch.setProjectionMatrix(new Matrix4().setToOrtho(0, 640, 0, 240, -1, 1));
spriteBatch.begin();
spriteBatch.draw(textureRegion, 0, 0);
spriteBatch.end();
You could either
double the viewport width of the SpriteBatch
use a Sprite and set its width scale to 0.5f (be careful about the origin) and use its draw(SpriteBatch) method to draw it.