OpenGL ES glRotatef performing shear instead of rotate? - opengl-es

I am able to draw a sprite on the screen of an iPhone, but when I try to rotate it I am getting some weird results. It seems to be stretching the sprite in the y direction more the closer the sprite gets to pointing down the y-axis (90 and 270 degrees). It displays correctly when pointing down the x and -x axes (0 and 180 degrees). It is basically like it is shearing instead of rotating. Here are the essentials of the code (projection matrix is ortho):
glPushMatrix();
glLoadIdentity();
glTranslatef( position.x, position.y, -1.0f );
glRotatef( rotation, 0.0f, 0.0f, 1.0f );
glScalef( halfSize.x, halfSize.y, 1.0f );
vertices[0] = 1.0f;
vertices[1] = 1.0f;
vertices[2] = 0.0f;
vertices[3] = 1.0f;
vertices[4] = -1.0f;
vertices[5] = 0.0f;
vertices[6] = -1.0f;
vertices[7] = 1.0f;
vertices[8] = 0.0f;
vertices[9] = -1.0f;
vertices[10] = -1.0f;
vertices[11] = 0.0f;
glVertexPointer( 3, GL_FLOAT, 0, vertices );
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
glPopMatrix();
Can anybody explain to me how to fix this please?
halfsize is just half the x and y extent of the sprite; removing the glScalef call does not make any difference.
Here is my matrix setup:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0, 320, 480, 0, 0.01, 5);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
OK, hopefully this screenshot will demonstrate what's happening:

If you are scaling by the same amount in the x and y directions, then your projection is causing the distortion.
Just a hunch, but maybe try swapping the 320 and 480 in your Ortho projection. (In case the X and Y on the iPhone is swapped)

Related

OpenGL Orthographic Projection and Translate

The code below draws a rectangle in 2D screen space using OpenGL ES2. How do move the drawing of the rectangle by 1 pixel to the right without modifying its vertices?
Specifically, what I am trying to do is move the coordinates 0.5 pixels to the right. I had to do this previously with GLES1.x and the reason for this is that I had problems drawing lines in the correct place unless I did a glTranslate() with 0.5f.
I'm confused about the use of glm::translate() in the code below.
If I attempt a translate of 0.5f, the whole rectangle moves from the left of the screen to the middle - a jump of about 200 pixels.
I get the same result whether I do a glm::translate on the Model or the View matrix.
Is the order of the matrix multiplication wrong and what should it be?
short g_RectFromTriIndices[] =
{
0, 1, 2,
0, 2, 3
}; // The order of vertex rendering.
GLfloat g_AspectRatio = 1.0f;
//--------------------------------------------------------------------------------------------
// LoadTwoTriangleVerticesForRect()
//--------------------------------------------------------------------------------------------
void LoadTwoTriangleVerticesForRect( GLfloat *pfRectVerts, float fLeft, float fTop, float fWidth, float fHeight )
{
pfRectVerts[ 0 ] = fLeft;
pfRectVerts[ 1 ] = fTop;
pfRectVerts[ 2 ] = 0.0;
pfRectVerts[ 3 ] = fLeft + fWidth;
pfRectVerts[ 4 ] = fTop;
pfRectVerts[ 5 ] = 0.0;
pfRectVerts[ 6 ] = fLeft + fWidth;
pfRectVerts[ 7 ] = fTop + fHeight;
pfRectVerts[ 8 ] = 0.0;
pfRectVerts[ 9 ] = fLeft;
pfRectVerts[ 10 ] = fTop + fHeight;
pfRectVerts[ 11 ] = 0.0;
}
//--------------------------------------------------------------------------------------------
// Draw()
//--------------------------------------------------------------------------------------------
void Draw( void )
{
GLfloat afRectVerts[ 12 ];
//LoadTwoTriangleVerticesForRect( afRectVerts, 0, 0, g_ScreenWidth, g_ScreenHeight );
LoadTwoTriangleVerticesForRect( afRectVerts, 50, 50, 100, 100 );
// Correct for aspect ratio so squares ARE squares and not rectangular stretchings..
g_AspectRatio = (GLfloat) g_ScreenWidth / (GLfloat) g_ScreenHeight;
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
GLuint hPosition = glGetAttribLocation( g_SolidProgram, "vPosition" );
// PROJECTION
glm::mat4 Projection = glm::mat4(1.0);
// Projection = glm::perspective( 45.0f, g_AspectRatio, 0.1f, 100.0f );
// VIEW
glm::mat4 View = glm::mat4(1.0);
static GLfloat transValY = 0.5f;
static GLfloat transValX = 0.5f;
//View = glm::translate( View, glm::vec3( transValX, transValY, 0.0f ) );
// MODEL
glm::mat4 Model = glm::mat4(1.0);
// static GLfloat rot = 0.0f;
// rot += 0.001f;
// Model = glm::rotate( Model, rot, glm::vec3( 0.0f, 0.0f, 1.0f ) ); // where x, y, z is axis of rotation (e.g. 0 1 0)
glm::mat4 Ortho = glm::ortho( 0.0f, (GLfloat) g_ScreenWidth, (GLfloat) g_ScreenHeight, 0.0f, 0.0f, 1000.0f );
glm::mat4 MVP;
MVP = Projection * View * Model * Ortho;
GLuint hMVP;
hMVP = glGetUniformLocation( g_SolidProgram, "MVP" );
glUniformMatrix4fv( hMVP, 1, GL_FALSE, glm::value_ptr( MVP ) );
glEnableVertexAttribArray( hPosition );
// Prepare the triangle coordinate data
glVertexAttribPointer( hPosition, 3, GL_FLOAT, FALSE, 0, afRectVerts );
// Draw the rectangle using triangles
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, g_RectFromTriIndices );
glDisableVertexAttribArray( hPosition );
}
Here is the vertex shader source:
attribute vec4 vPosition;
uniform mat4 MVP;
void main()
{
gl_Position = MVP * vPosition;
}
UPDATE: I'm finding the below matrix multiplication is giving me better results. I don't know if this is "correct" or not though:
MVP = Ortho * Model * View * Projection;
That MVP seems really weird to me, you shouldn't need 4 things in there to get your MVP.. your Projection matrix should just be the Orthogonal one, so in this case
MVP = Projection * View * Ortho;
But I can also see that your Projection matrix has been commented from perspective so I don't think it's doing much right now.
By the sounds of it since you want the model co-ordinates to stay the same while moving, you want to move your camera right? So (By the looks of it your vertices are using a 1 unit per pixel co-ordinate range) doing a translate of 0.5f to your View is shifting whatever half your projection space is. Instead, you want to have something like a Camera class that you get your Viewfrom using the camera's X and Y positions.
Then you can get your View matrix using the cameras position which can share the world units system you're using, which is 1 unit per pixel.
glm::mat4 view;
view = glm::lookAt(glm::vec3(camX, camY, 0.0), glm::vec3(0.0, 0.0, 0.0),glm::vec3(0.0, 1.0, 0.0));
I ripped that line straight (minus changing camZ for camY) from a really good 3d tutorial on camera here but the exact same concept can be applied to a orthogonal camera instead
I know it's a bit more overhead but having a cmaera class that you can control this way is nicer practice than manually using glm::translate,rotate&scale to control your viewport (and it lets you ensure that you'r working with a more obivous co-ordinate system between your camera and models co-ordinate points.

