(Using OpenGL, GLUT, GLU, and C)
I am trying to create a 3D game in C, and I have the camera movement, collision detection and all of the main stuff ready, however I have failed at the first hurdle. To create my rectangles I am using
glutSolidCube (2.0);
And I know about tranformations and scale and rotations, however I am looking for how to place it in a precise location. Say I had a 3D space, with XYZ. Say I had the camera at 5,5,20, looking towards 0,0,0 (So at an angle) and wanted to place a Cube at 5,2,10, and then another at -5,-2,20. How would I use these absolute positions? Also, how would I use absolute sizes, so say I wanted the one at -5,-2,20 to be 20,5,10 in size. How would I do this in OpenGL?
You'll have to use the functions:
glTranslatef()
glRotatef()
glScalef()
Additionally, also learn these:
glPushMatrix()
glPopMatrix()
Read the OpenGL reference for details.
First forget about glutSolidCube. GLUT is not a part of OpenGL, it's just a small convenience library for it.
You must understand the OpenGL only deals with points, lines and tranangles. And it doesn't maintain a scene, but its merely drawing points, lines and triangles. Each on its own without any connotation of topology. Also OpenGL should not be confused for some math library. The functions glTranslate, glRotate, glScale and so on are a pure legacy and have been removed from contemporary OpenGL versions.
That being said...
Say I had the camera at 5,5,20, looking towards 0,0,0 (So at an angle) and wanted to place a Cube at 5,2,10, and then another at -5,-2,20. How would I use these absolute positions? Also, how would I use absolute sizes, so say I wanted the one at -5,-2,20 to be 20,5,10 in size. How would I do this in OpenGL?
I'll go along with what you already know (which mans old OpenGL-1.1 and GLUT):
void draw()
{
/* Viewport and projection really should be set in the
drawing handler. They don't belong into the reshape. */
glViewport(...);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
your_projection();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(5, 5, 20, 0, 0, 0, 0, 1, 0);
glPushMatrix();
glTranslatef(5, 2, 10);
draw_cube();
glPopMatrix();
glPushMatrix();
glTranslatef(-5, -2, 20);
draw_cube();
glPopMatrix();
glPushMatrix();
glTranslatef(-5, -2, 20);
glScalef(20, 5, 10);
draw_cube();
glPopMatrix();
}
Related
I am trying to optimize drawing a cube with 3 different textures. An effect I want to achieve is:
What I am doing now is drawing cube using three Draw() calls:
graphicsDevice.Textures[0] = cube.frontTexture;
graphicsDevice
.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0,
36, 0, 2);
graphicsDevice.Textures[0] = cube.backTexture;
graphicsDevice
.DrawIndexedPrimitives(PrimitiveType.TriangleList, 6, 0,
30, 0, 2);
graphicsDevice.Textures[0] = cube.sideTexture;
graphicsDevice
.DrawIndexedPrimitives(PrimitiveType.TriangleList, 12, 0,
24, 0, 8);
Then my texture is processed in pixel shader I sample my texture:
texture Texture;
sampler textureSampler : register(s0) = sampler_state {
Texture = (Texture);
Filter = MIN_MAG_MIP_POINT;
AddressU = Wrap;
AddressV = Wrap;
};
and produce output:
return tex2D(textureSampler, texCoord); // I have my texCoords from vertex shader output
Unfortunately in my scene there are hundreds of similar cubes with different textures, as well as other objects and it has bad influence on FPS rate. What I noticed is that I can sample in my pixel shader more than one texture:
graphicsDevice.Textures[0] = cube.frontTexture;
graphicsDevice.Textures[1] = cube.backTexture;
graphicsDevice.Textures[2] = cube.sideTexture;
Can I somehow stick each texture to proper face of cuboid in my pixel shader, in order to draw it in one Draw() call? I use Silverlight 5.0, but any answers also concerning XNA, or MonoGames will be appreciated :)
You could take all 3 bitmaps that make up the 3 textures and add them to one big bitmap. The result would be one big texture or texture atlas. Then you just set the UV for each face to the appropriate parts of the large texture.
In this way, there is only ever one bound texture and no need to perform expensive texture context switches.
It's a common practice. It's popular too for sprite sheets.
As #Micky says, it's good practice to use sprite sheets instead of thousands separate textures. In my case I'm want to have separate textures in file system, but few textures in the game, so I write special class to compose small textures in big sprite sheets and recalculate texture coords.
There is lot of code, so I'll better provide a link to sources.
Textures packing when game starting. If you don't mind about few seconds of processing, you can use it for your sprites.
I am doing in a simplistic experiment as below:
glPushMatrix();
glGetDoublev(GL_MODELVIEW, modelMatrix);
glTranslatef(...);
glGetDoublev(GL_MODELVIEW, modelMatrix);
glPopMatrix();
However, after the translation, there is not change in the modelview matrix. I am wondering why is that, and how can I see the effect of this translation? In other words, how can I get the transformation marix?
Your code is invalid. The correct enum for glGet...() is GL_MODELVIEW_MATRIX, not GL_MODELVIEW (which is a constant for use glMatrixMode()), so all you get is some GL error, and the memory at modelMatrix will be not touched at all, so it is probably just left uninitialized.
I'm currently trying to get to know the basics with the means of OpenGL.
At the time I try to render a Floating Cube with a Pyramid beneath it. I want the Cube to rotate on Input (which is already working) and the Pyramid to stay where it's supposed to be.
After figuring out the use of Push- and PopMatrix I managed to rotate only the cube.
My Problem is, that the Cube stops rotating as soon as I let go of the key.
The player.X and Player.Z aren't reset at that point (checked that).
So my guess is that PushMatrix puts some kind of standard matrix onto the stack, then rotates it and displays it. Because of 1 * x always equalling x there is no rotation.
So the question is:
How do I manage to push the "old" matrix onto the stack, rather than the new one?
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
glRotatef( -(player->Z), 1.0f, 0.0f, 0.0f );
glRotatef( -(player->X), 0.0f, 1.0f, 0.0f );
glBegin( GL_QUADS );
//Draw Cube
glEnd();
glPopMatrix( );
glBegin( GL_TRIANGLES );
//Draw Pyramid
glEnd();
glFlush();
SwapBuffers (hDC);
glPushMatrix() does not push a 'standard' matrix onto the stack, it pushes the current matrix. Hopefully you've initialised the matrix at some point with a glLoadIdentity(), and possibly some initial transforms to set up the view, and so this is what will be pushed.
You should not generally keep updating that matrix from frame to frame, as errors will eventually accumulate.
Instead, update your rotation values in some update loop, rather than in the key-down routine.
Also, note that this method of rendering with GL is considered deprecated. The recommended approach is to use the programmable pipeline, which involves creating your own matrices (amongst other changes).
(if you desperately want to keep a persistent transform while also pushing and popping to render other things, it is possible to read the current matrix with a glGet(), store it somewhere, and then perform a glLoadMatrix() to restore it again later... but don't do that for this.)
Preface
First of all, why is a vertex shader required for a SilverlightEffect (.slfx file) in Silverlight 5? I'm trying to port a simple 2D XNA game to Silverlight 5 RC, and I would like to use a basic pixel shader. This shader works great in XNA for Windows and Xbox, but I can't get it to compile with Silverlight as a SilverlightEffect.
The MS blog for the Silverlight Toolkit says that "there is no difference between .slfx and .fx", but apparently this isn't quite true -- or at least SpriteBatch is working some magic for us in "regular XNA", and it isn't in "Silverlight XNA".
If I try to directly copy my pixel shader file into a Silverlight project (and change it to the supported "Effect - Silverlight" importer/processor), when I try to compile I see the following error message:
Invalid effect file. Unable to find vertex shader in pass "P0"
Indeed, there isn't a vertex shader in my pixel shader file. I haven't needed one with my other 2D XNA apps since I'm just doing basic SpriteBatch drawing.
I tried adding a vertex shader to my shader file, using Remi Gillig's comment on this Shawn Hargreaves blog post for guidance, but it doesn't quite work. The shader file successfully compiles, and I see some semblance of my game on screen, but it's tiny, twisted, repeated, and all jumbled up. So clearly something's not quite right.
The Real Question
So that brings me to my real question: Since a vertex shader is required, is there a basic vertex shader function that works for simple 2D SpriteBatch drawing?
And if the vertex shader requires world/view/project matricies as parameters, what values am I supposed to use for a 2D game?
Can any shader pros help? Thanks!
In XNA, SpriteBatch is providing its own vertex shader. Because there is no SpriteBatch in Silverlight 5, you have to provide your own.
You may want to look at the source code for the shader that SpriteBatch uses (it's in SpriteEffect.fx). Here is its vertex shader, it's pretty simple:
void SpriteVertexShader(inout float4 color : COLOR0,
inout float2 texCoord : TEXCOORD0,
inout float4 position : SV_Position)
{
position = mul(position, MatrixTransform);
}
So now you just need the input position and the transformation matrix (and the texture co-ordinates, but those are fairly simple).
The same blog post you linked, towards the end, tells you how to set up the matrix (also here). Here it is again:
Matrix projection = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 1);
Matrix halfPixelOffset = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
Matrix transformation = halfPixelOffset * projection;
(Note: I'm not sure if Silverlight actually requires the half-pixel offset to maintain texel alignment (ref). It probably does.)
The tricky bit is that the positioning of the sprite is done outside of the shader, on the CPU. Here's the order of what SpriteBatch does:
Start with four vertices in a rectangle, with (0,0) being the top-left and the texture's (width,height) as the bottom right
Translate backwards by origin
Scale
Rotate
Translate by position
This places the sprite vertices in "client space", and then the transformation matrix transforms those vertices from client space into projection space (which is used for drawing).
I've got a highly-inlined version of this transformation in ExEn (SpriteBatch.InternalDraw in SpriteBatchOpenGL.cs) that you could easily adapt for your use.
I came across this question today and I want to add that you can do all of the calculations in the vertex shader itself:
float2 Viewport; //Set to viewport size from application code
void SpriteVertexShader(inout float4 color : COLOR0,
inout float2 texCoord : TEXCOORD0,
inout float4 position : POSITION0)
{
// Half pixel offset for correct texel centering.
position.xy -= 0.5;
// Viewport adjustment.
position.xy = position.xy / Viewport;
position.xy *= float2(2, -2);
position.xy -= float2(1, -1);
}
(I didn't write this, credit goes to the comments in the article mensioned above)
I am reading a book on OpenGL, SDL, and have read some of the OpenGL documentation. I have also read this post: What does glLoadIdentity() do in OpenGL?
I am grasping what glLoadIdentity() does, and why it is used in a general sense (to return the current matrix back to its original state). What I do not know is why I am returning it to its original state. For instance:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, 640, 480, 0.0f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
I am not exactly sure why glLoadIdentity() has to be called after each call to glMatrixMode.
When to call glMatrixMode() -- 1st answer tries to explain:
glLoadIdentity() is typically called immediately after a matrix mode change so you are starting "fresh" if you will. Matrix transforms such as the gluPerspective(), glOrtho(), glFrustum(), glRotate(), glMultMatrix(), glTranslate() are cumulative operations because they aggregate to allow you to describe complex 3D world space transforms or to describe your OpenGL viewing volume. Example: if I want a cube translated in the +X direction then rotated around the Z axis I issue a glRotate() followed by a glTranslate().
glLoadIdentity() wipes out the matrix (of the current matrix mode) with the identity matrix so following a gluPerspective() by glLoadIdentity() is equivalent to a single call to glLoadIdentity(). In other words, that sequence is nonsensical.