Reputation: 43
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?
Upvotes: 2
Views: 5017
Reputation: 162164
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
Upvotes: 5