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正确就能正常工作。



目录
相关文章
|
前端开发
Threejs - 加载视频纹理渲染 实现一个3D视频播放器
Threejs - 加载视频纹理渲染 实现一个3D视频播放器
2162 0
Threejs - 加载视频纹理渲染 实现一个3D视频播放器
|
3月前
|
容器
ThreeJs同一个场景多个相机的显示
这篇文章讲解了如何在Three.js中实现多相机功能,通过创建和布置多个相机及渲染器,从而能够在同一场景中从不同角度观察3D模型。
105 1
|
5月前
|
缓存 图形学
Unity3D学习笔记12——渲染纹理
Unity3D学习笔记12——渲染纹理
50 2
|
6月前
|
JavaScript
vue 组件封装 | 随鼠标移动的信息框 (含监听鼠标移动、移出事件,获取元素的宽高、获取浏览器的宽高)
vue 组件封装 | 随鼠标移动的信息框 (含监听鼠标移动、移出事件,获取元素的宽高、获取浏览器的宽高)
58 1
|
6月前
|
编解码 前端开发 iOS开发
响应式图片的实现(含picture标签、srcset属性、sizes属性的使用方法,设备像素比详解)
响应式图片的实现(含picture标签、srcset属性、sizes属性的使用方法,设备像素比详解)
92 0
|
6月前
|
Web App开发 前端开发
canvas系列教程04 —— 渐变、阴影、路径、状态、Canvas对象、图形重叠模式
canvas系列教程04 —— 渐变、阴影、路径、状态、Canvas对象、图形重叠模式
524 0
|
8月前
|
Android开发 开发者
Android开发之通过渲染纹理展示地球仪
该文阐述了如何使用OpenGL为三维物体添加纹理,以增强其真实感。纹理坐标是二维的,用于标记摊平后的“布料”对应物体的哪个部位,类似裁缝制作衣服的过程。在OpenGL中,启用纹理和深度测试是关键,还包括设置纹理参数、分配纹理编号、绑定位图材质等步骤。计算材质的纹理坐标后,通过`glDrawArrays`结合顶点和纹理坐标逐个贴图。最终示例展示了将世界地图贴到球体上形成逼真的地球仪效果。通过控制旋转、平移和缩放,能实现简单的三维动画效果。
89 2
Android开发之通过渲染纹理展示地球仪
|
存储 前端开发
canvas自定义绘制顺序解决遮挡问题
canvas自定义绘制顺序解决遮挡问题
268 0
|
前端开发 容器
Bootstrap4(一)重点----网格系统,图像形状,轮播,多媒体对象,滚动监听
Bootstrap 提供了一套响应式、移动设备优先的流式网格系统,随着屏幕或视口(viewport)尺寸的增加,系统会自动分为最多 12 列。
194 0
Bootstrap4(一)重点----网格系统,图像形状,轮播,多媒体对象,滚动监听