最近因为工作需要阅读《Cocos2D-X 3.X 3D图形学渲染技术讲解》这本书所做的笔记。
该字段申明的变量是外部程序传给顶点(Vertex)着色器、片段(Fragment)着色器的变量。
该字段是一种从CPU应用向GPU中的着色器发送数据的方式。它是全局的,故而在每个着色器程序中必须保证其对象是唯一的。
可以在任意着色器中的任意阶段中访问,它会一致保持它的数据直到被
该变量是常量,类似C++中的const,不能被shader程序修改,只能使用。
如果声明之后没有用过,那么编辑器会默认移除这个变量。(如果只是在着色器内用,不需要任何声明修饰,直接定义使用就可以了)
通过glGetUniformLocation 函数查询uniform变量,用glUniformxx() 函数赋值。
GLint vertexColorLocation = glGetUniformLocation(shaderProgram, "vertexColor");
glUseProgram(shaderProgram);
glUniform4f(vertexColor,0.0f,1.0f,0.0f,1.0f);
作用: 一般用于变换矩阵、材质、光照参数、颜色等。
该变量只能在顶点(Vertex)着色器中申明和使用。
作用:一般用来表示一些顶点数据,例如:顶点坐标、法线、纹理坐标、顶点颜色等等
使用函数glBindAttribLocation来绑定每一个该变量的位置,接着使用函数glVertexAttribPointer为其赋值。
该变量主要用于Vertex和Fragment之间传递数据的。
一般流程是在Vertex中修改改变量,在Fragment中使用该变量。必须声明一致。
每个着色器的入口都是main函数,在这个函数中处理所有的输入变量,并将结果输出到输出变量中。
定义输入和输出的。 每个着色器是独立的,但也是整体的一部分。也就是,每个都有自己的输出和输入。in 和 out的作用就是用来输入和输出。
只要一个着色器的输出变量和下一个着色器的输入变量匹配,这个数据就会一致传递下去。
顶点着色器需要从顶点数据中直接输入。
片段着色器需要一个vec4 的变量作为输出。目的是因为片段着色器需要输出最终的颜色,如果不指定颜色,那么就会默认输出黑色或者白色。
因此可以看出,如果需要从一个着色器向另一个着色器发送数据,则必须在发送方着色器和接收方着色器中声明一样类型一样名字的变量。
可以看出来,三个顶点的在内存中的排列顺序,是XYZ+RGB进行排列的。
//位置属性
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,6 * sizeof(GLfloat),(GLvoid*) 0);
glEnableVertexAttribArray(0);
//颜色属性
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,6 * sizeof(GLfloat),(GLvoid*) (3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
函数glVertexAttribPointer 的作用是指定了渲染时索引值为 index 的顶点属性数组的数据格式和位置。
index:第几个属性,从0开始取,0,1,2,顺序自己定义,例如顶点位置,纹理,法线。
size:一个顶点所有数据的个数,坐标(XYZ)和颜色(RGB)都占3个float,所以是3
type:顶点描述数据的类型,这里position数组中的数据全部为float,所以是GL_FLOAT
normalized:是否需要显卡帮忙把数据归一化到-1到+1区间,这里不需要,所以设置GL_FALSE
stride:一个顶点占有的总的字节数。这里是6个float (xyzrgb),所以是6 * sizeof(GLfloat)
pointer:当前指针指向的vertex内部的偏离字节数,可以唯一的标识顶点某个属性的偏移量。第一个是0,顶点位置的属性。第二个是颜色,紧接着位置之后的,所以是 3 * sizeof(GLfloat)
原理: 在原始向量的基础上加上另一个向量,从而获得一个在不同位置的新向量。
三维坐标无法完成平移变换,需要将三维的点转换成四维的点。四维的点称为齐次坐标,本质就是在三维坐标的基础上加上一位w。
假设点为P(x,y,z)
,平移向量
T ⃗ ( T x , T y , T z ) \vec{T}(T_x,T_y,T_z) T(Tx,Ty,Tz)
可以用如下公式:
∣
1
0
0
T
x
0
1
0
T
y
0
0
1
T
z
0
0
0
1
∣
⋅
{
x
y
z
1
}
=
{
x
+
T
x
y
+
T
y
z
+
T
z
1
}
\left| 100Tx010Ty001Tz0001
cocos2dx中相关代码
//创建矩阵的平移函数
void Mat4::createTranslation(const Vec3& translation, Mat4* dst)
{
GP_ASSERT(dst);
memcpy(dst, &IDENTITY, MATRIX_SIZE);
dst->m[12] = translation.x;
dst->m[13] = translation.y;
dst->m[14] = translation.z;
}
void Mat4::createTranslation(float xTranslation, float yTranslation, float zTranslation, Mat4* dst)
{
GP_ASSERT(dst);
memcpy(dst, &IDENTITY, MATRIX_SIZE);
dst->m[12] = xTranslation;
dst->m[13] = yTranslation;
dst->m[14] = zTranslation;
}
原理:定义一个角,和旋转轴,物体沿着给定的轴旋转特定的角度,从而实现旋转功能。
X轴:在屏幕上的方向从左指向右。
Y轴:在屏幕上的方向是从下指向上。
Z轴:在屏幕上分为两种:
主要分为3种。
还有其他旋转组合,比如 XZ轴、XYZ轴等等
公式如下:
∣
1
0
0
0
0
cos
θ
−
sin
θ
0
0
sin
θ
cos
θ
0
0
0
0
1
∣
⋅
{
x
y
z
1
}
=
{
x
y
⋅
cos
θ
−
z
⋅
sin
θ
y
⋅
sin
θ
+
z
⋅
cos
θ
1
}
\left| 10000cosθ−sinθ00sinθcosθ00001
cocos2dx中代码:
void Mat4::createRotationX(float angle, Mat4* dst)
{
GP_ASSERT(dst);
memcpy(dst, &IDENTITY, MATRIX_SIZE);
float c = std::cos(angle);
float s = std::sin(angle);
dst->m[5] = c;
dst->m[6] = s;
dst->m[9] = -s;
dst->m[10] = c;
}
公式如下:
∣
cos
θ
0
sin
θ
0
0
1
0
0
−
sin
θ
0
cos
θ
0
0
0
0
1
∣
⋅
{
x
y
z
1
}
=
{
x
⋅
cos
θ
+
z
⋅
sin
θ
y
−
x
⋅
sin
θ
+
z
⋅
cos
θ
1
}
\left| cosθ0sinθ00100−sinθ0cosθ00001
cocos2dx中的代码如下:
void Mat4::createRotationY(float angle, Mat4* dst)
{
GP_ASSERT(dst);
memcpy(dst, &IDENTITY, MATRIX_SIZE);
float c = std::cos(angle);
float s = std::sin(angle);
dst->m[0] = c;
dst->m[2] = -s;
dst->m[8] = s;
dst->m[10] = c;
}
公式如下:
∣
cos
θ
−
sin
θ
0
0
sin
θ
cos
θ
0
0
0
0
1
0
0
0
0
1
∣
⋅
{
x
y
z
1
}
=
{
x
⋅
cos
θ
−
y
⋅
sin
θ
x
⋅
sin
θ
+
y
⋅
cos
θ
z
1
}
\left| cosθ−sinθ00sinθcosθ0000100001
cocos2dx中的代码如下:
void Mat4::createRotationZ(float angle, Mat4* dst)
{
GP_ASSERT(dst);
memcpy(dst, &IDENTITY, MATRIX_SIZE);
float c = std::cos(angle);
float s = std::sin(angle);
dst->m[0] = c;
dst->m[1] = s;
dst->m[4] = -s;
dst->m[5] = c;
}
cocos2dx中的实现方法
void Mat4::createRotation(const Quaternion& q, Mat4* dst)
{
GP_ASSERT(dst);
float x2 = q.x + q.x;
float y2 = q.y + q.y;
float z2 = q.z + q.z;
float xx2 = q.x * x2;
float yy2 = q.y * y2;
float zz2 = q.z * z2;
float xy2 = q.x * y2;
float xz2 = q.x * z2;
float yz2 = q.y * z2;
float wx2 = q.w * x2;
float wy2 = q.w * y2;
float wz2 = q.w * z2;
dst->m[0] = 1.0f - yy2 - zz2;
dst->m[1] = xy2 + wz2;
dst->m[2] = xz2 - wy2;
dst->m[3] = 0.0f;
dst->m[4] = xy2 - wz2;
dst->m[5] = 1.0f - xx2 - zz2;
dst->m[6] = yz2 + wx2;
dst->m[7] = 0.0f;
dst->m[8] = xz2 + wy2;
dst->m[9] = yz2 - wx2;
dst->m[10] = 1.0f - xx2 - yy2;
dst->m[11] = 0.0f;
dst->m[12] = 0.0f;
dst->m[13] = 0.0f;
dst->m[14] = 0.0f;
dst->m[15] = 1.0f;
}
公式如下:
∣
S
1
0
0
0
0
S
2
0
0
0
0
S
3
0
0
0
0
1
∣
⋅
{
x
y
z
1
}
=
{
S
1
⋅
x
S
2
⋅
y
S
3
⋅
z
1
}
\left| S10000S20000S300001
其中S1
,S2
,S3
是放大系数。
cocos2dx中的代码
void Mat4::createScale(const Vec3& scale, Mat4* dst)
{
GP_ASSERT(dst);
memcpy(dst, &IDENTITY, MATRIX_SIZE);
dst->m[0] = scale.x;
dst->m[5] = scale.y;
dst->m[10] = scale.z;
}
void Mat4::createScale(float xScale, float yScale, float zScale, Mat4* dst)
{
GP_ASSERT(dst);
memcpy(dst, &IDENTITY, MATRIX_SIZE);
dst->m[0] = xScale;
dst->m[5] = yScale;
dst->m[10] = zScale;
}