cocos中用到了许多shader
例如最常用的Sprite所使用的
ccPositionTextureColor_noMVP_frag
其中主函数写到
void main()
{
gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
}
即最终片段的颜色值=图形颜色与纹理的混合
一般来说Sprite只对应一张纹理,也就是一张png贴图
那么纹理是如何与CC_Texture0建立关系的呢
下面梳理一下cocos的封装套路
个人认为并不能喷cocos封装的不好
毕竟底层的东西的确十分复杂
对于游戏开发人员,越简单的API越nice
但同样封装也不可避免的增加了学习底层技术的难度
1.CCGLProgram.cpp/GLProgram::compileShader
这里如下声明了CC_Texture0
const GLchar *sources[] = {
...
uniform sampler2D CC_Texture0;
...
}
我的理解是,sources内容被强加入每一个shader
作为通用部分
这里sampler2D类型在glsl中作为纹理单元/纹理句柄
大概就是一个类似指针的东西,指向具体的纹理数据(图片颜色数组)
2.CCGLProgram.cpp/GLProgram::updateUniforms()
这里为CC_Texture0做了赋值操作
首先找到location
_builtInUniforms[UNIFORM_SAMPLER0] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER0);
_builtInUniforms[UNIFORM_SAMPLER1] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER1);
_builtInUniforms[UNIFORM_SAMPLER2] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER2);
_builtInUniforms[UNIFORM_SAMPLER3] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER3);
然后做了这样的操作
// Since sample most probably won't change, set it to 0,1,2,3 now.
if(_builtInUniforms[UNIFORM_SAMPLER0] != -1)
setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER0], 0);
void GLProgram::setUniformLocationWith1i(GLint location, GLint i1)
{
bool updated = updateUniformLocation(location, &i1, sizeof(i1)*1);
if( updated )
{
glUniform1i( (GLint)location, i1);
}
}
结果就是用glUniform1i把
CC_Texture0的值做成了0
我的理解是,CC_Texture0现在被赋值为对应0号纹理单元
3.GL::bindTexture2D(textureId);
将纹理绑定于纹理单元
因为多重纹理的关系,所以我们既可以选择纹理图,还可以选择纹理单元!
当然如果只有单个纹理,那么自然应该绑在默认纹理也就是CC_Texture0上面
GL::bindTexture2D(textureId)中调用如下函数
GL::bindTexture2DN(0, textureId);
GL::bindTexture2DN(GLuint textureUnit, GLuint textureId)
内部调用如下
activeTexture(GL_TEXTURE0 + textureUnit);//1.激活纹理单元,选择纹理单元
glBindTexture(GL_TEXTURE_2D, textureId);//2.为当前纹理单元绑定纹理图片
textureUnit == 0 表示我们激活CC_Texture0
textureId 是我们使用的纹理图片
因此这时在shader中就可以使用CC_Texture0来做纹理采样了!
写的不怎么好
帮助自己理解
高手看到错误劳烦指出!
参考文献
https://zhuanlan.zhihu.com/p/20289660
http://www.cnblogs.com/slysky/p/3981210.html