CCVertexIndexData 主要用于保存实际持有vbo的VertexBuffer 类和 VertexStreanAtrribute 结构体的文件。 #1 VertexData 实际使用的对象
class CC_DLL VertexData : public Ref
{
public:
/**
Create function, used to create a instance of VertexData.
*/
static VertexData* create();
/**
Get the number of streams in the VertexData.
*/
size_t getVertexStreamCount() const;
/**
Set a stream to VertexData,given that stream is identified by semantic, so if the semantic is not
specified before, it will add a stream, or it will override the old one.
@param buffer The binding buffer of the stream.
@param stream The binding vertex attribute, its member semantic will be used as the identifier.
*/
bool setStream(VertexBuffer* buffer, const VertexStreamAttribute& stream);
/**
Remove the given streams.
@param semantic The semantic of the stream.
*/
void removeStream(int semantic);
/**
Get the attribute of stream, const version.
@param semantic The semantic of the stream.
*/
const VertexStreamAttribute* getStreamAttribute(int semantic) const;
/**
Get the attribute of stream.
@param semantic The semantic of the stream.
*/
VertexStreamAttribute* getStreamAttribute(int semantic);
/**
Get the binded buffer of the stream.
@param semantic The semantic of the stream.
*/
VertexBuffer* getStreamBuffer(int semantic) const;
/**
Called for rendering, it will bind the state of vertex data to current rendering pipeline.
*/
void use();
//.......
protected:
/**
Simple struct to bundle buffer and attribute.
*/
struct BufferAttribute
{
VertexBuffer* _buffer;
VertexStreamAttribute _stream;
};
/**
Streams in the VertexData.
*/
std::map<int, BufferAttribute> _vertexStreams;
};
复制代码
其中除了一系列设置属性获取属性的方法外最重要的就是 _vertexStreams 和 use()方法 _vertexStreams 保存了持有gl层使用 的顶点缓存对像即vbo的vertexBuffer 和用于glVertexAttributePointer*()方法的 VertexStreamAttribute 结构体, 实际的使用方法都在use方法内
void VertexData::use()
{
uint32_t flags(0);
for(auto& element : _vertexStreams)
{
flags = flags | (1 << element.second._stream._semantic);
}
GL::enableVertexAttribs(flags);
int lastVBO = -1;
for(auto& element : _vertexStreams)
{
//glEnableVertexAttribArray((GLint)element.second._stream._semantic);
auto vertexStreamAttrib = element.second._stream;
auto vertexBuffer = element.second._buffer;
// don't call glBindBuffer() if not needed. Expensive operation.
int vbo = vertexBuffer->getVBO();
if (vbo != lastVBO) {
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->getVBO());
lastVBO = vbo;
}
glVertexAttribPointer(GLint(vertexStreamAttrib._semantic),
vertexStreamAttrib._size,
vertexStreamAttrib._type,
vertexStreamAttrib._normalize,
vertexBuffer->getSizePerVertex(),
(GLvoid*)((long)vertexStreamAttrib._offset));
}
}
复制代码
glVertexAttribPointer方法各参数的意义在之前的日记中有提到过这里就不说明了,会与 对应的vertexStreamAttribute各参数的一同说明
#VertexStreamAttribute 保存了顶点着色器的顶点属性的绑定参数
struct CC_DLL VertexStreamAttribute
{
/**
Constructor.
*/
VertexStreamAttribute()
: _normalize(false),_offset(0),_semantic(0),_type(0),_size(0)
{
}
/**
Constructor
@param offset The offset of the attribute.
@param semantic The semantic (Position, Texcoord, Color etc) of attribute.
@param type The type of attribute, could be GL_FLOAT, GL_UNSIGNED_BYTE etc.
@param size Describe how many elements of type in the attribute.
*/
VertexStreamAttribute(int offset, int semantic, int type, int size)
: _normalize(false),_offset(offset),_semantic(semantic),_type(type),_size(size)
{
}
/**
Constructor
@param offset The offset of the attribute.
@param semantic The semantic (Position, Texcoord, Color etc) of attribute.
@param type The type of attribute, could be GL_FLOAT, GL_UNSIGNED_BYTE etc.
@param size Describe how many elements of type in the attribute.
@param normalize If true, the data will be normalized by dividing 255.
*/
VertexStreamAttribute(int offset, int semantic, int type, int size, bool normalize)
: _normalize(normalize),_offset(offset),_semantic(semantic),_type(type),_size(size)
{
}
/**
Whether the attribute should be normalized or not.
*/
bool _normalize;
/**
The offset of the attribute in the buffer.
*/
int _offset;
/**
Describe that the attribute usage, could be Position, Color etc.
这里应该对应的是之前GLProgram里声明的顶点属性名称 枚举里的值
*/
int _semantic;
/**
Describe the type of attribute, could be GL_FLOAT, GL_UNSIGNED_BYTE etc.
*/
int _type;
/**
Describe how many elements of type in the attribute.
*/
int _size;
};
复制代码
感觉这个应该放在上面的VertexData的use方法上面说明,应该更合适些 这里估计一种顶点属性就会有一个对应的VertexStreamAttribute 所以如果你需要往顶点shader里传递Position TexCoord 等多个绑定顶点属性时就需要创建多个VertexStreamAttribute, 这些都是在引擎底层实现的使用者基本上不需要去管理
VertexBuffer
实际持有opengl 提供的vbo索引的cocos对象
lass CC_DLL VertexBuffer : public Ref
{
public:
/**
Create an instance of VertexBuffer.
@param sizePerVertex Size in bytes of one vertex.
@param vertexNumber The number of vertex.
@param usage A hint to indicate whether the vertexBuffer are updated frequently or not to let GL optimise it.
*/
static VertexBuffer* create(int sizePerVertex, int vertexNumber, GLenum usage = GL_STATIC_DRAW);
/**Get the size in bytes of one vertex.*/
int getSizePerVertex() const;
/**Get the number of vertices.*/
int getVertexNumber() const;
/**
Update all or part of vertices data, if the range specified exceeds the vertex buffer, it will be clipped.
@param verts The pointer of the vertex data.
@param count The number of vertices to update.
@param begin The first vertex to update.
*/
bool updateVertices(const void* verts, int count, int begin);
/**
Get the size of the vertex array in bytes, equals getSizePerVertex() * getVertexNumber().
*/
int getSize() const;
/**
Get the internal openGL handle.
*/
GLuint getVBO() const;
protected:
/**
Constructor.
*/
VertexBuffer();
/**
Destructor.
*/
virtual ~VertexBuffer();
/**
Init the storage of vertex buffer.
@param sizePerVertex Size in bytes of one vertex.
@param vertexNumber The number of vertex.
@param usage A hint to indicate whether the vertexBuffer are updated frequently or not to let GL optimise it.
*/
bool init(int sizePerVertex, int vertexNumber, GLenum usage = GL_STATIC_DRAW);
protected:
/**
Event handler for foreground.
*/
void recreateVBO() const;
/**
Event listener for foreground.
*/
EventListenerCustom* _recreateVBOEventListener;
protected:
/**
Internal handle for openGL.
*/
mutable GLuint _vbo;
/**
Size in bytes for one vertex.
*/
int _sizePerVertex;
/**
Number of vertices.
*/
int _vertexNumber;
/**
Buffer used for shadow copy.
*/
std::vector<unsigned char> _shadowCopy;
/**
Hint for optimisation in GL.
*/
GLenum _usage;
protected:
/**
Static member to indicate that use _shadowCopy or not.
*/
static bool _enableShadowCopy;
public:
/**
Static getter for shadowCopy.
*/
static bool isShadowCopyEnabled() { return _enableShadowCopy; }
/**
Static setter for shadowCopy.
*/
static void enableShadowCopy(bool enabled) { _enableShadowCopy = enabled; }
};
复制代码
如果有opengl基础的同学估计看到这些方法的时候就知道这个类是干什么的了
bool VertexBuffer::init(int sizePerVertex, int vertexNumber, GLenum usage/* = GL_STATIC_DRAW*/)
{
if(0 == sizePerVertex || 0 == vertexNumber)
return false;
_sizePerVertex = sizePerVertex;
_vertexNumber = vertexNumber;
_usage = usage;
if(isShadowCopyEnabled())
{
_shadowCopy.resize(sizePerVertex * _vertexNumber);
}
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, getSize(), nullptr, _usage);
glBindBuffer(GL_ARRAY_BUFFER, 0);
return true;
}
复制代码
看到上面init函数的实现后是不是一下子就看懂了,这就是个用来管理对应VBO的管理对象(Cocos中使用了大量这种对象, 基本上使用到的opengl里的handler都有对应的管理对象,就像CCGLProgram)
bool VertexBuffer::updateVertices(const void* verts, int count, int begin)
{
if(count <= 0 || nullptr == verts) return false;
if(begin < 0)
{
CCLOGERROR("Update vertices with begin = %d, will set begin to 0", begin);
begin = 0;
}
if(count + begin > _vertexNumber)
{
CCLOGERROR("updated vertices exceed the max size of vertex buffer, will set count to _vertexNumber-begin");
count = _vertexNumber - begin;
}
if(isShadowCopyEnabled())
{
memcpy(&_shadowCopy[begin * _sizePerVertex], verts, count * _sizePerVertex);
}
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferSubData(GL_ARRAY_BUFFER, begin * _sizePerVertex, count * _sizePerVertex, verts);
glBindBuffer(GL_ARRAY_BUFFER, 0);
return true;
}
复制代码
上面是VertexBuffer的刷新方法, 绑定对应VBO 使用glsubData类型方法修改VBO缓存中对应区域的数据
#IndexBuffer IndexBuffer 和VertexBuffer实际上功能差不多,但是是用于保存顶点索引缓存的主要用于Mesh等有指定渲染顺序的功能的,它绑定的VBO单独用于保存顶点索引 GL_ELEMENT_ARRAY_BUFFER (并没有在CCVertexIndexData文件中发现IndexData这个类, 可能跟它并不需要使用VertexStreamAttribute类似的结构体的关系吧,虽然这个索引的正确性决定了你最终的渲染结果,可能跟数据量和复杂度有关)