Cocos2dx源码记录(8) CCMaterial, CCTechnique,CCPass

#1Material 前面讲到过Material派生自RenderState类, RenderState保存了一系列的渲染参数, 类似blend混合,stencil模板,depth深度等等. Material == 材质,在3D中是这么翻译的包含了例如法线纹理,漫反射纹理等等解释对象渲染材质的属性,估计在cocos里也是类似的吧 先看看Material的几个静态创建方式

     /**
     * Creates a Material using the data from the Properties object defined at the specified URL,
     * where the URL is of the format "<file-path>.<extension>#<namespace-id>/<namespace-id>/.../<namespace-id>"
     * (and "#<namespace-id>/<namespace-id>/.../<namespace-id>" is optional).
     *
     * @param url The URL pointing to the Properties object defining the material.
     *
     * @return A new Material or NULL if there was an error.
     */
    static Material* createWithFilename(const std::string& path);

    /** Creates a Material with a GLProgramState.
     It will only contain one Technique and one Pass.
     Added in order to support legacy code.
     */
    static Material* createWithGLStateProgram(GLProgramState* programState);

    /**
     * Creates a material from the specified properties object.
     *
     * @param materialProperties The properties object defining the
     *      material (must have namespace equal to 'material').
     * @return A new Material.
     */
    static Material* createWithProperties(Properties* materialProperties);
复制代码

实际上他们都调用了内部的构造方法和init方法

bool Material::initWithGLProgramState(cocos2d::GLProgramState *state)
{
    auto technique = Technique::createWithGLProgramState(this, state);
    if (technique) {
        _techniques.pushBack(technique);

        // weak pointer
        _currentTechnique = technique;

        return true;
    }
    return false;
}

