Cocos2d-x 3.x 图形学渲染系列十六

栏目: IOS · 发布时间: 7年前

内容简介:Cocos2d-x 3.x 图形学渲染系列十六

笔者介绍: 姜雪伟 IT 公司技术合伙人, IT 高级讲师, CSDN 社区专家,特邀编辑,畅销书作者,国家专利发明人 ; 已出版书籍:《手把手教你 架构 3D 游戏引擎》电子工业出版社 和《 Unity3D 实战核心技术详解》电子工业出版社等。

每个引擎都有自己的处理Shader类,Cocos使用的是GLProgram类, 之所以定义 GLProgram 类,是因为在引擎中需要有一个类管理模型的信息和矩阵信息声明。在 GLProgram 类中定义了模型顶点的属性,这些属性在加载模型时,用于解释模型文件内容时用于做属性标记处理,它是使用枚举定义的,枚举类代码如下所示:

enum
    {
		/**索引0用于定义位置*/
        VERTEX_ATTRIB_POSITION,
		/**索引1用于定义颜色*/
        VERTEX_ATTRIB_COLOR,
		/**索引2用于定义纹理坐标单元0*/
        VERTEX_ATTRIB_TEX_COORD,
		/**索引3用于定义纹理坐标单元1.*/
        VERTEX_ATTRIB_TEX_COORD1,
		/**索引4用于定义纹理坐标单元2.*/
        VERTEX_ATTRIB_TEX_COORD2,
		/**索引5用于定义纹理坐标单元3.*/
        VERTEX_ATTRIB_TEX_COORD3,
		/**索引6用于定义法线*/
        VERTEX_ATTRIB_NORMAL,
		/**索引7用于定义混合权重*/
        VERTEX_ATTRIB_BLEND_WEIGHT,
		/**索引8用于定义混合索引.*/
        VERTEX_ATTRIB_BLEND_INDEX,
		/**索引9用于定义正切.*/
        VERTEX_ATTRIB_TANGENT,
		/**索引10用于定义次法线.*/
        VERTEX_ATTRIB_BINORMAL,
        VERTEX_ATTRIB_MAX,

        VERTEX_ATTRIB_TEX_COORDS = VERTEX_ATTRIB_TEX_COORD,
    };

在后面有关模型章节时,会有这方面的实际操作,接下来 GLProgram 类还定义了 Shader 中经常用于计算矩阵转换的标记,也是以枚举形式定义的如下所示:

enum
    {
		/**环境颜色.*/
        UNIFORM_AMBIENT_COLOR,
		/**投影矩阵*/
        UNIFORM_P_MATRIX,
		/**模型视口矩阵.*/
        UNIFORM_MV_MATRIX,
		/**模型视口投影矩阵.*/
        UNIFORM_MVP_MATRIX,
		/**法线矩阵.*/
        UNIFORM_NORMAL_MATRIX,
		/**时间.*/
        UNIFORM_TIME,
		/**sin(时间).*/
        UNIFORM_SIN_TIME,
		/**cos(时间).*/
        UNIFORM_COS_TIME,
		/**随机数字.*/
        UNIFORM_RANDOM01,
		/** @{
        * 对纹理的取样0-3
        */
        UNIFORM_SAMPLER0,
        UNIFORM_SAMPLER1,
        UNIFORM_SAMPLER2,
        UNIFORM_SAMPLER3,
		/**@}*/
        UNIFORM_MAX,
};

GLProgram 类不只是只定义枚举属性,它还提供了加载顶点着色器和片段着色器接口函数,通过这些接口开发者可以知道它在加载Shader 脚本时是如何解释其内容的。加载Shader脚本函数如下所示:

GLProgram* GLProgram::createWithFilenames(const std::string& vShaderFilename, const std::string& fShaderFilename, const std::string& compileTimeDefines)
{
	auto ret = new (std::nothrow) GLProgram();
	if(ret && ret->initWithFilenames(vShaderFilename, fShaderFilename, compileTimeDefines)) {
        ret->link();
        ret->updateUniforms();
        ret->autorelease();
		return ret;
    }

		CC_SAFE_DELETE(ret);
	return nullptr;
}

createWithFilenames 函数中的参数是顶点着色器和片段着色器的文件路径,函数内部调用了 initWithFilenames 函数,继续深入进去查看该函数执行细节,内容如下所示:

bool GLProgram::initWithFilenames(const std::string& vShaderFilename, const std::string& fShaderFilename, const std::string& compileTimeDefines)
{
	auto fileUtils = FileUtils::getInstance();
std::string vertexSource = fileUtils->getStringFromFile(FileUtils::getInstance()->fullPathForFilename(vShaderFilename));
std::string fragmentSource = fileUtils->getStringFromFile(FileUtils::getInstance()->fullPathForFilename(fShaderFilename));

	return	initWithByteArrays(vertexSource.c_str(), fragmentSource.c_str(), compileTimeDefines);
}

