opengl es 2.0游戏与图形编程——2.设置图形投影

注意:本文是读书笔记,代码是使用书中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;
}
);



  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值