bool Material::initWithFile(const std::string& validfilename)
{
    // Warning: properties is not a "Ref" object, must be manually deleted
    Properties* properties = Properties::createNonRefCounted(validfilename);

    // get the first material
    parseProperties((strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace());

    CC_SAFE_DELETE(properties);
    return true;
}

bool Material::initWithProperties(Properties* materialProperties)
{
    return parseProperties(materialProperties);
}

复制代码

##1.1Technique 我们看到实际上这些函数内部都调用了一些利用其它保存渲染属性或状态的类的对象,其中我们只看过GLProgramState这个类,CCGLProgramState 是存储GLProgram使用到的 Attribute和 Uniform 具体值的类, 额通过GLProgramState创建的technique 我们还不了解,只知道他似乎也是派生自RenderState类的,我们可以简单的看下这个类所拥有的一些成员变量和创建对象的方法

class CC_DLL Technique : public RenderState
{
    friend class Material;
    friend class Renderer;
    friend class Pass;
    friend class MeshCommand;
    friend class Mesh;

public:
    /** Creates a new Technique with a GLProgramState.
     Method added to support legacy code
     */
    static Technique* createWithGLProgramState(Material* parent, GLProgramState* state);
    static Technique* create(Material* parent);

    /** Adds a new pass to the Technique.
     Order matters. First added, first rendered
     */
    void addPass(Pass* pass);

    /** Returns the name of the Technique */
    std::string getName() const;

    /** Returns the Pass at given index */
    Pass* getPassByIndex(ssize_t index) const;

    /** Returns the number of Passes in the Technique */
    ssize_t getPassCount() const;

    /** Returns the list of passes */
    const Vector<Pass*>& getPasses() const;

    /** Returns a new clone of the Technique */
    Technique* clone() const;

protected:
    Technique();
    ~Technique();
    bool init(Material* parent);

    void setName(const std::string& name);

    std::string _name;
    Vector<Pass*> _passes;
};
复制代码

很简单的头文件, 首先看到创建的方式可以通过GLProgramState 或者有parent创建,这里的parent是一个Material类,等有时间感觉要把整个派生关系理清楚啊. 根据对其他渲染框架的理解,一个Pass一般指的是一次渲染的批次,等会再看到关于Pass的时候回对这个类做简要的分析,这里Technique似乎是一个对Pass进行管理的一个类 先看下创建方法的实现

/** Adds a new pass to the Technique.
     Order matters. First added, first rendered
     */
    void addPass(Pass* pass);

    /** Returns the name of the Technique */
    std::string getName() const;

    /** Returns the Pass at given index */
    Pass* getPassByIndex(ssize_t index) const;

    /** Returns the number of Passes in the Technique */
    ssize_t getPassCount() const;

    /** Returns the list of passes */
    const Vector<Pass*>& getPasses() const;

Technique* Technique::createWithGLProgramState(Material* parent, GLProgramState* state)
{
    auto technique = new (std::nothrow) Technique();
    if (technique && technique->init(parent))
    {
        auto pass = Pass::createWithGLProgramState(technique, state);
        technique->addPass(pass);

        technique->autorelease();
        return technique;
    }
    return  nullptr;
}
复制代码

真是的咋就这么错综复杂呢,还是要看pass啊(总感觉这些已经脱离2d的范畴了).看完technique所有的cpp代码,发现这个真的就是一堆Pass的管理类....可以通过GLProgramState对象创建或者Material对象创建(前者可以生成一个Pass) ##1.2Pass 好吧看看Pass到底是啥子

class CC_DLL Pass : public RenderState
{
    friend class Material;

public:
    /** Creates a Pass with a GLProgramState.
     */
    static Pass* createWithGLProgramState(Technique* parent, GLProgramState* programState);

    static Pass* create(Technique* parent);

    /** Returns the GLProgramState */
    GLProgramState* getGLProgramState() const;

    /** Binds the GLProgramState and the RenderState.
     This method must be called before call the actual draw call.
     */
    void bind(const Mat4& modelView);
    void bind(const Mat4& modelView, bool bindAttributes);

    /** Unbinds the Pass.
     This method must be called AFTER calling the actual draw call
     */
    void unbind();

    /**
     * Sets a vertex attribute binding for this pass.
     *
     * When a mesh binding is set, the VertexAttribBinding will be automatically
     * bound when the bind() method is called for the pass.
     *
     * @param binding The VertexAttribBinding to set (or NULL to remove an existing binding).
     */
    void setVertexAttribBinding(VertexAttribBinding* binding);

    /**
     * Returns the vertex attribute binding for this pass.
     *
     * @return The vertex attribute binding for this pass.
     */
    VertexAttribBinding* getVertexAttributeBinding() const;

    uint32_t getHash() const;

    /**
     * Returns a clone (deep-copy) of this instance */
    Pass* clone() const;

protected:
    Pass();
    ~Pass();
    bool init(Technique* parent);
    bool initWithGLProgramState(Technique* parent, GLProgramState *glProgramState);

    void setGLProgramState(GLProgramState* glProgramState);
    Node* getTarget() const;

    GLProgramState* _glProgramState;
    VertexAttribBinding* _vertexAttribBinding;
};

复制代码

似乎是一个Material对象持有一组Technique对象, 一个Technique对象持有一组Pass对象的关系, 一个Pass是一次渲染的状态(问号脸),在这又看到了一个新的类 VertexAttribBinding.....戳记去看看 ###1.2.1VertexAttribBinding

class CC_DLL VertexAttribBinding : public Ref
{
public:

    /**
     * Creates a new VertexAttribBinding between the given MeshVertexData and GLProgramState.
     *
     * If a VertexAttribBinding matching the specified MeshVertexData and GLProgramState already
     * exists, it will be returned. Otherwise, a new VertexAttribBinding will
     * be returned. If OpenGL VAOs are enabled, the a new VAO will be created and
     * stored in the returned VertexAttribBinding, otherwise a client-side
     * array of vertex attribute bindings will be stored.
     *
     * @param mesh The mesh.
     * @param effect The effect.
     * 
     * @return A VertexAttribBinding for the requested parameters.
     */
    static VertexAttribBinding* create(MeshIndexData* meshIndexData, GLProgramState* glProgramState);

    /**
     * Binds this vertex array object.
     */
    void bind();

    /**
     * Unbinds this vertex array object.
     */
    void unbind();

    /**
     * Returns the vertex attrib flags
     */
    uint32_t getVertexAttribsFlags() const;


private:

    bool init(MeshIndexData* meshIndexData, GLProgramState* glProgramState);

    /**
     * Constructor.
     */
    VertexAttribBinding();

    /**
     * Destructor.
     */
    ~VertexAttribBinding();

    /**
     * Hidden copy assignment operator.
     */
    VertexAttribBinding& operator=(const VertexAttribBinding&);

    void setVertexAttribPointer(const std::string& name, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLvoid* pointer);
    VertexAttribValue* getVertexAttribValue(const std::string &name);
    void parseAttributes();


    GLuint _handle;

    MeshIndexData* _meshIndexData;
    GLProgramState* _glProgramState;

    std::unordered_map<std::string, VertexAttribValue> _attributes;
    uint32_t _vertexAttribsFlags;
};
复制代码

好吧看到这里知道了这就是一个3D用到的类用来获取一个模型文件mesh顶点信息的类.....暂时先放着我还没打算看cocos的3d部分(一般性不会好到哪里去) #1.3Properties 既然是3d的我们就快速的看一下,我们发现这里有个很常用的类Properties, 我们有必要搞懂这是个什么东西, 感觉像是一个特殊的数据结构

class CC_DLL Properties
{
public:

    /**
     * Data types supported by the properties class.
     */
    enum Type
    {
        NONE,
        STRING,
        NUMBER,
        VECTOR2,
        VECTOR3,
        VECTOR4,
        MATRIX
    };
   /**
     * Internal structure containing a single property.
     */
    struct Property
    {
        std::string name;
        std::string value;
        Property(const std::string& aname, const std::string& avalue) : name(aname), value(avalue) { }
    };


  ssize_t *_dataIdx;
    Data *_data;

    std::string _namespace;
    std::string _id;
    std::string _parentID;
    std::vector<Property> _properties;
    std::vector<Property>::iterator _propertiesItr;
    std::vector<Properties*> _namespaces;
    std::vector<Properties*>::const_iterator _namespacesItr;
    std::vector<Property>* _variables;
    std::string* _dirPath;
    Properties* _parent;
};

}
复制代码

