内容简介: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 图形学渲染系列十六》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- CubeEngine v0.3B 更新,图形渲染引擎
- TensorFlow也可以做图形渲染了:当神经网络遇上计算机图形学
- Basemark推出Rocksolid图形渲染解决方案
- Ogre 1.12.3 发布,三维图形渲染引擎
- Rust 移动端跨平台复杂图形渲染项目开发系列总结(目录)
- Cocos2d-x 3.x 图形学渲染系列总结
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。