关于模型(Native)

最終更新: 2019年11月7日

关于编辑模型信息

模型信息基本上由Modeler创建。
.moc3文件中记录了相对于参数的顶点等动作。
附加到其他物理模拟、图形网格的用户数据等作为单独的文件输出,
.model3.json文件记录模型相关的所有文件参考。

从Modeler输出.moc3文件时,可以同时输出。“输出嵌入数据”
您还可以使用Cubism Viewer(for OW)追加动态、表情文件和姿势文件的内置设置。

使用Framework从.model3.json文件导入

使用Framework导入时,从.model3.json文件中提取模型所需的信息,
然后考虑将维护和使用继承CubismUserModel类的副本。

// C++
const csmChar* dir = "example/";
const csmChar* fileName = "example.model3.json";
const csmString jsonpath = csmString(dir) + fileName;
csmSizeInt size;
csmByte* buffer = CreateBuffer(jsonpath.GetRawString(), &size);
ICubismModelSetting* setting = new CubismModelSettingJson(buffer, size);
DeleteBuffer(buffer, jsonpath.GetRawString());

ICubismModelSetting类中提取的各元素都可以通过CubismUserModel::Load~~系函数导入。

// C++
    csmSizeInt size;
    //Cubism Model
    if (strcmp(setting->GetModelFileName(), "") != 0)
    {
        csmString path = setting->GetModelFileName();
        path = dir + path;

        if (_debugMode)LAppPal::PrintLog("[APP]create model: %s", setting->GetModelFileName());

        csmByte* buffer = CreateBuffer(path.GetRawString(), &size);
        LoadModel(buffer, size);
        DeleteBuffer(buffer, path.GetRawString());

    }

.model3.json文件开始的全体读取流程按照范例中的LAppModel::LoadAssets函数
到LAppModel::SetupModel函数、CubismUserModel::CreateRenderer函数、LAppModel::SetupTextures函数的流程将会容易理解。


创建副本(导入.moc3文件)

首先,将.moc3文件导入到内存记忆中。
将导入缓冲区和大小传递给CubismMoc::Create函数,首先创建一个CubismMoc副本。
然后调用CubismMoc::CreateModel函数来创建一个CubismModel副本。
从这个CubismModel副本中,您可以操作参数并获取绘图信息等。

CubismMoc::CreateModel函数计算CubismMoc内部函数生成的Model数量,
放弃CubismMoc时,您需要放弃从CubismMoc生成的所有CubismModel。

// C++
csmString path = "example.moc3";
path = dir + path;
csmSizeInt size;
csmByte* buffer = CreateBuffer(path.GetRawString(), &size);
CubismMoc* moc = CubismMoc::Create(buffer, size);
CubismModel* model = _moc->CreateModel();

图形环境关联

Framework使用从CubismRenderer类派生的类,以便模型的纹理信息不依赖于图形API。
所有与模型相关的图形相关信息都由CubismRenderer类的派生类管理。
从CubismRenderer类中生成图形API的派生类,
并通过使用CubismRenderer::Initialize函数注册CubismModel副本,关联CubismRenderer副本和CubismModel副本。

// C++
Rendering::CubismRenderer* renderer = Rendering::CubismRenderer::Create();

renderer->Initialize(model);

纹理关联

Framework中模型的纹理由CubismRenderer类的派生类管理。
但是,该方法没有在CubismRenderer类中注册,因为该功能避免了对图形API的依赖。
请注意,方法规格会根据对象图形API的不同而有所不同。
在OpenGL处理中,使用CubismRenderer类的派生CubismRenderer_OpenGLES2类中的CubismRenderer_OpenGLES2::BindTexture函数进行注册。
第一个参数可以通过模型纹理编号和Editor上的纹理集编号来确认。
第二个参数是纹理在OpenGL中的管理编号。

下面的例子是在Cocos2d-x中导入纹理。

// C++
// 将纹理读取到OpenGL纹理单元中
csmInt32 modelTextureNumber = 0;
csmString texturePath = "example.2048/texture_00.png";
texturePath = dir + texturePath;

//cocos2d
Texture2D* texture = Director::getInstance()->getTextureCache()->addImage(std::string(texturePath.GetRawString()));
const csmInt32 glTextureNumber = texture->getName();
const Texture2D::TexParams texParams = { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE };
texture->setTexParameters(texParams);
texture->generateMipmap();

//OpenGL
GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->BindTexture(modelTextureNumber, glTextureNumber);

不使用Cocos2d-x管理Texture,且单独使用OpenGL的情况下,通过应用程序端的管理进行注册。

