注意:本文是读书笔记,代码是使用书中sdk的,主要掌握重点知识,别在意小细节
1.两种投影:正交投影(2d,但可使用z,只是透视完全基于当前屏幕比),透视投影(3d)
2.初始设置矩阵
模型视图矩阵:物体空间 -> (模型)世界空间 ->(视图) 摄像机空间
拓展:
[视图变换] 当摄像机的位置和朝向任意时,投影变换及气体类型的变换变得困难。为了简化运算,我们将摄像机变化到世界坐标系原点,并旋转使摄像机的 光轴和世界坐标系z轴正方向一致。 视图变换是从世界坐标系到摄像机坐标系的变换,计算就是将摄像机弄回原点并对齐z轴的变换(也可以是将摄像机从坐标轴原点移动到摄像机当前位置的 逆变换)。 许多计算都在眼睛坐标系中完成,一个常用的就是光照需要在这个空间中实现,因为眼睛位置决定了光照效果,否则的话,很难实现镜面光。因此我们需要将法线坐标转换到眼睛坐标系中。 标准向量(Normal vectors)——从对象坐标系(Object coordinates)变换到视觉坐标系(eye coordinates),它是用来计算光照(lighting calculation)的.注意标准向量(Normal vectors)的变换和顶点的不同。其中视觉矩阵(view matrix)是GL_MODELVIEW逆矩阵的转置矩阵和标准向量(Normal vector是)相乘所得。代码:
GFX_set_matrix_mode( MODELVIEW_MATRIX );
GFX_load_identity();
vec3 e = {0.0f, -3.0f, 0.0f},
c = {0.0f, 0.0f, 0.0f},
u = {0.0f, 0.0f, 1.0f};
GFX_look_at(&e, &c, &u);
static float y = 0.0f;
y += 0.1f;
GFX_translate(0.0f, y, 0.0f);
GFX_rotate(y * 50.0f, 1.0f, 1.0f, 1.0f);
投影矩阵:摄像机空间 -> 裁减空间(视锥空间)
// 2d
GFX_set_orthographic((float)height / (float)width, 5.0f, (float)width / (float)height, 1.0f, 100.0f, 0.0f);
// 3d
GFX_set_perspective(45.0f, (float)width / (float)height, 0.01f, 100.0f, 0.0f);
3.使用着色器
program = PROGRAM_init( ( char * )"default" );
program->vertex_shader = SHADER_init( VERTEX_SHADER, GL_VERTEX_SHADER );
program->fragment_shader = SHADER_init( FRAGMENT_SHADER, GL_FRAGMENT_SHADER );
m = mopen( VERTEX_SHADER, 1 );
if( m ) {
if( !SHADER_compile( program->vertex_shader,
( char * )m->buffer,
DEBUG_SHADERS ) ) exit( 1 );
}
m = mclose( m );
m = mopen( FRAGMENT_SHADER, 1 );
if( m ) {
if( !SHADER_compile( program->fragment_shader,
( char * )m->buffer,
DEBUG_SHADERS ) ) exit( 2 );
}
m = mclose( m );
if( !PROGRAM_link( program, DEBUG_SHADERS ) ) exit( 3 );
上面创建了一个着色器程序,并读取和编译了顶点着色器和片段着色器,然后链接了这个着色器程序。
下面是绘制时的代码:
if( program->pid ) {
char attribute, uniform;
glUseProgram( program->pid );
uniform = PROGRAM_get_uniform_location( program, ( char * )"MODELVIEWPROJECTIONMATRIX" );
glUniformMatrix4fv( uniform,
1 /* How many 4x4 matrix */,
GL_FALSE /* Transpose the matrix? */,
<span style="white-space:pre"> </span>( float * )GFX_get_modelview_projection_matrix() );
attribute = PROGRAM_get_vertex_attrib_location( program, ( char * )"POSITION" );
glEnableVertexAttribArray( attribute );
glVertexAttribPointer( attribute, 3, GL_FLOAT, GL_FALSE, 0, POSITION );
attribute = PROGRAM_get_vertex_attrib_location( program, ( char * )"COLOR" );
glEnableVertexAttribArray( attribute );
glVertexAttribPointer( attribute, 4, GL_FLOAT, GL_FALSE, 0, COLOR );
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
}
先使用来该着色器程序,获取其中定义的全局uniform变量 MODELVIEWPROJECTION 的地址location,并设置其值。
同理设置了要绘制的顶点多两个属性的值(数组),属性值如下:
static const float POSITION[ 12 ] = {
-0.5f, 0.0f, -0.5f, // Down left (pivot point)
0.5f, 0.0f, -0.5f, // Up left
-0.5f, 0.0f, 0.5f, // Down right
0.5f, 0.0f, 0.5f // Up right
};
static const float COLOR[ 16 ] = {
1.0f, 0.0f, 0.0f, 1.0f, // Red
0.0f, 1.0f, 0.0f, 1.0f, // Green
0.0f, 0.0f, 1.0f, 1.0f, // Blue
1.0f, 1.0f, 0.0f, 1.0f // Yellow
};
设置好变量和值后就提交渲染了。
4.着色器代码
顶点着色器:
uniform mediump mat4 MODELVIEWPROJECTIONMATRIX;
attribute mediump vec4 POSITION;
attribute lowp vec4 COLOR;
varying lowp vec4 color;
void main( void ) {
gl_Position = MODELVIEWPROJECTIONMATRIX * POSITION;
color = COLOR;
}
主要就是把cpp里传来的顶点位置属性 左乘了 模型视图 投影矩阵,即被变换到裁剪空间了,并用gl_Position输出。然后给片段着色器传递了一个color变量(varying标记)。
片段着色器:
varying lowp vec4 color;
void main( void ) {
gl_FragColor = color;
}
直接输出顶点着色器传来的颜色值。
最终效果如下:
5.看下cocos2dx
设置矩阵:
case Projection::_2D:
{
loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
Mat4 orthoMatrix;
Mat4::createOrthographicOffCenter(0, size.width, 0, size.height, -1024, 1024, &orthoMatrix);
multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, orthoMatrix);
loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
break;
}
case Projection::_3D:
{
float zeye = this->getZEye();
Mat4 matrixPerspective, matrixLookup;
loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
// issue #1334
Mat4::createPerspective(60, (GLfloat)size.width/size.height, 10, zeye+size.height/2, &matrixPerspective);
multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, matrixPerspective);
Vec3 eye(size.width/2, size.height/2, zeye), center(size.width/2, size.height/2, 0.0f), up(0.0f, 1.0f, 0.0f);
Mat4::createLookAt(eye, center, up, &matrixLookup);
multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, matrixLookup);
loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
break;
}
默认是3d方式,投影矩阵里已经乘了一个往屏幕中心看的摄像机矩阵了。
节点的模型视图矩阵:
Mat4 Node::transform(const Mat4& parentTransform)
{
return parentTransform * this->getNodeToParentTransform();
}
这个会传递给渲染命令RenderCommand使用,比如:
void TrianglesCommand::useMaterial() const
{
//Set texture
GL::bindTexture2D(_textureID);
//set blend mode
GL::blendFunc(_blendType.src, _blendType.dst);
_glProgramState->apply(_mv);
}
被着色器程序状态ProgramState作为内置的全局变量CC_MVMatrix (还有类似的
CC_MVPMatrix)传递给其着色器代码使用。
着色器代码:
const char* ccPositionColor_vert = STRINGIFY(
attribute vec4 a_position;
attribute vec4 a_color;
\n#ifdef GL_ES\n
varying lowp vec4 v_fragmentColor;
\n#else\n
varying vec4 v_fragmentColor;
\n#endif\n
void main()
{
gl_Position = CC_MVPMatrix * a_position;
v_fragmentColor = a_color;
}
);
const char* ccPositionColor_frag = STRINGIFY(
\n#ifdef GL_ES\n
precision lowp float;
\n#endif\n
varying vec4 v_fragmentColor;
void main()
{
gl_FragColor = v_fragmentColor;
}
);