4. 顶点着色器-mvp转换
目录概述
-
属性:用顶点数组提供的逐顶点数据(顶点位置、颜色、纹理)
-
统一变量和统一变量缓冲区:顶点着色器使用的不变数据(mvp变换矩阵)
-
采样器:代表顶点着色器使用的纹理的特殊统一变量类型
-
着色器程序:顶点着色器程序源代码或者描述在操作顶点的可执行文件
设置统一变量的流程
// 1. 在着色器程序中声明uniform变量
const char vShaderStr[] =
"#version 300 es \n"
"uniform mat4 u_mvpMatrix; \n" // 声明统一变量,u_mvpMatrix
"layout(location = 0) in vec4 a_position; \n"
"layout(location = 1) in vec4 a_color; \n"
"out vec4 v_color; \n"
"void main() \n"
"{ \n"
" v_color = a_color; \n"
" gl_Position = u_mvpMatrix * a_position; \n" // 进行mvp转换
"} \n";
2. 获取uniform变量的引用
userData->mvpLoc = glGetUniformLocation(userData->programObject, "u_mvpMatrix"); // 获取u_mvpMatrix统一变量的引用
3. 给uniform变量赋值
glUniformMatrix4fv(userData->mvpLoc, 1, GL_FALSE, (GLfloat *)&userData->mvpMatrix.m[0][0]); // 给u_mvpMatrix统一变量赋值
平移矩阵-行优先还是列优先
void myesTranslate ( ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz )
{
result->m[3][0] += ( result->m[0][0] * tx + result->m[1][0] * ty + result->m[2][0] * tz );
result->m[3][1] += ( result->m[0][1] * tx + result->m[1][1] * ty + result->m[2][1] * tz );
result->m[3][2] += ( result->m[0][2] * tx + result->m[1][2] * ty + result->m[2][2] * tz );
result->m[3][3] += ( result->m[0][3] * tx + result->m[1][3] * ty + result->m[2][3] * tz );
}
书上求得的平移矩阵的样子:
1, 0, 0, transX
0, 1, 0, transY
0, 0, 1, transZ
0, 0, 0, 1
opengl中平移矩阵的样子:
1, 0, 0, 0
0, 1, 0, 0
0, 0, 1, 0
transX, transY, transZ, 1
解释:
出于编程目的,OpenGL矩阵是16值数组,基本向量在内存中连续放置。转换分量占据16元素矩阵的第13、14和15个元素,其中索引的编号从1到16,如OpenGL 2.1规范的2.11.2节所述。
也就说,opengl规定平移矩阵在内存中,应该是这样子的:
{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 }
所以:就是opengl的一个规定而已,和是否行列无关
源码解析
#include <stdlib.h>
#include "esUtil.h"
typedef struct
{
GLuint programObject;
GLint mvpLoc;
GLfloat *vertices;
GLuint *indices;
int numIndices;
GLfloat angle;
ESMatrix mvpMatrix;
} myUserData;
int Init(MYESContext *myesContext)
{
myUserData *userData = (myUserData *)myesContext->userData;
const char vShaderStr[] =
"#version 300 es \n"
"uniform mat4 u_mvpMatrix; \n" // 声明统一变量,u_mvpMatrix
"layout(location = 0) in vec4 a_position; \n"
"layout(location = 1) in vec4 a_color; \n"
"out vec4 v_color; \n"
"void main() \n"
"{ \n"
" v_color = a_color; \n"
" gl_Position = u_mvpMatrix * a_position; \n" // 进行mvp转换
"} \n";
const char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"in vec4 v_color; \n"
"layout(location = 0) out vec4 outColor; \n"
"void main() \n"
"{ \n"
" outColor = v_color; \n"
"} \n";
userData->programObject = myesLoadProgram(vShaderStr, fShaderStr);
userData->mvpLoc = glGetUniformLocation(userData->programObject, "u_mvpMatrix"); // 获取u_mvpMatrix统一变量的引用
userData->numIndices = myesGenCube(1.0, &userData->vertices, NULL, NULL, &userData->indices);
userData->angle = 45.0f;
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
return GL_TRUE;
}
void Update(MYESContext *myesContext, float deltaTime)
{
myUserData *userData = (myUserData *)myesContext->userData;
ESMatrix perspective;
ESMatrix modelview;
float aspect;
userData->angle += (deltaTime * 40.0f);
if (userData->angle >= 360.0f) {
userData->angle -= 360.0f;
}
aspect = (GLfloat) myesContext->width / (GLfloat)myesContext->height;
myesMatrixLoadIdentity(&perspective);
// 投影矩阵P
myesPerspective(&perspective, 60.0f, aspect, 1.0f, 20.0f);
myesMatrixLoadIdentity(&modelview);
// 模型矩阵M
myesTranslate(&modelview, 0.0, 0.0, -3.0);
// 视图矩阵V
myesRotate(&modelview, userData->angle, 1.0, 0.0, 1.0);
// 组成MVP矩阵
myesMatrixMultiply(&userData->mvpMatrix, &modelview, &perspective);
}
void Draw(MYESContext *myesContext)
{
myUserData* userData = (myUserData *)myesContext->userData;
glViewport(0, 0, myesContext->width, myesContext->height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(userData->programObject);
glVertexAttribPointer(0, 3, GL_FLOAT,
GL_FALSE, 3 * sizeof(GLfloat), userData->vertices);
glEnableVertexAttribArray(0);
// 顶点常量属性color
glVertexAttrib4f(1, 1.0f, 0.0f, 0.0f, 1.0f);
// location表示uniform变量的引用;count表示矩阵的个数;transpose为FLASE表示列向量,TRUE表示行向量;value表示数据的指针
// void glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
glUniformMatrix4fv(userData->mvpLoc, 1, GL_FALSE, (GLfloat *)&userData->mvpMatrix.m[0][0]); // 给u_mvpMatrix统一变量赋值
glDrawElements(GL_TRIANGLES, userData->numIndices, GL_UNSIGNED_INT, userData->indices);
}
void Shutdown(MYESContext *myesContext)
{
myUserData *userData = (myUserData *)myesContext->userData;
if (userData->vertices != NULL) {
free(userData->vertices);
}
if (userData->indices != NULL) {
free(userData->indices);
}
glDeleteProgram(userData->programObject);
}
int myesMain(MYESContext *myesContext)
{
myesContext->userData = malloc(sizeof(myUserData));
myesCreateWindow(myesContext, "8_1_simple_vertexshader", 320, 240, MY_ES_WINDOW_RGB | MY_ES_WINDOW_DEPTH);
if (!Init(myesContext)) {
return GL_FALSE;
}
esRegisterUpdateFunc(myesContext, Update);
esRegisterDrawFunc(myesContext, Draw);
esRegisterShutdownFunc(myesContext, Shutdown);
return GL_TRUE;
}
参考
1. C ++和OpenGL矩阵顺序之间的混淆(行优先与列优先)
https://*.com/questions/17717600/confusion-between-c-and-opengl-matrix-order-row-major-vs-column-major