// C++
// 将纹理读取到OpenGL纹理单元中
csmString texturePath = _modelSetting->GetTextureFileName(modelTextureNumber);
texturePath = _modelHomeDir + texturePath;

LAppTextureManager::TextureInfo* texture = LAppDelegate::GetInstance()->GetTextureManager()->CreateTextureFromPngFile(texturePath.GetRawString());
const csmInt32 glTextureNumber = texture->id;

//OpenGL
GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->BindTexture(modelTextureNumber, glTextureNumber);

指定显示位置和大小

您可以通过到目前为止的设置绘制模型,
但在很多情况下,显示位置和比例尺相差太大,无法在画面上显示。
有关csmGetDrawableVertexPositions函数返回的顶点范围,请参考“DrawableVertexPositions范围”
使用CubismModelMatrix类、CubismModel::GetCanvasWidth函数和CubismModel::GetCanvasHeight函数来调整大小。

// C++
CubismModelMatrix* modelMatrix = CSM_NEW CubismModelMatrix(_model->GetCanvasWidth(), _model->GetCanvasHeight());

这个矩阵在绘制前乘以Projection矩阵,作为MVP矩阵传递给渲染器。

// C++
CubismMatrix44 projectionMatrix;
projectionMatrix.Scale(1, window.width / window.height);
projectionMatrix.MultiplyByMatrix(modelMatrix);

GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->SetMvpMatrix(&projectionMatrix);

GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->DrawModel();

顶点更新

执行CubismModel::Update函数,将CubismModel副本相对的参数操作应用在图形网格的顶点上。

// C++
model->Update();

绘制

绘制不是从CubismModel副本执行的,而是被指示给关联的渲染器。

// C++
CubismMatrix44 projectionMatrix;
projectionMatrix.Scale(1, window.width / window.height);
projectionMatrix.MultiplyByMatrix(modelMatrix);

GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->SetMvpMatrix(&projectionMatrix);

GetRenderer<Rendering::CubismRenderer_OpenGLES2>()->DrawModel();

放弃

放弃副本需要在放弃所有CubismlModel后,放弃CubismMoc。
要保持此顺序,请使用CubismMoc::DeleteModel删除来放弃CubismModel。
如果您不经由该函数,由于CubismMoc内部确认的模型数量不匹配,您将收到警告。

// C++
CubismUserModel::~CubismUserModel()
{
    CSM_DELETE(_motionManager);
    CSM_DELETE(_expressionManager);
    _moc->DeleteModel(_model); // <<<
    CubismMoc::Delete(_moc); // <<<
    CSM_DELETE(_modelMatrix);
    CubismPose::Delete(_pose);
    CubismEyeBlink::Delete(_eyeBlink);
    CubismBreath::Delete(_breath);
    CSM_DELETE(_dragManager);
    CubismPhysics::Delete(_physics);
    CubismModelUserData::Delete(_modelUserData);

    DeleteRenderer();
}
// C++
CubismMoc::~CubismMoc()
{
    CSM_ASSERT(_modelCount == 0);

    CSM_FREE_ALLIGNED(_moc);
}

void CubismMoc::DeleteModel(CubismModel* model)
{
    CSM_DELETE_SELF(CubismModel, model);
    --_modelCount;
}

在CubismModel类中使用模型中不存在的参数ID

在CubismModel类的参数和部件不透明度的操作中,可以处理.moc3文件中不存在ID的功能。
该功能被CubismMotion类、CubismPose类等使用,
使用它创建新结构时,请注意您使用的ID,避免与现有功能冲突。
另外,请注意使用解读Framework时也会创建的参数与其他功能联动的可能性。
* 访问不存在的最大值、最小值和初始值时会出现错误。

// C++
csmInt32 CubismModel::GetParameterIndex(CubismIdHandle parameterId)
{
    csmInt32            parameterIndex;
    const csmChar**     idArray = Core::csmGetParameterIds(_model);
    csmInt32            idCount = Core::csmGetParameterCount(_model);


    for (parameterIndex = 0; parameterIndex < idCount; ++parameterIndex)
    {
        if (parameterId != _parameterIds[parameterIndex])
        {
            continue;
        }

        return parameterIndex;
    }

    // 如果模型中不存在,则搜索不存在的参数ID列表并返回其索引
    if (_notExistParameterId.IsExist(parameterId))
    {
        return _notExistParameterId[parameterId];
    }

    // 如果不存在的参数ID列表中没有,则追加一个新元素
    parameterIndex = Core::csmGetParameterCount(_model) + _notExistParameterId.GetSize();

    _notExistParameterId[parameterId] = parameterIndex;
    _notExistParameterValues.AppendKey(parameterIndex);

    return parameterIndex;
}
关于本报道,敬请提出您的意见及要求。