我一直在研究来自open.gl的转换教程,并且无法使我的透视投影矩阵工作。本教程使用了GLM,但我选择使用自己的矩阵数学函数来尝试更好地学习数学。一切都编译得很好(gcc-Wall),我的旋转和外观矩阵函数工作得很好,但我的透视投影矩阵导致黑屏没有OpenGL错误。
投影矩阵(我认为)应该是
/ cot(fovy/2)/aspect 0.0 0.0 0.0 \
| 0.0 cot(fovy/2) 0.0 0.0 |
| 0.0 0.0 (zfar + znear)/(znear - zfar) -1.0 |
\ 0.0 0.0 (2 * zfar * znear)/(znear - zfar) 0.0 /
有趣的是,我可以用矩阵
提供预期的效果/ cot(fovy/2)/aspect 0.0 0.0 0.0 \
| 0.0 cot(fovy/2) 0.0 0.0 |
| 0.0 0.0 (zfar + znear)/(znear - zfar) -1.0 |
\ 0.0 0.0 0.4 1.0 /
Here are the necessary source files.您需要GLFW3和SOIL来编译代码 - 我一直在使用gcc -Wall -Werror -std=c99 -lGL -lGLEW -lglfw -lm -lSOIL transform.c -o transform
。我已经尝试在下面提供更短(非编译)的源代码,以防有任何明显的错误。
transform.c:
#include <math.h>
#define M_PI (3.14159265358979323846)
#include <stdio.h>
#include <stdlib.h>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <SOIL/SOIL.h>
typedef struct mat4_t {
float arr[16];
} mat4_t;
typedef struct vec3_t {
float arr[3];
} vec3_t;
/* forward declarations... */
/* return a 4x4 'lookat' matrix to be multiplied by model space coords */
mat4_t mat4mklook(const vec3_t eye, const vec3_t center, const vec3_t up) {
/* check out the OpenGL gluLookAt documentation for an explanation */
vec3_t f = vec3norm(vec3sub(center, eye));
vec3_t up_ = vec3norm(up);
vec3_t s = vec3cross(f, up_);
vec3_t u = vec3cross(s, f);
return (mat4_t) { {
s.arr[0], s.arr[1], s.arr[2], 0.0f,
u.arr[0], u.arr[1], u.arr[2], 0.0f,
-f.arr[0], -f.arr[1], -f.arr[2], 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
} };
}
/* return a 4x4 persp. projection matrix to be multiplied by camera coords */
mat4_t mat4mkproj(const float fovy, const float aspect, const float znear, const float zfar) {
float f = 1 / tan(fovy / 2.0f);
return (mat4_t){ {
f/aspect, 0.0f, 0.0f, 0.0f,
0.0f, f, 0.0f, 0.0f,
0.0f, 0.0f, (zfar+znear)/(znear-zfar), (2*zfar*znear)/(znear-zfar),
0.0f, 0.0f, -1.0f, 0.0f
} };
}
/* returns a 4x4 rotation matrix of magnitude 'th' about unit vector 'axis' */
mat4_t mat4mkrot(const vec3_t axis, const float th) {
const float uX = axis.arr[0];
const float uY = axis.arr[1];
const float uZ = axis.arr[2];
const float sinth = sin(th);
const float costh = cos(th);
return (mat4_t) { {
costh+pow(uX,2)*(1-costh), uX*uY*(1-costh)-uZ*sinth, uX*uZ*(1-costh)+uY*sinth, 0.0,
uY*uX*(1-costh)+uZ*sinth, costh+pow(uY,2)*(1-costh), uY*uZ*(1-costh)-uX*sinth, 0.0,
uZ*uX*(1-costh)-uY*sinth, uZ*uY*(1-costh)+uX*sinth, costh+pow(uZ,2)*(1-costh), 0.0,
0.0, 0.0, 0.0, 1.0
} };
}
/* returns the product of matrices 'a' and 'b' */
mat4_t mat4mult(const mat4_t a, const mat4_t b) {
mat4_t result;
for(int i = 0; i < 16; ++i) {
result.arr[i] = 0.0f;
for(int j = 0; j < 4; ++j) {
result.arr[i] += a.arr[i / 4 + j] * b.arr[i % 4 + j * 4];
}
}
return result;
}
/* returns the cross product of vectors 'a' and 'b' */
vec3_t vec3cross(const vec3_t a, const vec3_t b) {
return (vec3_t){ {
a.arr[1] * b.arr[2] - a.arr[2] * b.arr[1],
a.arr[2] * b.arr[0] - a.arr[0] * b.arr[2],
a.arr[0] * b.arr[1] - a.arr[1] * b.arr[0]
} };
}
/* returns a unit vector derived from vector 'v' */
vec3_t vec3norm(const vec3_t a) {
vec3_t result;
float mag;
if((mag = sqrt(pow(a.arr[0], 2) + pow(a.arr[1], 2) + pow(a.arr[2], 2))) == 0.0f) {
result = (vec3_t) {{0}};
} else {
for(int i = 0; i < 3; ++i) {
result.arr[i] = a.arr[i] / mag;
}
}
return result;
}
/* return the vector difference 'a' - 'b' */
vec3_t vec3sub(const vec3_t a, const vec3_t b) {
vec3_t result;
for(int i = 0; i < 3; ++i) {
result.arr[i] = a.arr[i] - b.arr[i];
}
return result;
}
/* returns the dot product of vectors 'a' and 'b' */
float vec3dot(const vec3_t a, const vec3_t b) {
return a.arr[0] * b.arr[0] +
a.arr[1] * b.arr[1] +
a.arr[2] * b.arr[2];
}
GLfloat vertices[] = {
/* position texture */
-0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, 0.0f, 1.0f
};
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
int main() {
glfwInit();
/* context settings */
/* window & context creation */
GLFWwindow * const window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);
glfwMakeContextCurrent(window);
/* glew initialization -- generates harmless error */
glewExperimental = GL_TRUE;
glewInit();
glGetError();
/* vertex setup */
/* shader setup */
/* vertex attribute setup */
/* texture setup */
GLint modeluni;
{ /* matrix uniform setup */
modeluni = glGetUniformLocation(shaderProgram, "model");
mat4_t viewmat = mat4mklook((vec3_t){{1.2f, 1.2f, 1.2f}}, (vec3_t){{0.0f, 0.0f, 0.0f}}, (vec3_t){{0.0f, 0.0f, 1.0f}});
GLint viewuni = glGetUniformLocation(shaderProgram, "view");
glUniformMatrix4fv(viewuni, 1, GL_TRUE, viewmat.arr);
mat4_t projmat = mat4mkproj(M_PI / 4.0f, 800.0f / 600.0f, 1.0f, 10.0f);
GLint projuni = glGetUniformLocation(shaderProgram, "proj");
glUniformMatrix4fv(projuni, 1, GL_TRUE, projmat.arr);
}
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
while(!glfwWindowShouldClose(window)) {
const GLuint error = glGetError();
if(error) {
fprintf(stderr, "%d\n", error);
}
glClear(GL_COLOR_BUFFER_BIT);
mat4_t modmat = mat4mkrot((vec3_t){{0.0f, 0.0f, 1.0f}}, (glfwGetTime() / 2.0) * M_PI);
glUniformMatrix4fv(modeluni, 1, GL_TRUE, modmat.arr);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
/* delete opengl ids */
glfwTerminate();
return 0;
}
vert.glsl:
#version 330
in vec2 position;
in vec3 color;
in vec2 texcoord;
out vec3 Color;
out vec2 Texcoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 proj;
void main() {
Color = color;
Texcoord = texcoord;
gl_Position = proj * view * model * vec4(position.x, position.y, 0.0, 1.0);
}
frag.glsl:
#version 330
in vec3 Color;
in vec2 Texcoord;
out vec4 outColor;
uniform sampler2D texKitten;
uniform sampler2D texPuppy;
void main() {
vec4 colKitten = texture(texKitten, Texcoord);
vec4 colPuppy = texture(texPuppy, Texcoord);
outColor = mix(colKitten, colPuppy, 0.5);
}