Related
I am trying to calculate the Tangent and Bitangent vectors for my terrain. I followed this tutorial to figure out how to calculate these 2 vectors and from what I understand, Tangent Bitangent and Normal vectors should all be orthogonal to each other right? I am checking that and it seems like I am doing something wrong since they are not orthogonal. Can someone please explain to me what I am doing wrong here? Here is my code.
for (int i = 0; i < indices.size(); i += 3) {
glm::vec3 v0 = vertices.at(indices.at(i)).position;
glm::vec3 v1 = vertices.at(indices.at(i + 1)).position;
glm::vec3 v2 = vertices.at(indices.at(i + 2)).position;
std::cout << "v0 " << glm::to_string(v0) << std::endl;
std::cout << "v1 " << glm::to_string(v1) << std::endl;
std::cout << "v2 " << glm::to_string(v2) << std::endl;
glm::vec2 uv0 = vertices.at(indices.at(i)).texcoord;
glm::vec2 uv1 = vertices.at(indices.at(i + 1)).texcoord;
glm::vec2 uv2 = vertices.at(indices.at(i + 2)).texcoord;
std::cout << "uv0 " << glm::to_string(uv0) << std::endl;
std::cout << "uv1 " << glm::to_string(uv1) << std::endl;
std::cout << "uv2 " << glm::to_string(uv2) << std::endl;
glm::vec3 deltaPos1 = v1 - v0;
glm::vec3 deltaPos2 = v2 - v0;
std::cout << "e1 " << glm::to_string(deltaPos1) << std::endl;
std::cout << "e2 " << glm::to_string(deltaPos2) << std::endl;
glm::vec2 deltaUV1 = uv1 - uv0;
glm::vec2 deltaUV2 = uv2 - uv0;
std::cout << "deltaUV1 " << glm::to_string(deltaUV1) << std::endl;
std::cout << "deltaUV2 " << glm::to_string(deltaUV2) << std::endl;
GLfloat r = (GLfloat) (1.f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x));
std::cout << "r is: " << r << std::endl;
glm::vec3 tangent = glm::normalize((deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r);
glm::vec3 bitangent = glm::normalize((deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r);
std::cout << "normal 1 " << glm::to_string(vertices.at(indices.at(0)).normal) << std::endl;
std::cout << "normal 2 " << glm::to_string(vertices.at(indices.at(1)).normal) << std::endl;
std::cout << "normal 3 " << glm::to_string(vertices.at(indices.at(2)).normal) << std::endl;
std::cout << "tangent " << glm::to_string(tangent) << std::endl;
std::cout << "bitangent " << glm::to_string(bitangent) << std::endl;
glm::vec3 normal1 = vertices.at(indices.at(i)).normal;
glm::vec3 normal2 = vertices.at(indices.at(i + 1)).normal;
glm::vec3 normal3 = vertices.at(indices.at(i + 2)).normal;
for (int j = 0; j < 3; j++) {
glm::vec3 norm;
if (j == 0) {
norm = normal1;
} else if (j == 1) {
norm = normal2;
} else {
norm = normal3;
}
GLfloat tangentDot = glm::dot(norm, tangent);
GLfloat bitangentDot = glm::dot(norm, bitangent);
if (tangentDot != 0 || bitangentDot != 0) {
std::cerr << "ERROR::Terrain::Tangent or bitangent were not orthogonal" << std::endl;
std::cerr << tangentDot << " " << bitangentDot << std::endl;
}
}
vertices.at(indices.at(i)).tangents = tangent;
vertices.at(indices.at(i)).bitangents = bitangent;
vertices.at(indices.at(i + 1)).tangents = tangent;
vertices.at(indices.at(i + 1)).bitangents = bitangent;
vertices.at(indices.at(i + 2)).tangents = tangent;
vertices.at(indices.at(i + 2)).bitangents = bitangent;
}
And here are the debug outputs that I get for the first iteration as an example.
v0 vec3(0.000000, 0.078430, 0.000000)
v1 vec3(0.000000, 0.078430, 3.137255)
v2 vec3(3.137255, 0.078430, 0.000000)
uv0 vec2(0.000000, 0.000000)
uv1 vec2(0.000000, 0.003922)
uv2 vec2(0.003922, 0.000000)
e1 vec3(0.000000, 0.000000, 3.137255)
e2 vec3(3.137255, 0.000000, 0.000000)
deltaUV1 vec2(0.000000, 0.003922)
deltaUV2 vec2(0.003922, 0.000000)
r is: -65025
normal 1 vec3(-0.039155, 0.998466, -0.039155)
normal 2 vec3(-0.039185, 0.999232, 0.000000)
normal 3 vec3(0.000000, 0.999232, -0.039185)
tangent vec3(1.000000, -0.000000, -0.000000)
bitangent vec3(-0.000000, -0.000000, 1.000000)
ERROR::Terrain::Tangent or bitangent were not orthogonal
-0.0391549 -0.0391549
ERROR::Terrain::Tangent or bitangent were not orthogonal
-0.039185 0
ERROR::Terrain::Tangent or bitangent were not orthogonal
0 -0.039185
The dot product of Tangent and Normal is pretty small for the first iteration but it gets much bigger for some of them. Am I understanding the concept correctly? Do these 3 vectors have to be orthogonal? I checked the same dot product for vectors from imported meshes that I import with ASSIMP and they are all orthogonal.
-- Edit: Here is how I calculate my normals.
glm::vec3 Terrain::calculateNormal(int x, int z, unsigned char *textureData, int imageWidth, int imageHeight, int imageChannels) {
// TODO: Not optimal since we are calculating the same vertice height multiple times
// TODO: We also do the same calls above, maybe it will be smarter to just create a lookup table?
float heightL = getHeight(x - 1, z, textureData,imageWidth, imageHeight, imageChannels);
float heightR = getHeight(x + 1, z, textureData,imageWidth, imageHeight, imageChannels);
float heightD = getHeight(x, z - 1, textureData,imageWidth, imageHeight, imageChannels);
float heightU = getHeight(x, z + 1, textureData,imageWidth, imageHeight, imageChannels);
glm::vec3 normal = glm::vec3{heightL - heightR, 2.f, heightD - heightU};
normal = glm::normalize(normal);
return normal;
}
As pointed out in the comments, each of the vertices has it`s own normal and they may vary from one another. How would I handle the tangent and bitangent calculation in this case?
I'm writing a static function that uses GLM's rotate() function to rotate a vector about an arbitrary axis.
I wrote a simple test to check my work, and I found that the rotations occur in the opposite direction than what I expected.
I rotate a unit vector (0,0,1) about the X axis (1,0,0) in steps of pi/4. I expected that since OpenGL (and GLM?) use a right-handed coordinate system, the rotations would occur in a counter-clockwise direction about the X axis. Instead, they're occurring in clockwise direction.
vec3& RotateVector(vec3& targetVector, float const& radians, vec3 const &axis)
{
mat4 rotation = glm::rotate(mat4(1.0f), radians, axis);
targetVector = (vec4(targetVector, 0.0f) * rotation).xyz();
return targetVector;
}
vec3 test(0, 0, 1);
cout << "test initial vals: " << test.x << " " << test.y << " " << test.z << "\n";
RotateVector(test, 3.14f / 4.0f, vec3(1, 0, 0) );
cout << "Rotated test: " << test.x << " " << test.y << " " << test.z << "\n";
RotateVector(test, 3.14 /4.0f, vec3(1, 0, 0));
cout << "Rotated test: " << test.x << " " << test.y << " " << test.z << "\n";
RotateVector(test, 3.14 / 4.0f, vec3(1, 0, 0));
cout << "Rotated test: " << test.x << " " << test.y << " " << test.z << "\n";
RotateVector(test, 3.14 / 4.0f, vec3(1, 0, 0));
cout << "Rotated test: " << test.x << " " << test.y << " " << test.z << "\n";
When I run the code above, I get the following output:
test initial vals: 0 0 1
Rotated test: 0 0.706825 0.707388
Rotated test: 0 1 0.000796229
Rotated test: 0 0.707951 -0.706262
Rotated test: 0 0.00159246 -0.999999
The output shows that the rotation is moving clockwise about the X axis.
Why is that? I'd expect that OpenGL's right handed coordinate system would adhere to the right hand rule? Am I missing something, or am I just confused?
You're using the matrices transposed, and since rotation matrices are orthogonal matrices, this has the effect of using the inverse of those matrices: R^-1 = R^T.
glm mimics classic GL conventions with mat4 * vec4 multiplication order, where vec4 is a column vector.
When you write vec4 * mat4, vec4 is interpreted as row vector, and since (A*B)^T = B^T * A^T, you get the same result as transpose(mat4) * vec4.
I recently started learning tessellation and today I was trying to draw a triangle after tessellation so that I can see all the tessellated smaller triangles using glPolygonMode(GL_FRONT_AND_BACK, GL_LINE). But for some reason the output is just a coloured background without any triangle in it.
For the tessellation, I make a control shader and evaluation shader and then link them to the program.(Code below)
// Source code for Tesselation Control Shader
static const GLchar * tesselation_control_shader[] =
{
"#version 450 core \n"
" \n"
"layout(vertices = 3) out; \n"
" \n"
"void main(void) \n"
"{ \n"
" //Only if I am invocation 0 \n"
" if (gl_InvocationID == 0) \n"
" { \n"
" gl_TessLevelInner[0] = 5.0; \n"
" gl_TessLevelOuter[0] = 5.0; \n"
" gl_TessLevelOuter[1] = 5.0; \n"
" gl_TessLevelOuter[2] = 5.0; \n"
" } \n"
" \n"
" // Everybody copies their input to their input \n"
" gl_out[gl_InvocationID].gl_Position = \n"
" gl_in[gl_InvocationID].gl_Position; \n"
"} \n"
};
// Source code for tesselation evaluation shader
static const GLchar * tesselation_evaluation_shader[] =
{
"#version 450 core \n"
" \n"
"layout(triangles, equal_spacing, cw) in; \n"
" \n"
"void main(void) \n"
"{ \n"
" gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position + \n"
" gl_TessCoord.y * gl_in[1].gl_Position + \n"
" gl_TessCoord.z * gl_in[2].gl_Position); \n"
"} \n"
};
I then call the glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) in my render function right before draw the triangle using glDrawArrays(GL_TRIANGLE, 0, 3).
I initially thought that the glPolygonMode was defaulting to GL_FILL but I don't think that's the issue since I am just following a book (OpenGL Superbible 7th Edition).
How can I fix this?
Edit:
I have added the code of my entire program below:
GLuint compile_shaders(void)
{
GLuint vertex_shader;
GLuint fragment_shader;
GLuint control_shader;
GLuint evaluation_shader;
GLuint program;
// Source code for Vertex Shader
static const GLchar * vertex_shader_source[] =
{
"#version 450 core \n"
" \n"
"// offset and color are input vertex attribute \n"
"layout (location = 0) in vec4 offset; \n"
"layout (location = 1) in vec4 color; \n"
" \n"
"//Declare VS_OUT as an output interface block \n"
"out VS_OUT \n"
"{ \n"
" vec4 color; //Send color to next stage \n"
"}vs_out; \n"
" \n"
"void main(void) \n"
"{ \n"
" //Decalre a hardcoded array of positions \n"
" const vec4 vertices[3] = vec4[3](vec4(0.25, -0.25, 0.5, 1.0), \n"
" vec4(-0.25, -0.25, 0.5, 1.0), \n"
" vec4(0.25, 0.25, 0.5, 1.0)); \n"
" \n"
" //Index into our array using gl_VertexID \n"
" gl_Position = vertices[gl_VertexID] + offset; \n"
" \n"
"//color = vec4(1.0, 0.0, 0.0, 1.0); \n"
"//Output fixed value for vs_color \n"
"vs_out.color = color; \n"
"} \n"
};
// Source code for Fragment Shader
static const GLchar * fragment_shader_source[] =
{
"#version 450 core \n"
" \n"
"//Declare VS_OUT as an input interface block \n"
"in VS_OUT \n"
"{ \n"
" vec4 color; //Send color to next stage \n"
"}fs_in; \n"
" \n"
"//Ouput to the framebuffer \n"
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
"// Simply assign the color we were given by the vertex shader to our output \n"
" color = fs_in.color; \n"
"} \n"
};
// Source code for Tesselation Control Shader
static const GLchar * tesselation_control_shader[] =
{
"#version 450 core \n"
" \n"
"layout(vertices = 3) out; \n"
" \n"
"void main(void) \n"
"{ \n"
" //Only if I am invocation 0 \n"
" if (gl_InvocationID == 0) \n"
" { \n"
" gl_TessLevelInner[0] = 5.0; \n"
" gl_TessLevelOuter[0] = 5.0; \n"
" gl_TessLevelOuter[1] = 5.0; \n"
" gl_TessLevelOuter[2] = 5.0; \n"
" } \n"
" \n"
" // Everybody copies their input to their input \n"
" gl_out[gl_InvocationID].gl_Position = \n"
" gl_in[gl_InvocationID].gl_Position; \n"
"} \n"
};
// Source code for tesselation evaluation shader
static const GLchar * tesselation_evaluation_shader[] =
{
"#version 450 core \n"
" \n"
"layout(triangles, equal_spacing, cw) in; \n"
" \n"
"void main(void) \n"
"{ \n"
" gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position + \n"
" gl_TessCoord.y * gl_in[1].gl_Position + \n"
" gl_TessCoord.z * gl_in[2].gl_Position); \n"
"} \n"
};
// Create and compiler Vertex Shader
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
glCompileShader(vertex_shader);
// Create and compiler Fragment Shader
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
glCompileShader(fragment_shader);
// Create and compile tesselation control shader
control_shader = glCreateShader(GL_TESS_CONTROL_SHADER);
glShaderSource(control_shader, 1, tesselation_control_shader, NULL);
glCompileShader(control_shader);
// Create and compile tesselation evaluation shader
evaluation_shader = glCreateShader(GL_TESS_CONTROL_SHADER);
glShaderSource(evaluation_shader, 1, tesselation_control_shader, NULL);
glCompileShader(evaluation_shader);
// Create program, attach shaders to it, and link it
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glAttachShader(program, control_shader);
glAttachShader(program, evaluation_shader);
glLinkProgram(program);
// Delete shaders as program has them now
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
glDeleteShader(control_shader);
glDeleteShader(evaluation_shader);
return program;
};
class TesselationCSOne : public sb7::application
{
public:
void startup()
{
rendering_program = compile_shaders();
glCreateVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
}
void shutdown()
{
glDeleteVertexArrays(1, &vertex_array_object);
glDeleteProgram(rendering_program);
glDeleteVertexArrays(1, &vertex_array_object);
}
// Our rendering function
void render(double currentTime)
{
// Sets colour
static const GLfloat color[] = { (float)sin(currentTime) * 0.5f + 0.5f, (float)sin(currentTime) * 0.5f + 0.5f, 0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, color);
//Tell OpenGL to draw only the outlines of the resulting triangle
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// Use program object we created for rendering
glUseProgram(rendering_program);
GLfloat attrib[] = { 1.0, 0.0, 0.0, 0.0 };/*{ (float)sin(currentTime) * 0.5f, (float)sin(currentTime) * 0.6f, 0.0f, 0.0f };*/
// Update value of input attribute 0
glVertexAttrib4fv(0, attrib);
// Draw pathes for tesselation shaders
glPatchParameteri(GL_PATCH_VERTICES, 3);
// Draw one triangle
glDrawArrays(GL_PATCHES, 0, 3);
}
private:
GLuint rendering_program;
GLuint vertex_array_object;
};
// Only instance of DECLARE_MAIN to state entry point
DECLARE_MAIN(TesselationCSOne);
If you use a tessellation shader then you have to draw Patches. You have to set the size of the patches by glPatchParameteri( GL_PATCH_VERTICES, ...) and the primitive type has to be GL_PATCHES.
If the the number of vertices in a patch is 3, then you have to do it like this:
glPatchParameteri(GL_PATCH_VERTICES, 3);
glDrawArrays(GL_PATCHES, 0, 3)
See OpenGL 4.6 API Core Profile Specification; 10.1.15 Separate Patches; page 342:
Separate patches are specified with mode PATCHES. A patch is an ordered collection of vertices used for primitive tessellation (section 11.2). The vertices comprising a patch have no implied geometric ordering. The vertices of a patch are used by tessellation shaders and the fixed-function tessellator to generate new point, line, or triangle primitives.
void PatchParameteri( enum pname, int value );
with pname set to PATCH_VERTICES
Your shader program doesn't even link, because the fragment shader tries to read from an input interface block,
which is not declared as an output from the previous shader stage.
You have to pass the vertex attributes, through the tessellation control and evaluation shader to the fragment shader:
Tessellation control shader:
#version 450 core
layout(vertices = 3) out;
in VS_OUT
{
vec4 color;
} tesc_in[];
out TESC_OUT
{
vec4 color;
} tesc_out[];
void main(void)
{
if (gl_InvocationID == 0)
{
gl_TessLevelInner[0] = 5.0;
gl_TessLevelOuter[0] = 5.0;
gl_TessLevelOuter[1] = 5.0;
gl_TessLevelOuter[2] = 5.0;
}
tesc_out[gl_InvocationID].color = tesc_in[gl_InvocationID].color;
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
Tessellation evaluation shader:
#version 450 core
layout(triangles, equal_spacing, cw) in;
in TESC_OUT
{
vec4 color;
} tese_in[];
out TESE_OUT
{
vec4 color;
} tese_out;
void main(void)
{
tese_out.color = ( gl_TessCoord.x * tese_in[0].color +
gl_TessCoord.y * tese_in[1].color +
gl_TessCoord.z * tese_in[2].color ) / 3.0;
gl_Position = ( gl_TessCoord.x * gl_in[0].gl_Position +
gl_TessCoord.y * gl_in[1].gl_Position +
gl_TessCoord.z * gl_in[2].gl_Position ) / 3.0;
}
Fragment shader:
#version 450 core
in TESE_OUT
{
vec4 color;
} fs_in;
out vec4 color;
void main(void)
{
color = fs_in.color;
}
Further, I recommend to check if a shader object was successfully compiled:
GLuint shaderObj = .... ;
glCompileShader( shaderObj );
GLint status = GL_TRUE;
glGetShaderiv( shaderObj, GL_COMPILE_STATUS, &status );
if ( status == GL_FALSE )
{
GLint logLen;
glGetShaderiv( shaderObj, GL_INFO_LOG_LENGTH, &logLen );
std::vector< char >log( logLen );
GLsizei written;
glGetShaderInfoLog( shaderObj, logLen, &written, log.data() );
std::cout << "compile error:" << std::endl << log.data() << std::endl;
}
and a shader program object was successfully linked:
GLuint progObj = ....;
glLinkProgram( progObj );
GLint status = GL_TRUE;
glGetProgramiv( progObj, GL_LINK_STATUS, &status );
if ( status == GL_FALSE )
{
GLint logLen;
glGetProgramiv( progObj, GL_INFO_LOG_LENGTH, &logLen );
std::vector< char >log( logLen );
GLsizei written;
glGetProgramInfoLog( progObj, logLen, &written, log.data() );
std::cout << "link error:" << std::endl << log.data() << std::endl;
}
By the way, read about Raw string literals, which simplify the declaration of the shader source code strings:
e.g.
std::string fragment_shader_source = R"(
#version 450 core
in TESE_OUT
{
vec4 color;
} fs_in;
out vec4 color;
void main(void)
{
color = fs_in.color;
}
)";
Further note, the the offset probably moves the the triangle out of the viewport. Either change the value of the offset in the attribute initialization:
GLfloat attrib[] = { 0.0, 0.0, 0.0, 0.0 };
or get rid of the offest in the vertex shader for debug reasons
gl_Position = vertices[gl_VertexID];
You have to ensure that the color attribute is set too:
GLfloat attrib1[] = { 1.0, 1.0, 0.0, 1.0 };
glVertexAttrib4fv(1, attrib1);
The result may look like this:
So after checking a lot of sources and the Superbible's code repository I realized I have a lot of unnecessary code (For example, the interface blocks in the shaders) and even quite a few mistakes (For example I had two program varibles).
But, after fixing all that the code that produces the required output (A tessellated triangle) is:
/**
Program to draw a triangle with tesselation.
**/
#include <sb7.h>
class TesselatedTriangle : public sb7::application
{
void init()
{
static const char title[] = "Tessellated Triangle";
sb7::application::init();
memcpy(info.title, title, sizeof(title));
}
virtual void startup()
{
static const char * vertex_shader_source[] =
{
"#version 450 core \n"
" \n"
"void main(void) \n"
"{ \n"
" const vec4 vertices[] = vec4[](vec4( 0.25, -0.25, 0.5, 1.0), \n"
" vec4(-0.25, -0.25, 0.5, 1.0), \n"
" vec4( 0.25, 0.25, 0.5, 1.0)); \n"
" \n"
" gl_Position = vertices[gl_VertexID]; \n"
"} \n"
};
static const char * tesselation_control_shader_source[] =
{
"#version 450 core \n"
" \n"
"layout (vertices = 3) out; \n"
" \n"
"void main(void) \n"
"{ \n"
" if (gl_InvocationID == 0) \n"
" { \n"
" gl_TessLevelInner[0] = 5.0; \n"
" gl_TessLevelOuter[0] = 5.0; \n"
" gl_TessLevelOuter[1] = 5.0; \n"
" gl_TessLevelOuter[2] = 5.0; \n"
" } \n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; \n"
"} \n"
};
static const char * tesselation_evaluation_shader_source[] =
{
"#version 450 core \n"
" \n"
"layout (triangles, equal_spacing, cw) in; \n"
" \n"
"void main(void) \n"
"{ \n"
" gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) + \n"
" (gl_TessCoord.y * gl_in[1].gl_Position) + \n"
" (gl_TessCoord.z * gl_in[2].gl_Position); \n"
"} \n"
};
static const char * fragment_shader_source[] =
{
"#version 450 core \n"
" \n"
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
" color = vec4(0.0, 0.8, 1.0, 1.0); \n"
"} \n"
};
rendering_program = glCreateProgram();
// Compile shaders
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, vertex_shader_source, NULL);
glCompileShader(vs);
GLuint tcs = glCreateShader(GL_TESS_CONTROL_SHADER);
glShaderSource(tcs, 1, tesselation_control_shader_source, NULL);
glCompileShader(tcs);
GLuint tes = glCreateShader(GL_TESS_EVALUATION_SHADER);
glShaderSource(tes, 1, tesselation_evaluation_shader_source, NULL);
glCompileShader(tes);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, fragment_shader_source, NULL);
glCompileShader(fs);
// Attach shaders to the program
glAttachShader(rendering_program, vs);
glAttachShader(rendering_program, tcs);
glAttachShader(rendering_program, tes);
glAttachShader(rendering_program, fs);
// Link the program
glLinkProgram(rendering_program);
// Generate vertex arrays
glGenVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
// Declare the drawing mode for the polygons
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
virtual void render(double currentTime)
{
static const GLfloat green[] = { 0.0f, 0.25f, 0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, green);
glUseProgram(rendering_program);
glDrawArrays(GL_PATCHES, 0, 3);
}
virtual void shutdown()
{
glDeleteVertexArrays(1, &vertex_array_object);
glDeleteProgram(rendering_program);
}
private:
GLuint rendering_program;
GLuint vertex_array_object;
};
// One and only instance of DECLARE_MAIN
DECLARE_MAIN(TesselatedTriangle)
Hopefully this helps somebody else with the same problem.
This was my vertex shader before it was corrupt:
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 m;
uniform mat4 v;
uniform mat4 p;
out vec2 texPos;
void main() {
gl_Position = p * v * m * vec4(aPos, 1.0);
texPos = vec2(0, 0);
}
And this is my vertex shader after it was corrupt:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexPos;
uniform mat4 m;
uniform mat4 v;
uniform mat4 p;
out vec2 texPos;
void main() {
gl_Position = p * v * m * vec4(aPos, 1.0);
texPos = vec2(0, 0);
}
The difference between them is just a layout (location = 1) in vec2 aTexPos. How and why did this 'corruption' happen?
EDIT: here's the loadProgram function that is used to load the shaders:
GLuint Framework::loadProgram(string vpath, string fpath) {
GLuint v, f;
stringstream ss;
char log[512];
v = glCreateShader(GL_VERTEX_SHADER);
fstream vf(vpath);
if (vf.good()) {
ss << vf.rdbuf();
const GLchar* g = ss.str().c_str();
glShaderSource(v, 1, &g, nullptr);
glCompileShader(v);
glGetShaderInfoLog(v, 512, nullptr, log);
cout << "Vertex Shader: " << log << endl;
} else {
cout << "Bad path " << vpath.c_str() << endl;
return static_cast<GLuint>(-1);
}
ss.str("");
f = glCreateShader(GL_FRAGMENT_SHADER);
fstream ff(fpath);
if (ff.good()) {
ss << ff.rdbuf();
const GLchar* g = ss.str().c_str();
glShaderSource(f, 1, &g, nullptr);
glCompileShader(f);
glGetShaderInfoLog(f, 512, nullptr, log);
cout << "Fragment Shader: " << log << endl;
} else {
cout << "Bad path " << fpath.c_str() << endl;
return static_cast<GLuint>(-1);
}
GLuint prog;
prog = glCreateProgram();
glAttachShader(prog, v);
glAttachShader(prog, f);
glLinkProgram(prog);
glGetProgramInfoLog(prog, 512, nullptr, log);
cout << "Program: " << log;
glDeleteShader(v);
glDeleteShader(f);
return prog;
}
It just says it's corrupted... And I have no idea where it had gone wrong.
Here's what I got when I run the program:
Vertex Shader:
Fragment Shader:
Program: ERROR: Compiled vertexshader was corrupt.
Problem solved.
It's the problem of the loadProgram function, that vertex shader's ss.str().c_str() return a single '\0' character. I have no idea why fragment shader's string stream works well, though.
So here's the code now:
GLuint Framework::loadProgram(string vpath, string fpath) {
GLuint v, f;
stringstream ss;
char log[512];
v = glCreateShader(GL_VERTEX_SHADER);
fstream vf(vpath);
if (vf.good()) {
ss << vf.rdbuf();
string str = ss.str();
const GLchar* g = str.c_str();
glShaderSource(v, 1, &g, nullptr);
glCompileShader(v);
glGetShaderInfoLog(v, 512, nullptr, log);
cout << "Vertex Shader: " << log << endl;
} else {
cout << "Bad path " << vpath.c_str() << endl;
return static_cast<GLuint>(-1);
}
ss.str("");
f = glCreateShader(GL_FRAGMENT_SHADER);
fstream ff(fpath);
if (ff.good()) {
ss << ff.rdbuf();
string str = ss.str();
const GLchar* g = str.c_str();
glShaderSource(f, 1, &g, nullptr);
glCompileShader(f);
glGetShaderInfoLog(f, 512, nullptr, log);
cout << "Fragment Shader: " << log << endl;
} else {
cout << "Bad path " << fpath.c_str() << endl;
return static_cast<GLuint>(-1);
}
GLuint prog;
prog = glCreateProgram();
glAttachShader(prog, v);
glAttachShader(prog, f);
glLinkProgram(prog);
glGetProgramInfoLog(prog, 512, nullptr, log);
cout << "Program: " << log;
glDeleteShader(v);
glDeleteShader(f);
return prog;
}
I have the following function code:
D3DXVECTOR3 Mouse::GetClickDirection(D3DXMATRIX projMatrix, D3DXMATRIX viewMatrix, D3DXVECTOR3 cameraPosition)
{
POINT mousePoint;
GetCursorPos(&mousePoint);
ScreenToClient(hwnd, &mousePoint);
float x = ((mousePoint.x * 2.0f) / (float)backBufferWidth) - 1.0f;
float y = ((mousePoint.y * -2.0f) / (float)backBufferHeight) + 1.0f;
D3DXVECTOR3 mouseClip = D3DXVECTOR3(x, y, 1.0f);
D3DXMATRIX invViewMatrix;
D3DXMatrixInverse(&invViewMatrix, 0, &viewMatrix);
D3DXMATRIX invProjMatrix;
D3DXMatrixInverse(&invProjMatrix, 0, &projMatrix);
D3DXMATRIX inversedMatrix = invViewMatrix * invProjMatrix;
D3DXVECTOR3 mouseWorldSpace;
D3DXVec3TransformCoord(&mouseWorldSpace, &mouseClip, &inversedMatrix);
D3DXVECTOR3 direction = mouseWorldSpace - cameraPosition;
D3DXVec3Normalize(&direction, &direction);
system("CLS");
std::cout << "sX: " << x << std::endl;
std::cout << "sY: " << y << std::endl;
std::cout << "X: " << direction.x << std::endl;
std::cout << "Y: " << direction.y << std::endl;
std::cout << "Z: " << direction.z << std::endl;
return direction;
}
I'm trying to calculate and create a directional ray based on the x and y screen point that the user has clicked on in my DirectX 3D app. So far, the printed results seems to indicate that my calculations are wrong as the Z value is always around 0.9 and I have no idea why. What exactly am I doing wrong here? Please help. Thanks
I think your inverse matrix calculation is backwards.
D3DXMATRIX inversedMatrix = invProjMatrix * invViewMatrix;