Related
i am trying to make a clock and have all the numbers in the correct place but they are all rotated e.g. 6 is upside down whereas 12 is correct. is there anyway to rotate just the text not the position of the text?
my code is
push();
textSize(48);
for (int i = 1; i < 13; i++) {
int offset = -15;
if (str(i).length() == 2) {
offset -= 14.5;
}
rotate(radians(30));
text(i, offset, -350);
//println(i*30);
}
pop();
Without seeing the code my hunch is you use rotate(), but probably you don't use pushMatrix()/popMatrix(); to isolate the coordinate space to local one that can be temporarily rotated.
I recommend reading the 2D Transformations tutorial
As the tutorial mentions, the order of transformations matters:
size(300, 300);
background(0);
stroke(255);
// center align text
textAlign(CENTER);
// global translation to center
translate(width / 2, height / 2);
int hours = 12;
// an angle section (360/12 = 30 degrees), but in radians
float angleIncrement = TWO_PI / hours;
// distance from center
float radius = 100;
for(int i = 0 ; i < hours; i++){
// calculate the angle for each hour, subtracting a bit because angle 0 points to the right, not top (12 o'clock)
// remember this offset: it may come in handy when drawing clock handles ;)
float angle = (angleIncrement * i) - (QUARTER_PI * 4/3);
// isolate coordinate space
pushMatrix();
// rotate from global center by each hour angle
rotate(angle);
// translate from locally rotated center based on radius
translate(radius, 0);
// undo local rotation so text is straight
rotate(-angle);
// render text
text(i+1,0,0);
// exit local coordinate system, back to global coordinates after this
popMatrix();
}
Here is the same example with a helper function to help visualise the coordinate systems:
void setup() {
size(300, 300);
background(0);
stroke(255);
// center align text
textAlign(CENTER);
drawCoordinateSystem("1.original cooordinates",60, 255);
// global translation to center
translate(width / 2, height / 2);
drawCoordinateSystem("2.global center",60, 64);
int hours = 12;
// an angle section (360/12 = 30 degrees), but in radians
float angleIncrement = TWO_PI / hours;
// distance from center
float radius = 100;
for (int i = 0; i < hours; i++) {
// calculate the angle for each hour, subtracting a bit because angle 0 points to the right, not top (12 o'clock)
// remember this offset: it may come in handy when drawing clock handles ;)
float angle = (angleIncrement * i) - (QUARTER_PI * 4/3);
// isolate coordinate space
pushMatrix();
// rotate from global center by each hour angle
rotate(angle);
if(i == 0){
drawCoordinateSystem("3.local+rotation",60, 127);
}
// translate from locally rotated center based on radius
translate(radius, 0);
if(i == 0){
drawCoordinateSystem("4.local+rot.+\ntrans.",60, 192);
}
// undo local rotation so text is straight
rotate(-angle);
if(i == 0){
drawCoordinateSystem("\n5.prev.\n-rot.",60, 255);
}
// render text
text(i+1, 0, 0);
// exit local coordinate system, back to global coordinates after this
popMatrix();
}
}
void drawCoordinateSystem(String label, float size, float alpha){
pushStyle();
textAlign(LEFT);
strokeWeight(3);
// x axis
stroke(192, 0, 0, alpha);
line(0, 0, size, 0);
// y axis
stroke(0, 192, 0, alpha);
line(0, 0, 0, size);
text(label, 10, 15);
popStyle();
}
Note that the indent is not required for pushMatrix()/popMatrix(), it's more of a visual cue to aid when you read code to remember coordinate system nesting.
This is over the top and you won't need the code bellow, but hopefully it's a fun visualisation:
PImage screenshot;
String[] labels = {"1.original cooordinates","2.global center\ntranslate(width / 2, height / 2)",
"3.local+rotation\npushMatrix();\nrotate(angle)",
"4.local+rot.+\ntrans.\ntranslate(radius, 0)","5.previous-rot.\nrotate(-angle)",""};
PMatrix2D[] systems = new PMatrix2D[labels.length];
PMatrix2D lerpMatrix = new PMatrix2D();
void setup() {
size(300, 300);
background(0);
stroke(255);
// center align text
textAlign(CENTER);
// "1.original cooordinates"
systems[0] = new PMatrix2D();
// global translation to center
translate(width / 2, height / 2);
// "2.global center"
systems[1] = systems[0].get();
systems[1].translate(width / 2, height / 2);
int hours = 12;
// an angle section (360/12 = 30 degrees), but in radians
float angleIncrement = TWO_PI / hours;
// distance from center
float radius = 100;
for (int i = 0; i < hours; i++) {
// calculate the angle for each hour, subtracting a bit because angle 0 points to the right, not top (12 o'clock)
// remember this offset: it may come in handy when drawing clock handles ;)
float angle = (angleIncrement * i) - (QUARTER_PI * 4/3);
// isolate coordinate space
pushMatrix();
// rotate from global center by each hour angle
rotate(angle);
if(i == 0){
// "3.local+rotation"
PMatrix2D local = new PMatrix2D();
local.apply(systems[1]);
local.rotate(angle);
systems[2] = local.get();
}
// translate from locally rotated center based on radius
translate(radius, 0);
if(i == 0){
// "4.local+rot.+\ntrans."
systems[3] = systems[2].get();
systems[3].translate(radius,0);
}
// undo local rotation so text is straight
rotate(-angle);
if(i == 0){
// "\n5.prev.\n-rot."
systems[4] = systems[3].get();
systems[4].rotate(-angle);
systems[5] = systems[4];
}
// render text
text(i+1, 0, 0);
// exit local coordinate system, back to global coordinates after this
popMatrix();
}
screenshot = get();
}
void draw(){
image(screenshot,0, 0);
animateCoordinateSystems();
text("mouse mouse on X axis", width / 2, height - 12);
}
void animateCoordinateSystems(){
float mapping = map(constrain(mouseX, 0, width), 0, width, 0.0, 1.0);
float globalT = (float)(labels.length -1) * mapping;
int index = (int)globalT;
float localT = globalT - index;
lerpMatrix(systems[index], systems[index+1], localT, lerpMatrix);
pushMatrix();
applyMatrix(lerpMatrix);
drawCoordinateSystem(labels[index] + (labels[index+1].length() > 0 ? "\ntransitions to\n" + labels[index+1] : ""),60, 255);
popMatrix();
}
void lerpMatrix(PMatrix2D from, PMatrix2D to, float t, PMatrix2D result){
result.m00 = lerp(from.m00, to.m00, t);
result.m01 = lerp(from.m01, to.m01, t);
result.m02 = lerp(from.m02, to.m02, t);
result.m10 = lerp(from.m10, to.m10, t);
result.m11 = lerp(from.m11, to.m11, t);
result.m12 = lerp(from.m12, to.m12, t);
}
void drawCoordinateSystem(String label, float size, float alpha){
pushStyle();
textAlign(LEFT);
strokeWeight(3);
// x axis
stroke(192, 0, 0, alpha);
line(0, 0, size, 0);
// y axis
stroke(0, 192, 0, alpha);
line(0, 0, 0, size);
text(label, 10, 15);
popStyle();
}
I have a basic LWJGL window set up and I am trying to draw a square using the glBegin(GL_QUADS) method. Square square = new Square(25, 25, 25), is the way I am calling my Square class to draw the square... but it is a rectangle. When I call it I pass in all 25's as the parameters. the first two are the starting coordinates and the last 25 is the side length, as seen below. What am I doing wrong to produce a rectangle?
public Square(float x,float y,float sl) {
GL11.glColor3f(0.5F, 0.0F, 0.7F);
glBegin(GL11.GL_QUADS);
glVertex2f(x, y);
glVertex2f(x, y+sl);
glVertex2f(x+sl, y+sl);
glVertex2f(x+sl, y);
glEnd();
}
My Viewport code
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // Resets any previous projection matrices
glOrtho(0, 640, 0, 480, 1, -1);
glMatrixMode(GL_MODELVIEW);
Using glOrtho(0, 640, 0, 480, 1, -1); constructs a non-square viewport. That means that the rendered output is more than likely going to be skewed if your window is not the same size as your viewport (or at least the same aspect ratio).
Consider the following comparison:
If your viewport is the same size as your window, then it should remain square. I'm using JOGL, but in my resize function, I reshape my viewport to be the new size of my window.
glcanvas.addGLEventListener(new GLEventListener() {
#Override
public void reshape(GLAutoDrawable glautodrawable, int x, int y, int width, int height) {
GL2 gl = glautodrawable.getGL().getGL2();
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity(); // Resets any previous projection matrices
gl.glOrtho(0, width, 0, height, 1, -1);
gl.glMatrixMode(GL2.GL_MODELVIEW);
}
... Other methods
}
To draw a square around the point (x | y) you can calculate the four points that represent the corners of your square.
First you'll need your width to height ratio
float ratio = width / height
I will use a defaultSize for the length of the shortest path from the midpoint to any of the sides.
Then you can calculate four values like so:
float a = x + defaultSize
float b = ratio * (y + defaultSize)
float c = x - defaultSize
float d = ratio * (y - defaultSize)
with which you can represent all four corners to draw your square with. Since GL_SQUAD is deprecated I'll use GL_TRIANGLE.
glBegin(GL_TRIANGLES);
glColor3f(red, green, blue);
// upper left triangle
glVertex2f(a, b);
glVertex2f(c, b);
glVertex2f(c, d);
// lower right triangle
glVertex2f(a, b);
glVertex2f(c, d);
glVertex2f(a, d);
glEnd();
I don't know if this is the most performant or idiomatic way to do this since I just started exploring LWJGL.
Im trying to implement Bitmap font rendering. The only thing that confuses me so much, that i have to ask about it here, is that when I draw the quads for each char, every time it a new quad get rendered, the UV`s are absolutelly broken.
If I just render a single quad, everything is OK.
(tile x = 3, y = 4)
Thats what it looks like with a few more letters.
Thats my code to render this stuff:
...
rc.translate(getTransform().getPos());
drawTileAt(3, 4);
rc.translate(100, 0, 0);
drawTileAt(5, 5);
rc.translate(200, 0, 0);
drawTileAt(2,6);
rc.translate(300,0,0);
drawTileAt(1, 7);
...
public void drawTileAt(int x, int y)
{
float w = 1f / 16f;
float _x = 1f / 16f * x;
float _y = 1f / 16f * y;
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2f(0, 100);GL11.glTexCoord2f(_x,_y);
GL11.glVertex2f(0, 0);GL11.glTexCoord2f(_x + w,_y);
GL11.glVertex2f(100,0);GL11.glTexCoord2f(_x + w,_y + w);
GL11.glVertex2f(100, 100);
GL11.glTexCoord2f(_x,_y + w);
GL11.glEnd();
}
Im also drawing VBO quads with tex-coords, everything looks fine...
glVertex() bundles up the current vertex state (like the texture coordinate!) and sends it to the GPU.
So you need to set the texcoord before you set the vertex position:
GL11.glTexCoord2f(_x,_y); GL11.glVertex2f(0, 100);
GL11.glTexCoord2f(_x + w,_y); GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(_x + w,_y + w); GL11.glVertex2f(100,0);
GL11.glTexCoord2f(_x,_y + w); GL11.glVertex2f(100, 100);
I got this code for billboarding I created (With the help of others, and a nehe tutorial), but it seems that when I move my sprites from 0,0,0 it stops working correctly, for example the closer I get to a sprite that's at 50,0,50 the more sideways it gets.
Any idea how to make the sprites billboard properly when not on 0,0,0?
Here is the code:
public void drawBillBoardSprite(Texture texture, Vector3f sprPos, float r, float g, float b, int sprWidth, int sprHeight){
// store the current model matrix
GL11.glPushMatrix();
// bind to the appropriate texture for this sprite
texture.bind();
Vector3f look = new Vector3f(0,0,0);
Vector3f.sub(player.pos, sprPos, look);
look.normalise();
Vector3f right = new Vector3f(0,0,0);
Vector3f.cross(new Vector3f(0,1,0) /* <-- default up vector */, look, right);
right.normalise();
Vector3f up = new Vector3f(0,0,0);
Vector3f.cross(look, right, up);
up.normalise();
Matrix4f m = new Matrix4f();
m.m00 = right.x;
m.m01 = right.y;
m.m02 = right.z;
m.m03 = 0;
m.m10 = up.x;
m.m11 = up.y;
m.m12 = up.z;
m.m13 = 0;
m.m20 = look.x;
m.m21 = look.y;
m.m22 = look.z;
m.m23 = 0;
m.m30 = sprPos.x;
m.m31 = sprPos.y;
m.m32 = sprPos.z;
m.m33 = 1;
java.nio.FloatBuffer fb = BufferUtils.createFloatBuffer(32);
m.store(fb);
fb.flip();
GL11.glMultMatrix(fb);
// draw a quad textured to match the sprite
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0,0); GL11.glVertex3f( - (sprWidth/2), (sprHeight/2), 0); // Top left Of The Quad (Left)
GL11.glTexCoord2f(texture.getWidth(), 0); GL11.glVertex3f( + (sprWidth/2), (sprHeight/2), 0); // Top right Of The Quad (Left)
GL11.glTexCoord2f(texture.getWidth(), texture.getHeight()); GL11.glVertex3f( + (sprWidth/2), -(sprHeight/2), 0); // Bottom right Of The Quad (Left)
GL11.glTexCoord2f(0, texture.getHeight()); GL11.glVertex3f( - (sprWidth/2), -(sprHeight/2), 0); // Bottom left Of The Quad (Left)
GL11.glEnd();
// restore the model view matrix to prevent contamination
GL11.glPopMatrix();
}
Edit: tried this code based on Knetic's answer, but it didn't even rotate the sprites towards the camera. Here is the code I used:
public void drawBillBoardSprite(Texture texture, Vector3f sprPos, float r, float g, float b, int sprWidth, int sprHeight){
// store the current model matrix
GL11.glPushMatrix();
FloatBuffer tempViewBuf = BufferUtils.createFloatBuffer(16);
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, tempViewBuf);
float[] tempView = new float[16];
for(int i = 0; i < 16; i++){
tempView[i] = tempViewBuf.get(i);
}
float[] modelView = new float[6];
modelView[0] = tempView[0] - tempView[1];
modelView[1] = tempView[0] + tempView[1];
modelView[2] = tempView[4] - tempView[5];
modelView[3] = tempView[4] + tempView[5];
modelView[4] = tempView[8] - tempView[9];
modelView[5] = tempView[8] + tempView[9];
// bind to the appropriate texture for this sprite
texture.bind();
// draw a quad textured to match the sprite
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0,0); GL11.glVertex3f( - (sprWidth/2) + modelView[1], (sprHeight/2) + modelView[3], 0 + modelView[5]); // Top left Of The Quad (Left)
GL11.glTexCoord2f(texture.getWidth(), 0); GL11.glVertex3f( + (sprWidth/2) + modelView[0], (sprHeight/2) + modelView[2], 0 + modelView[4]); // Top right Of The Quad (Left)
GL11.glTexCoord2f(texture.getWidth(), texture.getHeight()); GL11.glVertex3f( + (sprWidth/2) + modelView[1], -(sprHeight/2)+ modelView[3], 0 + modelView[5]); // Bottom right Of The Quad (Left)
GL11.glTexCoord2f(0, texture.getHeight()); GL11.glVertex3f( - (sprWidth/2) + modelView[0], -(sprHeight/2)+ modelView[2], 0 + modelView[4]); // Bottom left Of The Quad (Left)
GL11.glEnd();
// restore the model view matrix to prevent contamination
GL11.glPopMatrix();
}
I dug up an old project of mine which had billboarded particles, and my solution was this.
static float[] tempView;
// ...additional render stuff up here
// If there's anything that needs billboarding
if(getParticleTop() > 0)
{
glGetFloatv(GL_MODELVIEW_MATRIX, tempView);
modelView[0] = tempView[0] - tempView[1];
modelView[1] = tempView[0] + tempView[1];
modelView[2] = tempView[4] - tempView[5];
modelView[3] = tempView[4] + tempView[5];
modelView[4] = tempView[8] - tempView[9];
modelView[5] = tempView[8] + tempView[9];
// ... render each particle
}
And in the individual particle renders
float* modelView = renderer->getModelView();
glBegin(GL_QUADS);
{
glTexCoord2f(0, 1);
glVertex3f(owner->x - (modelView[1] * scale), owner->y - (modelView[3] * scale), owner->z - (modelView[5] * scale));
glTexCoord2f(0, 0);
glVertex3f(owner->x + (modelView[0] * scale), (owner->y + modelView[2] * scale), owner->z + (modelView[4] * scale));
glTexCoord2f(1, 0);
glVertex3f(owner->x + (modelView[1] * scale), owner->y + (modelView[3] * scale), owner->z + (modelView[5] * scale));
glTexCoord2f(1, 1);
glVertex3f(owner->x - (modelView[0] * scale), owner->y + (modelView[2] * scale), owner->z - (modelView[4] * scale));
}
glEnd();
Looking on it now, i see that i wasn't precaching scalar calculation and was using GL_QUADS instead of unrolling it myself, but i do know this works with all angles and all sizes.
I remember going through NeHe's tutorial and finding the same problem, this solution gave up on NeHe and googled out someone else who suggested the GL modelview method, which saves calculations (and time, if your video architecture is close enough to your processor).
I hope this helps.
EDIT; I should have mentioned, but the layout i used in this project was to have the entity class separate from model classes, so each entity could switch or share models as required; so this is a billboard model class, and owner->x/y/z refer to the entity who owns that model's position.
Just had to use a different way of billboarding:
public void drawBillBoardSprite(Texture texture, Vector3f sprPos, float r, float g, float b, int sprWidth, int sprHeight){
// store the current model matrix
GL11.glPushMatrix();
GL11.glTranslatef(sprPos.x, 0, sprPos.z);
// bind to the appropriate texture for this sprite
texture.bind();
FloatBuffer modelview = BufferUtils.createFloatBuffer(16);
// get the current modelview matrix
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelview);
// Note that a row in the C convention is a column
// in OpenGL convention (see the red book, pg.106 in version 1.2)
// right vector is [1,0,0] (1st column)
// lookAt vector is [0,0,1] (3d column)
// leave the up vector unchanged (2nd column)
// notice the increment in i in the first cycle (i+=2)
for(int i=0; i<3; i+=2 )
for(int j=0; j<3; j++ ) {
if ( i==j )
modelview.put(i*4+j, 1.0f);
else
modelview.put(i*4+j, 0.0f);
}
// set the modelview matrix
GL11.glLoadMatrix(modelview);
// draw a quad textured to match the sprite
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0,0); GL11.glVertex3f( - (sprWidth/2), (sprHeight/2), 0); // Top left Of The Quad (Left)
GL11.glTexCoord2f(texture.getWidth(), 0); GL11.glVertex3f( + (sprWidth/2), (sprHeight/2), 0); // Top right Of The Quad (Left)
GL11.glTexCoord2f(texture.getWidth(), texture.getHeight()); GL11.glVertex3f( + (sprWidth/2), -(sprHeight/2), 0); // Bottom right Of The Quad (Left)
GL11.glTexCoord2f(0, texture.getHeight()); GL11.glVertex3f( - (sprWidth/2), -(sprHeight/2), 0); // Bottom left Of The Quad (Left)
GL11.glEnd();
// restore the model view matrix to prevent contamination
GL11.glPopMatrix();
}
I am trying to get some circles drawn onscreen using OpenGL ES 1.5 for android. They draw, but I want to be able to input x=300, y=500, and it will draw the circle centered at that coordinate (e.g. at the (300,500) pixel on the screen). Currently, I draw and translate the circles, but its not precise, I don't know how to get it exactly where i want it: here's some broken code from my last attempt:
//doesn't take w/h ratio into consideration, not sure how to implement that
gl.glViewport(0, 0, windowWidth, windowHeight);
gl.glOrthof(0,windowWidth, 0, windowHeight, 1, 2);
GLU.gluLookAt(gl, 0, 0, 5, 0, 0, 0, 0, 1, 0);
//And for drawing a circle, with the desired x and y coordinates:
for (int j = 0; j < number_Triangles; j++) {
x = Math.cos(theta) + xCoor;
y = Math.sin(theta) + yCoor;
z = 1;
theta += 2 * Math.PI / (number_Triangles);
}
If you are doing 2D graphics, I'd recommend gluOrtho2D(left,right,bottom,top). That way you have exact control over what coordinates will map to each edge of your screen.
So, for example, you could have:
gl.glViewport(0,0,windowWidth,windowHeight);
GLU.gluOrtho2D(-2.0f, 2.0f, -2.0f, 2.0f);
for (int j = .....