程序加载了顶点着色器和片段着色器,也就是将 Shader 文件加载到内存中,接下来开始编译 Shader 脚本了,编译 Shader 脚本的函数是 initWithByteArrays ,它的具体实现代码如下所示:

bool GLProgram::initWithByteArrays(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray, const std::string& compileTimeDefines)
{
	_program = glCreateProgram();
	CHECK_GL_ERROR_DEBUG();

	std::string replacedDefines = "";
	replaceDefines(compileTimeDefines, replacedDefines);

	_vertShader = _fragShader = 0;

	if (vShaderByteArray)
    {
		if(!compileShader(&_vertShader, GL_VERTEX_SHADER, vShaderByteArray, replacedDefines))
        {
			CCLOG("cocos2d: ERROR: Failed to compile vertex shader");
			return false;
       }
    }

	// 创建和编译片段着色器
	if (fShaderByteArray)
    {
	if(!compileShader(&_fragShader, GL_FRAGMENT_SHADER, fShaderByteArray, replacedDefines))
        {
			CCLOG("cocos2d: ERROR: Failed to compile fragment shader");
			return false;
        }
    }

	if (_vertShader)
    {
		glAttachShader(_program, _vertShader);
    }
	CHECK_GL_ERROR_DEBUG();

	if (_fragShader)
    {
		glAttachShader(_program, _fragShader);
    }

	_hashForUniforms.clear();

	CHECK_GL_ERROR_DEBUG();

	return true;
}

程序加载了顶点着色器和片段着色器,也就是将Shader 文件加载到内存中,接下来开始编译Shader脚本了,编译Shader脚本的函数是initWithByteArrays,它的具体实现如下所示:

bool GLProgram::compileShader(GLuint* shader, GLenum type, const GLchar* source, const std::string& convertedDefines)
{
	GLint status;

	if(!source)
    {
		return false;
    }

	const GLchar *sources[] = {
	#if CC_TARGET_PLATFORM == CC_PLATFORM_WINRT
        (type == GL_VERTEX_SHADER ?"precision mediump float;\n precision mediump int;\n" : "precision mediump float;\n precision mediump int;\n"),
	#elif (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32 && CC_TARGET_PLATFORM != CC_PLATFORM_LINUX && CC_TARGET_PLATFORM != CC_PLATFORM_MAC)
        (type == GL_VERTEX_SHADER ?"precision highp float;\n precision highp int;\n" : "precision mediump float;\n precision mediump int;\n"),
#endif
	COCOS2D_SHADER_UNIFORMS,
        convertedDefines.c_str(),
        source};

    *shader = glCreateShader(type);
	glShaderSource(*shader, sizeof(sources)/sizeof(*sources), sources, nullptr);
	glCompileShader(*shader);

	glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);

	if (! status)
    {
		GLsizei length;
		glGetShaderiv(*shader, GL_SHADER_SOURCE_LENGTH, &length);
		GLchar* src = (GLchar*)malloc(sizeof(GLchar) * length);

		glGetShaderSource(*shader, length, nullptr, src);
		CCLOG("cocos2d: ERROR: Failed to compile shader:\n%s", src);

		if (type == GL_VERTEX_SHADER)
        {
			CCLOG("cocos2d: %s", getVertexShaderLog().c_str());
        }
		else
        {
			CCLOG("cocos2d: %s", getFragmentShaderLog().c_str());
        }
			free(src);

			return false;
    }
		return (status == GL_TRUE);
}

函数的主要作用是对编写的 Shader 代码进行逐行解释,整个 Shader 底层加载编译就完成了,在明白其运行原理后,开始编写逻辑,假设已经有了顶点着色器代码 zerklo.vert 和片段着色器 zerklo.frag ,需将其传入到函数的参数中,调用的代码片段如下:

auto glprogram_Zerkalo = GLProgram::createWithFilenames("astronaut/zerkalo.vert", "astronaut/zerkalo.frag");
	auto _state_Zerkalo = GLProgramState::getOrCreateWithGLProgram(glprogram_Zerkalo);
sprite_Zerkalo->setGLProgramState(_state_Zerkalo);

代码片段是加载 Shader 的顶点着色器和片段着色器,加载完成将其作用到材质上。当然加载 Shader 的方式有很多种,也可以直接使用材质脚本加载,后面章节会有具体介绍,下面系列开始介绍顶点索引数据类。


以上所述就是小编给大家介绍的《Cocos2d-x 3.x 图形学渲染系列十六》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Lighttpd

Lighttpd

Andre Bogus / Packt Publishing / 2008-10 / 39.99

This is your fast guide to getting started and getting inside the Lighttpd web server. Written from a developer's perspective, this book helps you understand Lighttpd, and get it set up as securely an......一起来看看 《Lighttpd》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试