Sprite渲染流程-纹理绑定

简介: Sprite渲染流程-纹理绑定

Sprite使用的shader

  • vertexes
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
    gl_Position = CC_PMatrix * a_position;
    v_fragmentColor = a_color;
    v_texCoord = a_texCoord;
}
复制代码
  • fragment
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
    gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
}
复制代码

CCRenderer.cpp

drawBatchedTriangles(){
  for (int i=0; i<batchesTotal; ++i)
    {
        _triBatchesToDraw[i].cmd->useMaterial();
        glDrawElements(GL_TRIANGLES, (GLsizei) _triBatchesToDraw[i].indicesToDraw, GL_UNSIGNED_SHORT, (GLvoid*) (_triBatchesToDraw[i].offset*sizeof(_indices[0])) );   
    }
}
复制代码

在draw之前,会将材质同步进行设置。

Sprite使用的TrianglesCommand,TrianglesCommand在useMaterial中会绑定纹理

void TrianglesCommand::useMaterial() const
{
    //Set texture
    GL::bindTexture2D(_textureID);
    if (_alphaTextureID > 0)
    { // ANDROID ETC1 ALPHA supports.
        GL::bindTexture2DN(1, _alphaTextureID);
    }
    //set blend mode
    GL::blendFunc(_blendType.src, _blendType.dst);
    // 将uniform,attribute同步到shader
    _glProgramState->apply(_mv); 
}
复制代码

GL::bindTexture2D(_textureID)逻辑,里面做了cache,如果当前的纹理单元已经绑定了相同的纹理对象,就不再进行额外的active,bind逻辑

void bindTexture2D(GLuint textureId)
{
    GL::bindTexture2DN(0, textureId);
}
void bindTexture2DN(GLuint textureUnit, GLuint textureId)
{
#if CC_ENABLE_GL_STATE_CACHE
  CCASSERT(textureUnit < MAX_ACTIVE_TEXTURE, "textureUnit is too big");
  if (s_currentBoundTexture[textureUnit] != textureId)
  {
    s_currentBoundTexture[textureUnit] = textureId;
    activeTexture(GL_TEXTURE0 + textureUnit);
    glBindTexture(GL_TEXTURE_2D, textureId);
  }
#else
  glActiveTexture(GL_TEXTURE0 + textureUnit);
  glBindTexture(GL_TEXTURE_2D, textureId);
#endif
}
复制代码

最后的_glProgramState->apply()会再次同步shader变量

void GLProgramState::apply(const Mat4& modelView)
{
    applyGLProgram(modelView);
    applyAttributes();
    applyUniforms(); // 同步sampler的重点逻辑
}
void GLProgramState::applyUniforms()
{
    // set uniforms
    updateUniformsAndAttributes();
    for(auto& uniform : _uniforms) {
        uniform.second.apply();
    }
}
复制代码

uniform的同步

void UniformValue::apply()
{
  if (_type == Type::CALLBACK_FN) {
     switch (_uniform->type) {
            case GL_SAMPLER_2D:
                // 这里最终就是调用到了glUniform1i
                _glprogram->setUniformLocationWith1i(_uniform->location, _value.tex.textureUnit);
                // 再次确认绑定好纹理单元
                GL::bindTexture2DN(_value.tex.textureUnit, _value.tex.textureId);
                break;
    }
  }
}
复制代码

总结纹理绑定的流程

在fragment中需要定义一个sampler

uniform sampler2D texture;
复制代码
void bindTextureUnit(int textureUnit, GLunit textureId){
    // 先激活对应的纹理单元
    glActiveTexture(GL_TEXTURE0+textureUnit);
    // 将创建的纹理对象绑定到已经激活的纹理单元上
    glBindTexture(GL_TEXTURE_2D, textureId);
    // -----------上下2部分逻辑可以分离---------
    // glLinkProgram的结果,对shader的所有操作都依赖这个id
    GLuint shderProgram;
    // 获取shader fragment中的texture
    GLuint location = glGetUniformLocation(shderProgram, "texture");
    // 将sampler2D指定纹理单元
    glUniform1i(location, textureUnit);
}
复制代码
  • textureUnit

