我正在尝试了解使用矩阵的opengl中的相机。
我写了一个看起来像这样的简单着色器:
#version 330 core
layout (location = 0) in vec3 a_pos;
layout (location = 1) in vec4 a_col;
uniform mat4 u_mvp_mat;
uniform mat4 u_mod_mat;
uniform mat4 u_view_mat;
uniform mat4 u_proj_mat;
out vec4 f_color;
void main()
{
vec4 v = u_mvp_mat * vec4(0.0, 0.0, 1.0, 1.0);
gl_Position = u_mvp_mat * vec4(a_pos, 1.0);
//gl_Position = u_proj_mat * u_view_mat * u_mod_mat * vec4(a_pos, 1.0);
f_color = a_col;
}
这有点冗长,但那是因为我正在测试传递模型,视图或投影矩阵并在gpu上进行乘法或在cpu上进行乘法并传入mvp矩阵然后只是执行mvp *位置矩阵乘法。
据我所知,后者可以提供性能提升但是绘制1个四分之一我现在还没有看到任何性能问题。
现在我使用此代码从我的着色器获取位置并创建模型视图和投影矩阵。
pos_loc = get_attrib_location(ce_get_default_shader(), "a_pos");
col_loc = get_attrib_location(ce_get_default_shader(), "a_col");
mvp_matrix_loc = get_uniform_location(ce_get_default_shader(), "u_mvp_mat");
model_mat_loc = get_uniform_location(ce_get_default_shader(), "u_mod_mat");
view_mat_loc = get_uniform_location(ce_get_default_shader(), "u_view_mat");
proj_matrix_loc =
get_uniform_location(ce_get_default_shader(), "u_proj_mat");
float h_w = (float)ce_get_width() * 0.5f; //width = 320
float h_h = (float)ce_get_height() * 0.5f; //height = 480
model_mat = mat4_identity();
view_mat = mat4_identity();
proj_mat = mat4_identity();
point3* eye = point3_new(0, 0, 0);
point3* center = point3_new(0, 0, -1);
vec3* up = vec3_new(0, 1, 0);
mat4_look_at(view_mat, eye, center, up);
mat4_translate(view_mat, h_w, h_h, -20);
mat4_ortho(proj_mat, 0, ce_get_width(), 0, ce_get_height(), 1, 100);
mat4_scale(model_mat, 30, 30, 1);
mvp_mat = mat4_identity();
在此之后我设置了我的vao和vbo,然后准备好渲染。
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(ce_get_default_shader()->shader_program);
glBindVertexArray(vao);
mvp_mat = mat4_multi(mvp_mat, view_mat, model_mat);
mvp_mat = mat4_multi(mvp_mat, proj_mat, mvp_mat);
glUniformMatrix4fv(mvp_matrix_loc, 1, GL_FALSE, mat4_get_data(mvp_mat));
glUniformMatrix4fv(model_mat_loc, 1, GL_FALSE, mat4_get_data(model_mat));
glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, mat4_get_data(view_mat));
glUniformMatrix4fv(proj_matrix_loc, 1, GL_FALSE, mat4_get_data(proj_mat));
glDrawElements(GL_TRIANGLES, quad->vertex_count, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
假设所有矩阵数学都是正确的,我想将视图和投影矩阵抽象到相机结构中,并将模型矩阵抽象为精灵结构,以便我可以避免所有这些矩阵数学并使事情变得更容易使用
矩阵乘法顺序为:
Projection * View * Model * Vector
所以当精灵保持模型矩阵时,相机会保持投影和视图矩阵。
在将数据发送到gpu进行矩阵乘法之前,请完成所有相机变换和精灵变换。
如果我没记错,矩阵乘法不是可交换的
view * projection * model
会导致错误的结果矩阵。
伪代码
glClearxxx(....);
glUseProgram(..);
glBindVertexArray(..);
mvp_mat = mat4_identity();
proj_mat = camera_get_proj_mat();
view_mat = camera_get_view_mat();
mod_mat = sprite_get_transform_mat();
mat4_multi(mvp_mat, view_mat, mod_mat); //mvp holds model * view
mat4_multi(mvp_mat, proj_mat, mvp_mat); //mvp holds proj * model * view
glUniformMatrix4fv(mvp_mat, 1, GL_FALSE, mat4_get_data(mvp_mat));
glDrawElements(...);
glBindVertexArray(0);
这是一种高效的可扩展方式吗?
答案 0 :(得分:2)
这是一种高效的可扩展方式吗?
是的,除非你有一个非常奇特的用例,这种用例与标准非常不同。
您通常应该担心的最后一件事是关于从相机中检索模型视图和投影矩阵的性能。
这是因为这些矩阵通常每个视口每帧只需要获取一次。扫描线光栅化基元和从相机中拉出矩阵只需一个简单的恒定时间操作,就可以在帧中进行数百万次迭代。
所以通常你想让它像你想的那样方便。在我的例子中,我一直在中央SDK中通过函数指针的抽象接口,然后函数计算 proj / mv / ti_mv矩阵在用户定义的范围内与相机相关的属性。尽管如此,它从未表现为一个热点 - 它甚至根本没有出现在探查器中。
需要担心的事情要贵得多。可伸缩性意味着规模 - 从相机中检索矩阵的复杂性无法扩展。要渲染的三角形或四边形或线条或其他图元的数量可以缩放,在frag着色器中处理的碎片数量可以缩放。除了视口数量之外,相机通常不会缩放,任何人都不应该使用百万个视口。
答案 1 :(得分:2)
我没有检查过这一点,但一般看起来不错,你正在做什么。
我想将视图和投影矩阵抽象为相机结构
这是一个最合适的想法;如果没有这样的抽象,我很难想象一个严肃的GL应用程序
这是一种高效的可扩展方式吗?
可扩展性的一般限制是
漫反射和高光BRDFs(也需要,btw,光均匀,普通属性和普通矩阵的计算if the scaling of the model is non-uniform),需要per-pixel illumination才能进行质量渲染
与多个灯光相同(例如太阳和近距离聚光灯)
阴影贴图!阴影贴图? (每个光源一个?)
透明度
反射(镜子,玻璃,水)
纹理
正如你可以从列表中看到的那样,只有MVP制服和顶点坐标属性,你才能走得很远。
但到目前为止,制服的数量并不是最关键的表现 - 看到你的代码我肯定你不会不必要地重新编译你的着色器,只在需要时更新你的制服,使用{{3}等等..
问题是插入这些制服和维管组织的数据。或者不是。
考虑人形网格" Alice"晚上(不止一个相关的光源)穿过一个喷泉,在城市广场上(有水会有涟漪)穿过(那是一个网格变形+翻译)。
允许'考虑一下我们在CPU上只收集所有这些,而且只有插件准备好将数据渲染到着色器中:
(事实上后者是如此困难,你很难看到任何中途逼真的实时长开发动画,但令人惊讶的是(不,不是真的)许多马尾和短发削减)
我们还没有谈到爱丽丝的服装;让我们只希望她穿着T恤和牛仔裤(不是宽衬衫和裙子,这需要褶皱和碰撞计算)。
正如您可能已经猜到老派的方法并没有把我们带走,因此,在CPU和GPU操作之间找到了适合的方法。
此外,应该考虑在早期阶段进行计算的并行化。将数据尽可能平坦地放在合理的块中是有利的,因此只需将指针和大小放入gl-call中即可将数据告知,无需任何复制,重新安排,循环或进一步的ado。
这是我今天关于GL性能和可扩展性的2美分智慧。