Related
I want to draw cube and sphere, but openGl draws only cube. I've made 2 VAOs: first VAO contains VBO (with coordinates cube), other VAO contains coordinates sphere. If I want to draw only sphere, it doen't work as well. Maybe it happens because of inorrect VBO binding...but I don't exactly understand how to deal with it.
Code below (making sphere):
GLuint sphere(float radius, int slices, int stacks) {
GLuint vbo;
int n = 2 * (slices + 1) * stacks;
int i = 0;
vec3 *points = new vec3[n];
for (float theta = -M_PI / 2; theta < M_PI / 2 - 0.0001; theta += M_PI / stacks) {
for (float phi = -M_PI; phi <= M_PI + 0.0001; phi += 2 * M_PI / slices) {
points[i++] = vec3(cos(theta) * sin(phi), -sin(theta), cos(theta) * cos(phi));
points[i++] = vec3(cos(theta + M_PI / stacks) * sin(phi), -sin(theta + M_PI / stacks), cos(theta + M_PI / stacks) * cos(phi));
}
}
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
return vbo;}
Main (I remove cube coordinates in code, because it's too long):
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Laba5", nullptr, nullptr);
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, key_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glewExperimental = GL_TRUE;
glewInit();
glViewport(0, 0, WIDTH, HEIGHT);
glEnable(GL_DEPTH_TEST);
Shader ourShader("shader.vs", "shader.frag");
GLuint VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0); // Unbind VAO
//-----------------------------------------------------------2
GLuint VAO2;
glGenVertexArrays(1, &VAO2);
glBindVertexArray(VAO2);
glBindBuffer(GL_ARRAY_BUFFER, sphere(1, 30, 30));
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindVertexArray(0); // Unbind VAO
while (!glfwWindowShouldClose(window))
{
// Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
glfwPollEvents();
glClearColor(0.32f, 0.31f, 0.30f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ourShader.Use();
mat4 view = mat4(1.0);
mat4 projection = mat4(1.0);
view = translate(view, vec3(1.0f, 1.0f, -4.8f));
projection = perspective(45.0f, (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);
GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
GLint viewLoc = glGetUniformLocation(ourShader.Program, "view");
GLint projLoc = glGetUniformLocation(ourShader.Program, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
if (lbutton_down)
{
double cur_mx, cur_my;
glfwGetCursorPos(window, &cur_mx, &cur_my);
if (cur_mx != last_mx || cur_my != last_my)
{
vec3 va = get_arcball_vector(last_mx, last_my);
vec3 vb = get_arcball_vector(cur_mx, cur_my);
float angle = acos(min(1.0f, dot(va, vb)));
vec3 axis_in_camera_coord = cross(va, vb);
mat3 camera2object = inverse(model);
vec3 axis_in_object_coord = camera2object * axis_in_camera_coord;
model = rotate(model, degrees(angle)*0.05f, axis_in_object_coord);
last_mx = cur_mx;
last_my = cur_my;
}
}
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glBindVertexArray(VAO2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 2 * 31 * 30);
glBindVertexArray(0);
glfwSwapBuffers(window);
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteVertexArrays(1, &VAO2);
glfwTerminate();
return 0;
Your sphere function internally creates a new GL buffer object and returns its name, so:
GLuint sphereVBO = sphere(1, 30, 30);
you now have sphereVBO containing the name of that buffer.
glGenVertexArrays(1, &VAO2);
glGenBuffers(1, &sphereVBO);
But now, you created a new buffer object, and did overwrite sphereVBO with the new name. As a result, you are trying to draw from an empty buffer object (there was no call to glBufferData to actually create a data storage for it), and you totally lost track of the original VBO with the sphere data.
The class copied below serve to create an OpenGL context in a QT widget.
However it doesn't display any point while it works well when I use GLFW...
#include "glwidget.h"
#include "shader.hpp"
GLWidget::GLWidget(QWidget *parent) : QGLWidget(parent) {
}
GLWidget::~GLWidget() {
// Cleanup VBO
glDeleteBuffers(1, &vertexbuffer);
glDeleteBuffers(1, &colorbuffer);
glDeleteBuffers(1, &elementbuffer);
glDeleteProgram(programID);
glDeleteVertexArrays(1, &VertexArrayID);
}
void GLWidget::initializeGL()
{
glewInit();
// Dark blue background
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
// Cull triangles which normal is not towards the camera
glEnable(GL_CULL_FACE);
// Create and compile our GLSL program from the shaders
programID = LoadShaders("SimpleVertexShader.vertexshader", "ColorFragmentShader.fragmentshader");
// Get a handle for our "MVP" uniform
MatrixID = glGetUniformLocation(programID, "MVP");
ModelMatrixID = glGetUniformLocation(programID, "M");
// Get a handle for our buffers
vertexPosition_modelspaceID = glGetAttribLocation(programID, "vertexPosition_modelspace");
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Temporary code for vertices and their color generation
vertices.push_back(glm::vec3(0,0,0)); // A point situated at 0,0,0 for test
color.push_back(glm::vec3(1.0, 0.0, 0.0));
index.push_back(0);
int size = 1000;
for (int i = 1; i < size; ++i) {
vertices.push_back(glm::vec3((rand() % 100) / 10, (rand() % 100) / 10, (rand() % 100) / 10));
color.push_back(glm::vec3(1.0, 0.0, 0.0));
index.push_back(i);
}
/*Computing the points centroid */
for (int i = 0; i < vertices.size(); i++)
{
mx += vertices[i][0];
my += vertices[i][1];
mz += vertices[i][2];
}
mx = mx / vertices.size(); my = my / vertices.size(); mz = mz / vertices.size();
for (int i = 0; i < vertices.size(); i++)
{
vertices[i][0] = vertices[i][0] - mx;
vertices[i][1] = vertices[i][1] - my;
vertices[i][2] = vertices[i][2] - mz;
}
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glBufferData(GL_ARRAY_BUFFER, color.size() * sizeof(glm::vec3), &color[0], GL_STATIC_DRAW);
glGenBuffers(1, &elementbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index.size() * sizeof(unsigned int), &index[0], GL_STATIC_DRAW);
/* Line indexing, not in use actually....
unsigned int indexL[] = { 1550, vertices.size() - 1300 };
GLuint elementbufferLine;
glGenBuffers(1, &elementbufferLine);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbufferLine);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * sizeof(unsigned int), &indexL[0], GL_STATIC_DRAW); */
}
void GLWidget::resizeGL(int w, int h)
{
//glViewport(0, 0, w, h);
ViewMatrix = glm::lookAt(
glm::vec3(-5, -5, -5), // Camera is here
glm::vec3(mx, my, mz), // and looks here
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
ModelMatrix = glm::mat4(1.0f);
ProjectionMatrix = glm::perspective(glm::radians(80.0f), float(w) /float(h), 0.1f, 100.0f);
MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
}
void GLWidget::paintGL()
{
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Using shaders */
glUseProgram(programID);
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(
1, // attribute. No particular reason for 1, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
// Draw the point cloud !
glPointSize(5);
glDrawElements(
GL_POINTS, // mode
index.size(), // count
GL_UNSIGNED_INT, // type
(void*)0 // element array buffer offset
);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
I believe with your math, all vertices are created in a (0,0,0)-(9.9, 9.9, 9.9) range. Then you compute the centroid and subtract. lets say your mx, my, mz is (5.0, 5.0, 5.0). Now if you subtract the centroid, all your points are now in the range (-5.0, -5.0, -5.0) and (4.9, 4.9, 4.9).
In other words all you have done is center all your points to the origin. I believe you should be looking at the origin (0, 0, 0) not (5, 5, 5).
When I try to draw circle using glDrawArrays it displays quarter of circle
The VBO, generated by code, is correct. BTW there is no such coord as 0,0,0.
It appears that it draws only positive vertices, but if I multiply vertices by -1 glDrawArrays draws it on other side of screen.
Here's my code:
uint un_vertexArraySize = 20;
float f_radius = 1.0f;
float f_degrees = 0;
GLfloat f_vert[un_vertexArraySize*3];
// Generate circle vertices
for (int i=0; i<un_vertexArraySize*3; i+=3)
{
f_vert[i] = cos(f_degrees*M_PI/180)*f_radius;
f_vert[i+1] = sin(f_degrees*M_PI/180)*f_radius;
f_vert[i+2] = 0.0f;
f_degrees += (360/un_vertexArraySize);
}
// Do buffer stuff
GLuint vbo;
glGenBuffers(1, &vbo);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, un_vertexArraySize*3,
f_vert, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0); // unbind VBO
glBindVertexArray(0); // unbind VAO
// Start loop
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
shader.Use();
glBindBuffer(GL_ARRAY_BUFFER, vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_LINE_STRIP, 0, un_vertexArraySize*3);
glDisableVertexAttribArray(0);
shader.UnUse();
// End loop
Frag shader:
#version 130
void main(void)
{
gl_FragColor[0] = gl_FragCoord.x/640.0;
gl_FragColor[1] = gl_FragCoord.y/480.0;
gl_FragColor[2] = 0.2;
gl_FragColor[3] = 1.0f;
}
Vert shader:
#version 130
attribute vec3 coord3d;
void main(void)
{
vec4 temp = vec4(coord3d, 1.0f);
gl_Position = temp;
}
I tried to google it or find on stackoverflow, but nothing.
I can't test this right now but at glBufferData you use un_vertexArraySize*3, that is the number of elements, but I think you missed multiplying by 4 (bytes per float) so the size is specified in bytes. That would explain why you're only drawing a quarter of the circle
First of all - the code:
std::vector<glm::vec3> verticescopy;
std::vector<glm::vec2> newUVs;
/*Generating new UV Coordinates*/
void keyfunction(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_R && action == GLFW_PRESS)
{
glm::vec3 coords2D;
GLdouble point2DX, point2DY, point2DZ;
GLdouble model_view[16];
glGetDoublev(GL_MODELVIEW_MATRIX, model_view);
GLdouble projection[16];
glGetDoublev(GL_PROJECTION_MATRIX, projection);
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
for (int i = 0; i < verticescopy.size(); i++)
{
gluProject((double)verticescopy[i].x, (double)verticescopy[i].y, (double)verticescopy[i].z,
model_view, projection, viewport,
&point2DX, &point2DY, &point2DZ);
glm::vec2 UV;
UV.x = point2DX / 600;
UV.y = (point2DY - 800) / 800; /* I make Y - 800, because values from glProject are generated from (0,1), not (0,0) */
newUVs.push_back(UV);
}
}
}
int main(void)
{
if (!glfwInit())
{
fprintf(stderr, "Failed to initialize GLFW\n");
getchar();
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
window = glfwCreateWindow(600, 800, "Window", NULL, NULL);
if (window == NULL)
{
fprintf(stderr, "Nie utworzono okna GLFW.\n");
getchar();
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glewExperimental = true;
if (glewInit() != GLEW_OK)
{
fprintf(stderr, "Blad GLEW.\n");
getchar();
glfwTerminate();
return -1;
}
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwPollEvents();
glfwSetCursorPos(window, 1024 / 2, 768 / 2);
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_CULL_FACE);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
GLuint programID = LoadShaders("TransformVertexShader.vertexshader", "TextureFragmentShader.fragmentshader");
GLuint MatrixID = glGetUniformLocation(programID, "MVP");
GLuint Texture = loadBMP_custom("skull-xray.bmp");
GLuint TextureID = glGetUniformLocation(programID, "myTextureSampler");
std::vector<glm::vec3> vertices;
std::vector<glm::vec2> uvs;
std::vector<glm::vec3> normals;
bool res = loadOBJ("czaszkazeby.obj", vertices, uvs, normals);
for (int i = 0; i < vertices.size(); i++)
{
verticescopy.push_back(vertices[i]);
}
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
unsigned int Texture2DTextureID = loadBMP_custom("skull1.bmp");
unsigned int Texture2DVertexBufferID;
unsigned int Texture2DUVBufferID;
unsigned int Texture2DShaderID = LoadShaders("TextVertexShader.vertexshader", "TextVertexShader.fragmentshader");
unsigned int Texture2DUniformID = glGetUniformLocation(Texture2DShaderID, "myTextureSampler");
glGenBuffers(1, &Texture2DVertexBufferID);
glGenBuffers(1, &Texture2DUVBufferID);
glfwSetKeyCallback(window, keyfunction);
do{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programID);
computeMatricesFromInputs();
glm::mat4 ProjectionMatrix = getProjectionMatrix();
glm::mat4 ViewMatrix = getViewMatrix();
glm::mat4 ModelMatrix = glm::mat4(1.0);
glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
GLuint uvbuffer;
glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, newUVs.size() * sizeof(glm::vec2), &newUVs[0], GL_DYNAMIC_DRAW);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
glUniform1i(TextureID, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
/* HUD drawing, not really important for the problem (I know this is bad, but this is not the main problem) */
std::vector<glm::vec2> verticesTexture;
std::vector<glm::vec2> UVsTexture;
glm::vec2 vertex_up_left = glm::vec2(0, 600);
glm::vec2 vertex_up_right = glm::vec2(800, 600);
glm::vec2 vertex_down_right = glm::vec2(800, 0);
glm::vec2 vertex_down_left = glm::vec2(0, 0);
verticesTexture.push_back(vertex_up_left);
verticesTexture.push_back(vertex_down_left);
verticesTexture.push_back(vertex_up_right);
verticesTexture.push_back(vertex_down_right);
verticesTexture.push_back(vertex_up_right);
verticesTexture.push_back(vertex_down_left);
glm::vec2 uv_up_left = glm::vec2(0, 1);
glm::vec2 uv_up_right = glm::vec2(1, 1);
glm::vec2 uv_down_right = glm::vec2(1, 0);
glm::vec2 uv_down_left = glm::vec2(0, 0);
UVsTexture.push_back(uv_up_left);
UVsTexture.push_back(uv_down_left);
UVsTexture.push_back(uv_up_right);
UVsTexture.push_back(uv_down_right);
UVsTexture.push_back(uv_up_right);
UVsTexture.push_back(uv_down_left);
glBindBuffer(GL_ARRAY_BUFFER, Texture2DVertexBufferID);
glBufferData(GL_ARRAY_BUFFER, verticesTexture.size() * sizeof(glm::vec2), &verticesTexture[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, Texture2DUVBufferID);
glBufferData(GL_ARRAY_BUFFER, UVsTexture.size() * sizeof(glm::vec2), &UVsTexture[0], GL_STATIC_DRAW);
glUseProgram(Texture2DShaderID);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, Texture2DTextureID);
glUniform1i(Texture2DUniformID, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, Texture2DVertexBufferID);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, Texture2DUVBufferID);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDrawArrays(GL_TRIANGLES, 0, verticesTexture.size());
/* End of HUD code */
glDisable(GL_BLEND);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glfwSwapBuffers(window);
glfwPollEvents();
}
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0);
glDeleteBuffers(1, &vertexbuffer);
glDeleteProgram(programID);
glDeleteTextures(1, &TextureID);
glDeleteVertexArrays(1, &VertexArrayID);
glfwTerminate();
return 0;
}
And the result
As you can think this isn't effect which I'm looking for. What I want is to put skull X-ray texture, which you can see on image, on front of skull model (just like people paint their faces for Halloween etc.)
I used gluProject to convert 3D coordinates to 2D coordinates (world to screen). When I get 2D coordiantes of point I just divide it by width or height of texture (depends on coordinates type) which gets me UV coordinate for this point. Is there some hole in my thinking which causes this strange looking texturing?
I used gluProject to convert 3D coordinates to 2D coordinates (world to screen). When I get 2D coordiantes of point I just divide it by width or height of texture (depends on coordinates type) which gets me UV coordinate for this point. Is there some hole in my thinking which causes this strange looking texturing?
Yes. Apparently you think your texture coordinates in some way depend on the orientation of your model and the way it's projected. That would mean if you'd move the "camera" around, that the texture coordinates would have to change. This is obviously wrong (obviously if one knows, how texture coordinates are supposed to work). BTW, in OpenGL the texture coordinates are denoted, S, T, R and Q, instead of UV.
A texture coordinate associates a vertex with a specific position within an image. This image-space position may be completely independent from where the vertex is in model-space; there may be a relationship for procedural texturing or reflection maps, but in general those are completely independent.
Normally texture coordinates are not generated, but manually defined by an artist when creating the 3D model and then stored as another piece to the model data.
What I want is to put skull X-ray texture, which you can see on image, on front of skull model (just like people paint their faces for Halloween etc.)
Say you really want to go the texture generation method, fair enough, then this would be a planar projection of the texture space into the model space. You have to know which orientation your skull is. For the sake of writing this, that the top of the head) is Y+, the left side is X+ and nasal goes Z+, then your X-ray image would project into the XY plane. Let's furthermore assume that your X-ray image is snugly cropped. Texture space is defined to fit the image into the range ]0,1[^n (where n is the dimension of the image). So that means that whatever the value range for X and Y components of the vertex positions is, this has to be mapped into the range ]0,1[ respectively.
This gives the following peudocode:
min_X = +inf
max_X = -inf
min_Y = +inf
max_Y = -inf
foreach vertex in model:
min_X = min(min_X, vertex.position.x)
min_Y = min(min_Y, vertex.position.y)
max_X = max(max_X, vertex.position.x)
max_Y = max(max_Y, vertex.position.y)
k_X = 1/(max_X - min_X)
k_Y = 1/(max_Y - min_Y)
foreach vertex in model:
vertex.texturecoordinate.s = (vertex.position.x - min_X) * k_X
vertex.texturecoordinate.t = (vertex.position.y - min_Y) * k_Y
I'm following the tutorials from: http://www.opengl-tutorial.org and trying a few things by my self.
At the moment my program can create triangles as class objects, transform their size and positions, and animate them (very simple code I just play around with). But when I'm trying to pass color value with Buffer Array to the Shaders, my triangles are not rendering.
I'll pass the relevant code here and try to make it understandble, hope someone can help me out here!
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <iomanip>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
using namespace glm;
#include "loadShader.h"
#include "model.h"
int _screenWidth = 1024;
int _screenHeight = 768;
int main()
{
//START GLFW
if (!glfwInit())
{
fprintf(stderr, "Failed to initialize GLFW\n");
return -1;
}
//GLFW SETTINGS
glfwWindowHint(GLFW_SAMPLES, 4); //4x antialiasing
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); //OPENGL 3.3
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); //Mac compatible?
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//open window
GLFWwindow* window;
window = glfwCreateWindow(_screenWidth, _screenHeight, "Tutorial 01", NULL, NULL);
if (window == NULL) {
fprintf(stderr, "Failed to open GLFW window. Make sure your GPU is openGL 3.3 compatible!\n");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
//INITIALIZE GLEW
glewExperimental = true; //needed in core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW.\n");
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
glClearColor(0.125f, 0.0f, 0.3725f, 0.0f);
//Enable Depth test
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Create and compile GLSL program from the shaders
GLuint programID = LoadShaders("Shaders/vertexShaders.vert", "Shaders/fragmentShaders.frag");
//get handle for MVP uniform
GLuint MatrixID = glGetUniformLocation(programID, "MVP");
/////////////////////
//MODEL//////////////
/////////////////////
//two triangles
int nVertices = 6;
//created through model class
model object1, object2;
object1.createTriangle();
object2.createTriangle();
//initialize buffer data arrays
GLfloat g_vertex_buffer_data[12*3];
// One color for each vertex
static const GLfloat g_color_buffer_data[] = {
0.583f, 0.771f, 0.014f,
0.609f, 0.115f, 0.436f,
0.327f, 0.483f, 0.844f,
0.822f, 0.569f, 0.201f,
0.435f, 0.602f, 0.223f,
0.310f, 0.747f, 0.185f };
//////////////////////////
//////////////////////////
//////////////////////////
//CREATE BUFFER
//This will identify our vertex and color buffer
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
GLuint colorbuffer;
glGenBuffers(1, &colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
//counters
float time = 0.0f;
int counter = 0;
int counterStep = 100;
do {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
time = time + 0.01;
counter = counter + 1;
//TRANSFORM MY TRIANGLES (its working)
glm::vec3 rotationAxis(0.0f, 0.0f, 1.0f);
glm::vec3 translation(0.0f, 0.0f, 0.025f);
float rotationAngle = 0.25f;
object1.rotate(rotationAngle, rotationAxis);
//object2.rotate(0.5*rotationAngle, rotationAxis);
object1.translate(translation);
//Update coordinates in vertex buffer (both triangles)
for (int i = 0; i < 3; i++)
{
g_vertex_buffer_data[i * 3] = object1.transformedPosition[i].x;
g_vertex_buffer_data[i * 3 + 1] = object1.transformedPosition[i].y;
g_vertex_buffer_data[i * 3 + 2] = object1.transformedPosition[i].z;
}
for (int i = 0; i < 3; i++)
{
g_vertex_buffer_data[i * 3 + 9] = object2.transformedPosition[i].x;
g_vertex_buffer_data[i * 3 + 10] = object2.transformedPosition[i].y;
g_vertex_buffer_data[i * 3 + 11] = object2.transformedPosition[i].z;
}
//Model matrix
glm::mat4 modelM = glm::mat4(1.0f);
//Projection matrix:
glm::mat4 projectionM = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
//Camera matrix:
glm::mat4 viewM = lookAt(
glm::vec3(8, 2, 2+10*time),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0));
//MODEL VIEW PROJECTION MATRIX:
glm::mat4 mvpM = projectionM * viewM * modelM;
//Give our vertices and colors to OpenGL
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW);
/////////////////////////////////////////////
//USE SHADERS
glUseProgram(programID);
//Send our transformation to the currently bound shader, MVP uniform
glUniformMatrix4fv(MatrixID, 1, 0, &mvpM[0][0]);
//1rst attribute buffer: vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, //attribute 0, no particular reason, but must match the layout in the shader
3, //size
GL_FLOAT, //type
GL_FALSE, //normalized?
0, //stride
(void*)0 //array buffer offset
);
//2nd attribute buffer: colors
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(
1, //attribute number
3, //size
GL_FLOAT, //type
GL_FALSE, //normalized?
0, //stride
(void*)0 //array buffer offset
);
//Draw the triangle
glDrawArrays(GL_TRIANGLES, 0, nVertices); //Starting from vertex 0; 3 vertices total
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
}
// Check if the ESC key was pressed or the window was closed
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0);
// Cleanup VBO
glDeleteBuffers(1, &vertexbuffer);
glDeleteBuffers(1, &colorbuffer);
glDeleteProgram(programID);
glDeleteVertexArrays(1, &VertexArrayID);
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}
Vertexshader:
#version 330 core
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec3 vertexColor;
uniform mat4 MVP;
out vec3 fragmentColor;
void main(){
gl_Position = MVP * vec4(vertexPosition_modelspace,1.0);
fragmentColor = vertexColor;
}
Fragmentshder:
#version 330 core
in vec3 fragmentColor;
out vec3 color;
void main(){
color = fragmentColor;
}
If I remove:
glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW);
and:
//2nd attribute buffer: colors
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(
1, //attribute number
3, //size
GL_FLOAT, //type
GL_FALSE, //normalized?
0, //stride
(void*)0 //array buffer offset
);
from the main function, the triangles renders.
EDIT
Here is only the relevant code which is where I think there is a problem:
//FIRST DO THIS: (but not sure why..)
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
//initialize buffer data arrays
GLfloat g_vertex_buffer_data[] = { something };
GLfloat g_color_buffer_data[] = { something };
//CREATE BUFFER
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
GLuint colorbuffer;
glGenBuffers(1, &colorbuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
//LOOP
do {
//UPDATE BUFFER DATA
GLfloat g_vertex_buffer_data[] = { something new };
GLfloat g_color_buffer_data[] = { something new };
//SEND NEW BUFFER DATA TO SHADERS
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW);
//USE SHADERS
glUseProgram(programID);
//1rst attribute buffer: vertices positions
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, //attribute 0, no particular reason, but must match the layout in the shader
3, //size
GL_FLOAT, //type
GL_FALSE, //normalized?
0, //stride
(void*)0 //array buffer offset
);
//2nd attribute buffer: colors
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(
1, //attribute number
3, //size
GL_FLOAT, //type
GL_FALSE, //normalized?
0, //stride
(void*)0 //array buffer offset
);
//Draw the triangles
glDrawArrays(GL_TRIANGLES, 0, nVertices); //Starting from vertex 0; 3 vertices total
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
}
// Check if the ESC key was pressed or the window was closed
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0);
// Cleanup VBO
glDeleteBuffers(1, &vertexbuffer);
glDeleteBuffers(1, &colorbuffer);
glDeleteProgram(programID);
glDeleteVertexArrays(1, &VertexArrayID);
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}
SOLUTION
I sort off solved my problem by looking at this tutorial https://www.opengl.org/wiki/Tutorial2%3a_VAOs,_VBOs,_Vertex_and_Fragment_Shaders_%28C_/_SDL%29 .
Basically I just moved the bufferBinding and bufferData functions outside the loop. Somehow that was ok before with the vertex positions, but not the vertex colors...
I read and learned more and changed some of the code and it's working now and I'm happy with it now:)
Before you bufferdata, you should bind the buffer that you want send data in.
it should be
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW);
Your code send did,not send any data to vertex position buffer.
Ps. for efficiency you should generate buffer, and submit the data before the loop.