纹理单元,从0开始

  • textureId:本质上都是有glGenTextures生成的

从cocos2dx来说,它就是

texture->getName()
复制代码

从OpenGL的角度来说,

GLuint textureId;
glGenTextures(1, &textureId);
复制代码

因为OpenGL是个状态机,所以textureId会记录所有的操作痕迹。

知识点

为啥这么写:GL_TEXTURE0+textureUnit

#define GL_TEXTURE0 0x84C0
#define GL_TEXTURE1 0x84C1
#define GL_TEXTURE2 0x84C2
#define GL_TEXTURE3 0x84C3
#define GL_TEXTURE4 0x84C4
#define GL_TEXTURE5 0x84C5
#define GL_TEXTURE6 0x84C6
#define GL_TEXTURE7 0x84C7
#define GL_TEXTURE8 0x84C8
#define GL_TEXTURE9 0x84C9
复制代码

每个TEXTURE的id都是相邻的,对于glActiveTexture来说,只要value正确就能正常工作。



目录
相关文章
|
Linux
centos使用iptables实现nat端口转发
centos使用iptables实现nat端口转发
1118 4
|
前端开发 JavaScript 安全
【前端相关】elementui使用el-upload组件实现自定义上传
【前端相关】elementui使用el-upload组件实现自定义上传
3348 0
|
Web App开发 安全 应用服务中间件
阿里云服务器下Tomcat部署Web项目
3一、阿里云服务器下部署项目 1.登录linux服务器 2.下载mysql、tomcat、jdk 并安装 3.项目打成war包,并放置在tomcat下的webapps下 二、阿里云服务器开放访问端口 1.登录阿里云服务器管理控制台 2.点击进入云服务器ECS实例列表,如图: 3.点击右侧更多按钮,配置ip安全组 4.这里配置有80端口(http默认访问端口),443端口(https默认访问端口),3306端口(mysql访问端口) 5.配置完后浏览器输入ip+项目路径就可以访问了(ps:此处tomcat有端口配置,下文会提到)。
7988 1
|
JavaScript 前端开发 API
vue 开发规范
vue 开发规范
201 0
|
存储 前端开发 Java
Element el-upload 文件上传/图片上传/拖拽上传/附带参数/附带请求头部详解
文目录 1. 前言 2. 基本用法 2.1 前端部分 2.2 后端部分 2.3 获取后端返回信息 3. 外观功能介绍 3.1 拖拽上传 3.2 显示图片 3.3 设置文件列表样式 3.4 显示提示信息 4. 事件功能介绍 4.1 限制上传文件数量 4.2 限制上传文件类型和大小 4.3 移除文件处理 4.4 手动上传 5. 附带参数 6. 附带请求头部 7. 小结
7881 0
|
前端开发 API PHP
一款小而美的开源滑动验证码组件
一款小而美的开源滑动验证码组件
435 1
|
JavaScript 前端开发 安全
一个贼丝滑的 Vue 2 扩展组件,开源且免费
一个贼丝滑的 Vue 2 扩展组件,开源且免费
|
数据采集 人工智能 算法
你要牢记的四个常用AI提示词框架:ICIO、CRISPE、BROKE、RASCEF,有助于获取更加稳定和高质量的内容
你要牢记的四个常用AI提示词框架:ICIO、CRISPE、BROKE、RASCEF,有助于获取更加稳定和高质量的内容
|
设计模式 前端开发 Java
项目终于用上了 DDD 领域驱动,太强了!
我在公司对支付业务、结算业务、资金业务使用DDD进行领域建模的两年,得到了许多好评,也面对过不少质疑,总体来说还是能收获不少,这对团队成员理解业务起着很大作用。近半年一直在研究DDD的落地实战,如今已修得阶段性成果,迫不及待与大家分享我的落地经验。 DDD分为战略设计与战术设计。一般来说,领域建模是属于战略层的,而DDD工程落地是属于战术层的,两者是否结合使用,视实际情况而定,比如传统的MVC架构也能使用DDD进行领域建模,DDD架构最好是先做DDD领域建模。 最新上线的一个微服务——内部交易中心,我们使用了DDD架构来落地,希望看完对大家有启发。
|
网络协议 Linux 网络安全