OpenGL Matrix scale then Translate is still scaling my position

I am trying to position my text model mesh on screen. Using the code below, it draws mesh as the code suggests; with the left of the mesh at the center of the screen. But, I would like to position it at the left of edge of the screen, and this is where I get stuck. If I un-comment the Matrix.translateM line, I would think the position will now be at the left of the screen, but it seems that the position is being scaled (!?)
A few scenarios I have tried:
a.) Matrix.scaleM only (no Matrix.translateM) = the left of the mesh is positioned 0.0f (center of screen), has correct scale.
b.) Matrix.TranslateM only (no Matrix.scaleM) = the left of the mesh is positioned -1.77f at the left of screen correctly, but scale incorrect.
c.) Matrix.TranslateM then Matrix.scaleM, or Matrix.scaleM then Matrix.TranslateM = the scale is correct, but position incorrect. It seems the position is scaled and is very much closer to the center than to the left of the screen.
I am using OpenGL ES 2.0 in Android Studio programming in Java.
Screen bounds (as setup from Matrix.orthoM)
left: -1.77, right: 1.77 (center is 0.0), top: -1.0, bottom: 1.0 (center is 0.0)
Mesh height is 1.0f, so if no Matrix.scaleM, the mesh takes the entire screen height.
float ratio = (float) 1920.0f / 1080.0f;
float scale = 64.0f / 1080.0f; // 64px height to projection matrix
Matrix.setIdentityM(modelMatrix, 0);
Matrix.scaleM(modelMatrix, 0, scale, scale, scale); // these two lines
//Matrix.translateM(modelMatrix, 0, -ratio, 0.0f, 0.0f); // these two lines
Matrix.setIdentityM(mMVPMatrix, 0);
Matrix.orthoM(mMVPMatrix, 0, -ratio, ratio, -1.0f, 1.0f, -1.0f, 1.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mMVPMatrix, 0, modelMatrix, 0);
Thanks, Ed Halferty and Matic Oblak, you are both correct. As Matic suggested, I have now put the Matrix.TranslateM first, then Matrix.scaleM second. I have also ensured that the MVPMatrix is indeed modelviewprojection, and not projectionviewmodel.
Also, now with Matrix.translateM for the model mesh to -1.0f, it is to the left edge of the screen, which is better than -1.77f in any case.
Correct position + scale, thanks!
float ratio = (float) 1920.0f / 1080.0f;
float scale = 64.0f / 1080.0f;
Matrix.setIdentityM(modelMatrix, 0);
Matrix.translateM(modelMatrix, 0, -1.0f, 0.0f, 0.0f);
Matrix.scaleM(modelMatrix, 0, scale, scale, scale);
Matrix.setIdentityM(mMVPMatrix, 0);
Matrix.orthoM(mMVPMatrix, 0, -ratio, ratio, -1.0f, 1.0f, -1.0f, 1.0f);
Matrix.multiplyMM(mMVPMatrix, 0, modelMatrix, 0, mMVPMatrix, 0);