有点搞懂这个是什么了,这个就是用来做文本解析的最后生成的2叉树结构,每个节点由一个name 和一个value对应, 支持的value类型由Type 枚举决定, 每个子树由一个namespace决定, 整个properties 即一个从特定文本结构解析后获得的被整个cocos都能使用的properties 叉树结构, 所有能使用这个树结构的类自定义方法对其进行解构并按照特定的参数进行生成对应的对象. #1.4Material的parse函数 看到Properties 再去看每个类里的parse函数我们发现其实parse函数就是按照给定的properties 对对应的GLProgramState对象或者RenderState对象进行设置的函数

bool Material::parseUniform(GLProgramState* programState, Properties* properties, const char* uniformName)
{
    bool ret = true;

    auto type = properties->getType(uniformName);

    switch (type) {
        case Properties::Type::NUMBER:
        {
            auto f = properties->getFloat(uniformName);
            programState->setUniformFloat(uniformName, f);
            break;
        }

        case Properties::Type::VECTOR2:
        {
            Vec2 v2;
            properties->getVec2(uniformName, &v2);
            programState->setUniformVec2(uniformName, v2);
            break;
        }

        case Properties::Type::VECTOR3:
        {
            Vec3 v3;
            properties->getVec3(uniformName, &v3);
            programState->setUniformVec3(uniformName, v3);
            break;
        }

        case Properties::Type::VECTOR4:
        {
            Vec4 v4;
            properties->getVec4(uniformName, &v4);
            programState->setUniformVec4(uniformName, v4);
            break;
        }

        case Properties::Type::MATRIX:
        {
            Mat4 m4;
            properties->getMat4(uniformName, &m4);
            programState->setUniformMat4(uniformName, m4);
            break;
        }

        case Properties::Type::STRING:
        default:
        {
            // Assume this is a parameter auto-binding.
            programState->setParameterAutoBinding(uniformName, properties->getString());
            break;
        }
    }
    return ret;
}


bool Material::parseRenderState(RenderState* renderState, Properties* properties)
{
    auto state = renderState->getStateBlock();

    auto property = properties->getNextProperty();
    while (property)
    {
        // Parse uniforms only if the GLProgramState was created
        // Render state only can have "strings" or numbers as values. No new namespaces
        state->setState(property, properties->getString(property));

        property = properties->getNextProperty();
    }

    return true;
}
-
复制代码

因为暂时不关心3d的渲染,所以这里先将MeshCommand放到一边. .1首先我们搞清楚了Properties的实质, 将类似XML的文本解析成中间Model类的对象, .2Material -> Technique->Pass->VertexAttribBinding->MeshData的关系

下一个我们会先看QuadCommand类,然后直捣黄龙,看那个最基本的Renderer类

转载于:https://juejin.im/post/5a30dd48f265da430f32169f

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值