I have the following code to initialize my two matrices in lwjgl:
GL20.glUseProgram(shaderProgramID);
Matrix4f camera = new Matrix4f();
Matrix4f.translate(new Vector3f(0, 0, 0), camera, camera);
FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
camera.store(buffer);
buffer.flip();
GL20.glUniformMatrix2(GL20.glGetUniformLocation(shaderProgramID, "camera"), false, buffer);
GL20.glUseProgram(0);
float near = 0.1f, far = 100.0f, top = 300, bottom = -300, left = -400, right = 400;
Matrix4f projection = new Matrix4f();
projection.setIdentity();
projection.m00 = 2*near/(right - left);
projection.m11 = 2*near/(top - bottom);
projection.m22 = -(far +near)/(far - near);
projection.m23 = -1;
projection.m32 = -2*far*near/(far - near);
projection.m20 = (right+left)/(right -left);
projection.m21 = (top + bottom)/(top-bottom);
projection.m33 = 0;
FloatBuffer buffer2 = BufferUtils.createFloatBuffer(16);
projection.store(buffer2);
buffer.flip();
GL20.glUniformMatrix2(GL20.glGetUniformLocation(shaderProgramID, "projection"), false, buffer);
GL20.glUseProgram(0);
The vertex shader does the following:
gl_Position = projection * camera * vec4(vert, 1);
I dont know what could be wrong with it... anyone an idea?
I know this is late but for completenesse's sake:
The code above leaves no program bound when glUseProgram(0): is called, thus the later call of glUniform* creates a GL_INVALID_OPERATION as there is no program oject present. This also means that projection is never actually set for your program, so upon rendering it is an empty matrix which multiplied with a matrix and a vector still results in the null vector.
Also you might consider saving the uniform locations once after loading the shader and check if it actually is available.
Related
I'm a complete beginner to OpenGL programming and am trying to follow the Breakout tutorial at learnopengl.com but would like to draw the ball as an actual circle, instead of using a textured quad like Joey suggests. However, every result that Google throws back at me for "draw circle opengl 3.3" or similar phrases seems to be at least a few years old, and using even-older-than-that versions of the API :-(
The closest thing that I've found is this SO question, but of course the OP just had to use a custom VertexFormat object to abstract some of the details, without sharing his/her implementation of such! Just my luck! :P
There's also this YouTube tutorial that uses a seemingly-older version of the API, but copying the code verbatim (except for the last few lines which is where the code looks old) still got me nowhere.
My version of SpriteRenderer::initRenderData() from the tutorial:
void SpriteRenderer::initRenderData() {
GLuint vbo;
auto attribSize = 0;
GLfloat* vertices = nullptr;
// Determine whether this sprite is a circle or
// quad and setup the vertices array accordingly
if (!this->isCircle) {
attribSize = 4;
vertices = new GLfloat[24] {...} // works for rendering quads
} else {
// This code is adapted from the YouTube tutorial that I linked
// above and is where things go pear-shaped for me...or at least
// **not** circle-shaped :P
attribSize = 3;
GLfloat x = 0.0f;
GLfloat y = 0.0f;
GLfloat z = 0.0f;
GLfloat r = 100.0f;
GLint numSides = 6;
GLint numVertices = numSides + 2;
GLfloat* xCoords = new GLfloat[numVertices];
GLfloat* yCoords = new GLfloat[numVertices];
GLfloat* zCoords = new GLfloat[numVertices];
xCoords[0] = x;
yCoords[0] = y;
zCoords[0] = z;
for (auto i = 1; i < numVertices; i++) {
xCoords[i] = x + (r * cos(i * (M_PI * 2.0f) / numSides));
yCoords[i] = y + (r * sin(i * (M_PI * 2.0f) / numSides));
zCoords[i] = z;
}
vertices = new GLfloat[numVertices * 3];
for (auto i = 0; i < numVertices; i++) {
vertices[i * 3] = xCoords[i];
vertices[i * 3 + 1] = yCoords[i];
vertices[i * 3 + 2] = zCoords[i];
}
}
// This is where I go back to the learnopengl.com code. Once
// again, the following works for quads but not circles!
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(
GLfloat), vertices, GL_STATIC_DRAW);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, attribSize, GL_FLOAT, GL_FALSE,
attribSize * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
And here's the SpriteRenderer::DrawSprite() method (the only difference from the original being lines 24 - 28):
void SpriteRenderer::Draw(vec2 position, vec2 size, GLfloat rotation, vec3 colour) {
// Prepare transformations
shader.Use();
auto model = mat4(1.0f);
model = translate(model, vec3(position, 0.0f));
model = translate(model, vec3(0.5f * size.x, 0.5f * size.y, 0.0f)); // Move origin of rotation to center
model = rotate(model, rotation, vec3(0.0f, 0.0f, 1.0f)); // Rotate quad
model = translate(model, vec3(-0.5f * size.x, -0.5f * size.y, 0.0f)); // Move origin back
model = scale(model, vec3(size, 1.0f)); // Lastly, scale
shader.SetMatrix4("model", model);
// Render textured quad
shader.SetVector3f("spriteColour", colour);
glActiveTexture(GL_TEXTURE0);
texture.Bind();
glBindVertexArray(vao);
if (!isCircular) {
glDrawArrays(GL_TRIANGLES, 0, 6);
} else {
glDrawArrays(GL_TRIANGLE_FAN, 0, 24); // also tried "12" and "8" for the last param, to no avail
}
glBindVertexArray(0);
}
And finally, the shaders (different to the ones used for quads):
// Vertex shader
#version 330 core
layout (location = 0) in vec3 position;
uniform mat4 model;
uniform mat4 projection;
void main() {
gl_Position = projection * model *
vec4(position.xyz, 1.0f);
}
// Fragment shader
#version 330 core
out vec4 colour;
uniform vec3 spriteColour;
void main() {
colour = vec4(spriteColour, 1.0);
}
P.S. I know I could just use a quad but I'm trying to learn how to draw all primitives in OpenGL, not just quads and triangles (thanks anyway Joey)!
P.P.S I just realised that the learnopengl.com site has a whole section devoted to debugging OpenGL apps, so I set that up but to no avail :-( I don't think the error handling is supported by my driver (Intel UHD Graphics 620 latest driver) since the GL_CONTEXT_FLAG_DEBUG_BIT was not set after following the instructions:
Requesting a debug context in GLFW is surprisingly easy as all we have to do is pass a hint to GLFW that we'd like to have a debug output context. We have to do this before we call glfwCreateWindow:
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
Once we initialize GLFW we should have a debug context if we're using OpenGL version 4.3 or higher, or else we have to take our chances and hope the system is still able to request a debug context. Otherwise we have to request debug output using its OpenGL extension(s).
To check if we successfully initialized a debug context we can query OpenGL:
GLint flags; glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) {
// initialize debug output
}
That if statement is never entered into!
Thanks to #Mykola's answer to this question I have gotten half-way there:
numVertices = 43;
vertices = new GLfloat[numVertices];
auto i = 2;
auto x = 0.0f,
y = x,
z = x,
r = 0.3f;
auto numSides = 21;
auto TWO_PI = 2.0f * M_PI;
auto increment = TWO_PI / numSides;
for (auto angle = 0.0f; angle <= TWO_PI; angle += increment) {
vertices[i++] = r * cos(angle) + x;
vertices[i++] = r * sin(angle) + y;
}
Which gives me .
Two questions I still have:
Why is there an extra line going from the centre to the right side and how can I fix it?
According to #user1118321's comment on a related SO answer, I should be able to prepend another vertex to the array at (0, 0) and use GL_TRIANGLE_FAN instead of GL_LINE_LOOP
to get a coloured circle. But this results in no output for me :-( Why?
I can translate my 2d image to 0, 0 using the below code.
D3DXMATRIX worldMatrix, viewMatrix, orthoMatrix, rotation, movement;
// Get the world, view, and ortho matrices from the camera.
m_camera.GetViewMatrix(viewMatrix);
m_camera.GetWorldMatrix(worldMatrix);
m_camera.GetOrthoMatrix(orthoMatrix);
// Move the texture to the new position
D3DXMatrixTranslation(&movement, ((m_VerticeProperties->screenWidth / 2) * -1) + m_posX,
(m_VerticeProperties->screenHeight / 2) - m_posY, 0.0f);
worldMatrix = movement;
//float m_rotationZ = -90 * 0.0174532925f;
//D3DXMatrixRotationYawPitchRoll(&rotation, 0, 0, m_rotationZ);
//worldMatrix = rotation;
// Give the bitmap class what it needs to make source rect
m_bitmap->SetVerticeProperties(m_VerticeProperties->screenWidth, m_VerticeProperties->screenHeight,
m_VerticeProperties->frameWidth, m_VerticeProperties->frameHeight, m_VerticeProperties->U, m_VerticeProperties->V);
//Render the model (the vertices)
m_bitmap->Render(m_d3dManager.GetDeviceContext(), flipped);
//Render the shader
m_shader->Render(m_d3dManager.GetDeviceContext(), m_bitmap->GetIndexCount(), worldMatrix, viewMatrix,
orthoMatrix, m_bitmap->GetTexture(), m_textureTranslationU, m_VerticeProperties->translationPercentageV);
The result:
I can also rotate the image with this code:
D3DXMATRIX worldMatrix, viewMatrix, orthoMatrix, rotation, movement;
// Get the world, view, and ortho matrices from the camera.
m_camera.GetViewMatrix(viewMatrix);
m_camera.GetWorldMatrix(worldMatrix);
m_camera.GetOrthoMatrix(orthoMatrix);
//// Move the texture to the new position
//D3DXMatrixTranslation(&movement, ((m_VerticeProperties->screenWidth / 2) * -1) + m_posX,
// (m_VerticeProperties->screenHeight / 2) - m_posY, 0.0f);
//worldMatrix = movement;
float m_rotationZ = 90 * 0.0174532925f;
D3DXMatrixRotationYawPitchRoll(&rotation, 0, 0, m_rotationZ);
worldMatrix = rotation;
// Give the bitmap class what it needs to make source rect
m_bitmap->SetVerticeProperties(m_VerticeProperties->screenWidth, m_VerticeProperties->screenHeight,
m_VerticeProperties->frameWidth, m_VerticeProperties->frameHeight, m_VerticeProperties->U, m_VerticeProperties->V);
//Render the model (the vertices)
m_bitmap->Render(m_d3dManager.GetDeviceContext(), flipped);
//Render the shader
m_shader->Render(m_d3dManager.GetDeviceContext(), m_bitmap->GetIndexCount(), worldMatrix, viewMatrix,
orthoMatrix, m_bitmap->GetTexture(), m_textureTranslationU, m_VerticeProperties->translationPercentageV);
The result:
I thought multiplying the translation and rotation matrices and setting them = to the world matrix would allow me to see both effects at once.
D3DXMatrixTranslation(&movement, ((m_VerticeProperties->screenWidth / 2) * -1) + m_posX,
(m_VerticeProperties->screenHeight / 2) - m_posY, 0.0f);
float m_rotationZ = 90 * 0.0174532925f;
D3DXMatrixRotationYawPitchRoll(&rotation, 0, 0, m_rotationZ);
worldMatrix = rotation * movement;
It doesn't. The image no longer appears on the screen.
Can anyone tell me what im doing wrong? Thanks.
just do world * -translate * rotation * translate it will make you rotate local
here my code for example
void Ojbect::RotZ(float angle, Vec3 origin)
{
Mat4 w, rz, t;
rz.RotZ(angle);
t.Translation(-origin.x, -origin.y, 0);
w = t * rz * -1 * t;
Vec4 newPos;
for (int i = 0; i < countV; i++)
{
Vec3 pos(vertex[i].x, vertex[i].y, 1);
newPos.Transform(pos, w);
vertex[i].x = newPos.x;
vertex[i].y = newPos.y;
}
UpdateVertex(countV);
}
I am following this site to learn ray tracing using compute shaders: https://github.com/LWJGL/lwjgl3-wiki/wiki/2.6.1.-Ray-tracing-with-OpenGL-Compute-Shaders-%28Part-I%29
My question, The tutorial details a procedure to get the perspective projection. I think I followed his steps correctly but I am getting the wrong result and I believe I made a mistake in my matrix computations.
My code for the perspective projection-
//Getting the perspective projection using glm::perspective
glm::mat4 projection = glm::perspective(60.0f, 1024.0f/768.0f, 1.0f, 2.0f);
//My Camera Position
glm::vec3 camPos=glm::vec3(3.0, 2.0, 7.0);
//My View matrix using glm::lookAt
glm::mat4 view = glm::lookAt(camPos, glm::vec3(0.0, 0.5, 0.0),glm::vec3(0.0, 1.0, 0.0));
//Calculating inverse of the view*projection
glm::mat4 inv = glm::inverse(view*projection);
//Calculating the rays from camera position to the corners of the frustum as detailed in the site.
glm::vec4 ray00=glm::vec4(-1, -1, 0, 1) * inv;
ray00 /= ray00.w;
ray00 -= glm::vec4(camPos,1.0);
glm::vec4 ray10 = glm::vec4(+1, -1, 0, 1) * inv;
ray10 /= ray10.w;
ray10 -= glm::vec4(camPos,1.0);
glm::vec4 ray01=glm::vec4(-1, 1, 0, 1) * inv;
ray01 /= ray01.w;
ray01 -= glm::vec4(camPos,1.0);
glm::vec4 ray11 = glm::vec4(+1, +1, 0, 1) * inv;
ray11 /= ray11.w;
ray11 -= glm::vec4(camPos,1.0);
Result of above tranformations:
[![enter image description here][1]][1]
As additional information, I am calling my compute shaders using
//Dispatch Shaders.
glDispatchCompute ((GLuint)1024.0/16, (GLuint)768.0f/8 , 1);
I am also passing the values to the shader using the
//Querying the location for ray00 and assigning the value. Similarly for the rest
GLuint ray00Id = glGetUniformLocation(computeS, "ray00");
glUniform3f(ray00Id, ray00.x, ray00.y, ray00.z);
GLuint ray01Id = glGetUniformLocation(computeS, "ray01");
glUniform3f(ray01Id, ray01.x, ray01.y, ray01.z);
GLuint ray10Id = glGetUniformLocation(computeS, "ray10");
glUniform3f(ray10Id, ray10.x, ray10.y, ray10.z);
GLuint ray11Id = glGetUniformLocation(computeS, "ray11");
glUniform3f(ray11Id, ray11.x, ray11.y, ray11.z);
GLuint camId = glGetUniformLocation(computeS, "eye");
glUniform3f(camId, camPos.x, camPos.y, camPos.z);
Updated Answer following derhass suggestion.
My image now looks like :
Latest Image
The glm library uses the standard OpenGL matrix conventions, meaning that the matrices are created with the multiplication order Matrix * Vector in mind. So the following code is wrong:
//Calculating inverse of the view*projection
glm::mat4 inv = glm::inverse(view*projection);
The composition of the view matrix (transforming from world space to eye space) and the projection matrix (transforming from eye space to clip space) is projection * view, not view * projection as you put it (which would apply the projection before the view).
I try to use what many people seem to find a good way, I call gluUnproject 2 times with different z-values and then try to calculate the direction vector for the ray from these 2 vectors.
I read this question and tried to use the structure there for my own code:
glGetFloat(GL_MODELVIEW_MATRIX, modelBuffer);
glGetFloat(GL_PROJECTION_MATRIX, projBuffer);
glGetInteger(GL_VIEWPORT, viewBuffer);
gluUnProject(mouseX, mouseY, 0.0f, modelBuffer, projBuffer, viewBuffer, startBuffer);
gluUnProject(mouseX, mouseY, 1.0f, modelBuffer, projBuffer, viewBuffer, endBuffer);
start = vecmath.vector(startBuffer.get(0), startBuffer.get(1), startBuffer.get(2));
end = vecmath.vector(endBuffer.get(0), endBuffer.get(1), endBuffer.get(2));
direction = vecmath.vector(end.x()-start.x(), end.y()-start.y(), end.z()-start.z());
But this only returns the Homogeneous Clip Coordinates (I believe), since they only range from -1 to 1 on every axis.
How to actually get coordinates from which I can create a ray?
EDIT: This is how I construct the matrices:
Matrix projectionMatrix = vecmath.perspectiveMatrix(60f, aspect, 0.1f,
100f);
//The matrix of the camera = viewMatrix
setTransformation(vecmath.lookatMatrix(eye, center, up));
//And every object sets a ModelMatrix in it's display method
Matrix modelMatrix = parentMatrix.mult(vecmath
.translationMatrix(translation));
modelMatrix = modelMatrix.mult(vecmath.rotationMatrix(1, 0, 1, angle));
EDIT 2:
This is how the function looks right now:
private void calcMouseInWorldPosition(float mouseX, float mouseY, Matrix proj, Matrix view) {
Vector start = vecmath.vector(0, 0, 0);
Vector end = vecmath.vector(0, 0, 0);
FloatBuffer modelBuffer = BufferUtils.createFloatBuffer(16);
modelBuffer.put(view.asArray());
modelBuffer.rewind();
FloatBuffer projBuffer = BufferUtils.createFloatBuffer(16);
projBuffer.put(proj.asArray());
projBuffer.rewind();
FloatBuffer startBuffer = BufferUtils.createFloatBuffer(16);
FloatBuffer endBuffer = BufferUtils.createFloatBuffer(16);
IntBuffer viewBuffer = BufferUtils.createIntBuffer(16);
//The two calls for projection and modelView matrix are disabled here,
as I use my own matrices in this case
// glGetFloat(GL_MODELVIEW_MATRIX, modelBuffer);
// glGetFloat(GL_PROJECTION_MATRIX, projBuffer);
glGetInteger(GL_VIEWPORT, viewBuffer);
//I know this is really ugly and bad, but I know that the height and width is always 600
// and this is just for testing purposes
mouseY = 600 - mouseY;
gluUnProject(mouseX, mouseY, 0.0f, modelBuffer, projBuffer, viewBuffer, startBuffer);
gluUnProject(mouseX, mouseY, 1.0f, modelBuffer, projBuffer, viewBuffer, endBuffer);
start = vecmath.vector(startBuffer.get(0), startBuffer.get(1), startBuffer.get(2));
end = vecmath.vector(endBuffer.get(0), endBuffer.get(1), endBuffer.get(2));
direction = vecmath.vector(end.x()-start.x(), end.y()-start.y(), end.z()-start.z());
}
I'm trying to use my own projection and view matrix, but this only seems to give weirder results.
With the GlGet... stuff I get this for a click in the upper right corner:
start: (0.97333336, -0.98, -1.0)
end: (0.97333336, -0.98, 1.0)
When I use my own stuff I get this for the same position:
start: (-2.4399707, -0.55425626, -14.202201)
end: (-2.4399707, -0.55425626, -16.198204)
Now I actually need a modelView matrix instead of just the view matrix, but I don't know how I am supposed to get it, since it is altered and created anew in every display call of every object.
But is this really the problem? In this tutorial he says "Normally, to get into clip space from eye space we multiply the vector by a projection matrix. We can go backwards by multiplying by the inverse of this matrix." and in the next step he multiplies again by the inverse of the view matrix, so I thought this is what I should actually do?
EDIT 3:
Here I tried what user42813 suggested:
Matrix view = cam.getTransformation();
view = view.invertRigid();
mouseY = height - mouseY - 1;
//Here I only these values, because the Z and W values would be 0
//following your suggestion, so no use adding them here
float tempX = view.get(0, 0) * mouseX + view.get(1, 0) * mouseY;
float tempY = view.get(0, 1) * mouseX + view.get(1, 1) * mouseY;
float tempZ = view.get(0, 2) * mouseX + view.get(1, 2) * mouseY;
origin = vecmath.vector(tempX, tempY, tempZ);
direction = cam.getDirection();
But now the direction and origin values are always the same:
origin: (-0.04557252, -0.0020000197, -0.9989586)
direction: (-0.04557252, -0.0020000197, -0.9989586)
Ok I finally managed to work this out, maybe this will help someone.
I found some formula for this and did this with the coordinates that I was getting, which ranged from -1 to 1:
float tempX = (float) (start.x() * 0.1f * Math.tan(Math.PI * 60f / 360));
float tempY = (float) (start.y() * 0.1f * Math.tan(Math.PI * 60f / 360) * height / width);
float tempZ = -0.1f;
direction = vecmath.vector(tempX, tempY, tempZ); //create new vector with these x,y,z
direction = view.transformDirection(direction);
//multiply this new vector with the INVERSED viewMatrix
origin = view.getPosition(); //set the origin to the position values of the matrix (the right column)
I dont really use deprecated opengl but i would share my thought,
First it would be helpfull if you show us how you build your View matrix,
Second the View matrix you have is in the local space of the camera,
now typically you would multiply your mouseX and (ScreenHeight - mouseY - 1) by the View matrix (i think the inverse of that matrix sorry, not sure!) then you will have the mouse coordinates in camera space, then you will add the Forward vector to that vector created by the mouse, then you will have it, it would look something like that:
float mouseCoord[] = { mouseX, screen_heihgt - mouseY - 1, 0, 0 }; /* 0, 0 because we multipling by a matrix 4.*/
mouseCoord = multiply( ViewMatrix /*Or: inverse(ViewMatrix)*/, mouseCoord );
float ray[] = add( mouseCoord, forwardVector );
I'm having trouble converting my OpenGL scene coordiates to my screen coordinates.
I thought I needed to multiply my coordinates with the modelview matrix then with the projection matrix to get the ndc. But i'm getting weird coordinates.
Here is my piece of code
GLKVector3 coor = GLKVector3Make(point.x, point.y, 0);
GLKMatrix4 modelview = GLKMatrix4MakeWithArray(glProjectionMatrix);
GLKMatrix4 projetion = GLKMatrix4MakeWithArray(modelViewMatrix.data);
GLKVector3 eyeCoor = GLKMatrix4MultiplyVector3(modelview, coor);
GLKVector3 ndcCoor = GLKMatrix4MultiplyVector3(projetion,eyeCoor);
CGPoint p = CGPointMake(ndcCoor.x, ndcCoor.y);
Any idea ?
The code seems perfectly valid, but you should use 4D vectors for these homogeneous transforms.
So,
GLKVector4 coor = GLKVector4Make(point.x, point.y, 0, 1);
/// I hope those matrices are fine
GLKMatrix4 modelview = GLKMatrix4MakeWithArray(glProjectionMatrix);
GLKMatrix4 projetion = GLKMatrix4MakeWithArray(modelViewMatrix.data);
GLKVector4 eyeCoor = GLKMatrix4MultiplyVector4(modelview, coor);
GLKVector4 ndcCoor = GLKMatrix4MultiplyVector4(projetion,eyeCoor);
float XScr = ndcCoor.x / ndcCoor.w;
float YScr = ndcCoor.y / ndcCoor.w;
CGPoint p = CGPointMake(XScr, YScr);
If you want XScr and YScr to be in [0..1] range, then add
XScr = (XScr + 1.0f) * 0.5f;
YScr = (YScr + 1.0f) * 0.5f;
conversion.
Even easier: use the GLKit Math function GLKMathProject.
GLKVector3 GLKMathProject (
GLKVector3 object,
GLKMatrix4 model,
GLKMatrix4 projection,
int *viewport
);
So, in your case, e.g.
int viewport[] = {0, 0, 320, 480};
GLKVector3 windowVector = GLKMathProject(coor, modelview, projetion, viewport);
CGPoint p = CGPointMake(windowVector.x, windowVector.y);
Note that the origin is at lower left, so if you're using UIKit coordinates where the origin is at the upper left, then switch the y coordinate, e.g.
CGPoint p = CGPointMake(windowVector.x, window.bounds.size.height - windowVector.y);