OpenGL ES 2.0 renders coloured screen without the images

I'm trying to render sprites using OpenGL ES 2.0. However I only get a coloured screen without the sprites. Everything is setup correctly as far as I see. What could be wrong? Here is how I setup the projection and view matrices:
this.position = new Vector2(frustumWidth/2, frustumHeight/2);
for(int i=0;i<16;i++)
{
mtrxProjection[i] = 0.0f;
mtrxView[i] = 0.0f;
mtrxProjectionAndView[i] = 0.0f;
}
Matrix.orthoM(mtrxProjection, 0, position.x - frustumWidth * zoom / 2,
position.x + frustumWidth * zoom / 2,
position.y - frustumHeight * zoom / 2,
position.y + frustumHeight * zoom / 2,
10 , -10 );
Matrix.setLookAtM(mtrxView, 0, position.x, position.y, 0.0f, position.x, position.y, -1.0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mtrxProjectionAndView, 0, mtrxProjection, 0, mtrxView, 0);

How to position a textured quad in screen coordinates?

I am experimenting with different matrices, studying their effect on a textured quad. So far I have implemented Scaling, Rotation, and Translation matrices fairly easily - by using the following method against my position vectors:
enter code here
for(int a=0;a<noOfVertices;a++)
{
myVectorPositions[a] = SlimDX.Vector3.TransformCoordinate(myVectorPositions[a],myPerspectiveMatrix);
}
However, I what I want to do is be able to position my vectors using world-space coordinates, not object-space.
At the moment my position vectors are declared thusly:
enter code here
myVectorPositions[0] = new Vector3(-0.1f, 0.1f, 0.5f);
myVectorPositions[1] = new Vector3(0.1f, 0.1f, 0.5f);
myVectorPositions[2] = new Vector3(-0.1f, -0.1f, 0.5f);
myVectorPositions[3] = new Vector3(0.1f, -0.1f, 0.5f);
On the other hand (and as part of learning about matrices) I have read that I need to apply a matrix to get to screen coordinates. I've been looking through the SlimDX API docs and can't seem to pin down the one I should be using.
In any case, hopefully the above makes sense and what I am trying to achieve is clear. I'm aiming for a simple 1024 x 768 window as my application area, and want to position a my textured quad at 10,10. How do I go about this? Most confused right now.
I am not familiar with slimdx, but in native DirectX, if you want to draw a quad in screen coordinates, you should define the vertex format as Translated, that is you specify the screen coordinates directly instead of using D3D transform engine to transform your vertex. the vertex definition as below
#define SCREEN_SPACE_FVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
and you can define your vertex like this
ScreenVertex Vertices[] =
{
// Triangle 1
{ 150.0f, 150.0f, 0, 1.0f, 0xffff0000, }, // x, y, z, rhw, color
{ 350.0f, 150.0f, 0, 1.0f, 0xff00ff00, },
{ 350.0f, 350.0f, 0, 1.0f, 0xff00ffff, },
// Triangle 2
{ 150.0f, 150.0f, 0, 1.0f, 0xffff0000, },
{ 350.0f, 350.0f, 0, 1.0f, 0xff00ffff, },
{ 150.0f, 350.0f, 0, 1.0f, 0xff00ffff, },
};
By default screen space in 3d systems is from -1 to 1 (where -1,-1 is bottom left corner and 1,1 top right).
To convert those unit to pixel values, you need to convert pixel values into this space. So for example pixel 10,30 on a screen of 1024*768 is:
position.x = 10.0f * (1.0f / 1024.0f); // maps to 0/1
position.x *= 2.0f; //maps to 0/2
position.x -= 1.0f; // Maps to -1/1
Now for y you do
position.y = 30.0f * (1.0f / 768.0f); // maps to 0/1
position.y = 1.0f - position.y; //Inverts y
position.y *= 2.0f; //maps to 0/2
position.y -= 1.0f; // Maps to -1/1
Also if you want to apply transforms to your quads, It is better to send the transformation to the shader (and do the vector transformation in the vertex shader), rather than doing the multiplications on the vertices, since you will not need to update your vertexbuffer every time.

How to draw circle in opengles

Here is my part of code to show circle on screen but unfortunate circle is not coming on screen.
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glLoadIdentity();
glColor3f(0.0f,1.0f,0.0f);
glBegin(GL_LINE_LOOP);
const float DEG2RAD = 3.14159/180;
for (int i=0; i < 360; i++)
{
float degInRad = i*DEG2RAD;
glVertex2f(cos(degInRad)*8,sin(degInRad)*8);
}
glEnd();
glFlush();
I am not understanding code is seems to look ok but circle is not coming on screen.
Your circle is too big. The default viewport is in the range [(-1 -1), (1 1)].
BTW, you don't need 360 segments. About 30 is usually adequate, depending on how smooth you want it.

Resources