모델 정보(Java)

업데이트: 2023/01/26

모델 정보 편집에 대하여

모델 정보는 기본적으로 Cubism Editor의 모델 워크 스페이스에서 생성됩니다.
파라미터에 대한 정점 등의 움직임은 .moc3 파일에 기록됩니다.
그 외의 물리 연산이나 아트메쉬에 붙일 수 있는 유저 데이터 등은 다른 파일로서 출력되는데, 모델에 대한 모든 파일 참조를 기록하는 것이 .model3.json 파일입니다.

이들은 .moc3 파일을 출력할 때 동시에 출력할 수 있습니다. 「임베디드용 데이터 내보내기」
또한 Cubism Viewer(for OW)를 사용하여 모션, 표정 파일, 포즈 파일의 임베디드 설정을 추가할 수 있습니다.

Framework를 사용하여 .model3.json 파일에서 로드

Framework를 이용한 로드에서는 모델에 필요한 정보를 .model3.json 파일에서 추출하고, CubismUserModel 클래스를 상속한 인스턴스를 정비하고 이용하는 것을 상정하고 있습니다.

// Java
final String dir = "example/";
final String fileName = "example.model3.json";
final String jsonpath = dir + fileName;

byte[] buffer = createBuffer(jsonpath);
ICubismModelSetting setting = new CubismModelSettingJson(buffer);

ICubismModelSetting 클래스로 추출한 각 요소는 CubismUserModel.load~~ 계열 함수로 로드할 수 있습니다.

// Java
// Cubism Model
if (setting.getModelFileName() == ""){
    String path = setting.getModelFileName();
    path = dir + path;
  
    if (debugMode){
        LAppPal.printLog("[APP]create model" + setting.getModelFileName());
    }
  
    byte[] buffer = createBuffer(path);
    loadModel(buffer);
}

.model3.json 파일로부터의 전체 로드 흐름은 샘플의 LAppmodel.loadAssets 함수에서 다음 함수의 흐름을 따라가면 파악하기 쉽습니다.

  • LAppModel.setupModel 함수
  • CubismUserModel.createRenderer 함수
  • LAppModel.setupTextures 함수

인스턴스 생성(.moc3 파일 로드)

먼저 .moc3 파일을 메모리에 로드합니다.
읽은 버퍼를 CubismMoc.create 함수에 전달하고 먼저 CubismMoc 인스턴스를 만듭니다.
그런 다음 CubismMoc.createModel 함수를 호출하여 CubismModel 인스턴스를 만듭니다.
이 CubismModel 인스턴스로부터 파라미터의 조작이나 draw를 위한 정보 취득 등을 실시합니다.

CubismMoc.createModel 함수는 CubismMoc 내부에서 함수에 의해 생성된 Model 수를 세고 있으며, CubismMoc을 파기할 때는 그 CubismMoc에서 생성한 CubismModel을 모두 파기해 둘 필요가 있습니다.

// Java
String path = "example.moc3";
path = dir + path;

byte[] buffer = createBuffer(path);
CubismMoc moc = CubismMoc.create(buffer);
CubismModel model = moc.createModel();

그래픽 환경 연결

Framework는 모델의 텍스쳐 정보를 그래픽 API에 의존하지 않기 위해 CubismRenderer 클래스의 파생 클래스를 사용합니다.
모델과 관련된 그래픽 관련 정보는 모두 CubismRenderer 클래스의 파생 클래스에서 관리합니다.
SDK for Java R1 alpha1 시점에서는 Android에만 대응하고 있기 때문에 파생 클래스가 관리할 필요는 없지만, 장래의 그래픽 API 추가 가능성 및 기존 SDK와의 사양 통일 면을 고려해 이러한 사양으로 했습니다.

먼저 생성하고 싶은 그래픽 환경의 종류를 RendererType 열거형으로 지정해, CubismUserModel.createRenderer 함수의 인수로 하여 호출합니다.
(SDK for Java R1 alpha1에서는 Android에만 대응하고 있습니다.)
createRenderer 함수 내부에서는 인수에 대응하는 그래픽 API에 대한 파생 클래스를 생성하고 CubismRenderer.initialize 함수로 CubismModel 인스턴스를 등록하여 CubismRenderer 인스턴스와 CubismModel 인스턴스를 연결합니다.

// Java
public void setupRenderer(CubismRenderer renderer, int maskBufferCount) {
    this.renderer = renderer;
 
    this.renderer.initialize(model, maskBufferCount);
}

텍스쳐 연결

Framework에서 모델이 가지는 텍스쳐는 CubismRenderer 클래스의 파생 클래스가 관리합니다.
Android OpenGL ES 2.0의 처리에서는 CubismRenderer 클래스의 파생 클래스인 CubismRendererAndroid 클래스 내의 CubismRendererAndroid.bindTexture 함수를 사용해 등록하고 있습니다.
첫 번째 인수는 모델의 텍스쳐 번호, Editor에서는 텍스쳐 아틀라스의 번호로 확인할 수 있습니다.
두 번째 인수는 텍스쳐 OpenGL ES 2.0의 관리 번호입니다.

// Java
// Android OpenGL ES 2.0의 텍스쳐 유닛에 텍스쳐 로드
String texturePath = modelSetting.getTextureFileName(modelTextureNumber);
texturepath = modelHomeDir + texturePath;
LAppTextureManager.textureInfo texture = LAppDelegate.getInstance().getTextureManager().createTextureFromPngFile(texturePath);
final int glTextureNumber = texture.id;

this.<CubismRendererAndroid>getRenderer().bindTexture(modelTextureNumber, glTextureNumber);

표시 위치와 크기 지정

여기까지의 설정을 실시하면 모델을 그릴 수는 있지만 많을 경우 표시 위치나 축척이 너무 달라 그대로는 화면에 표시되지 않습니다.
CubismModel.getDrawableVertexPositions 함수로 반환되는 정점 범위에 대해서는 「DrawableVertexPositions 범위」를 참조하십시오.
크기를 조정하려면 CubismModelMatrix 클래스와 CubismModel.getCanvasWidth 함수, CubismModel.getCanvasHeight 함수를 사용합니다.

// Java
// modelMatrix는 LAppModel 클래스 내에 CubismModelMatrix 형식으로 정의
modelMatrix = CubismModelMatrix.create(model.getCanvasWidth(), model.getCanvasHeight());

이 행렬은 그리기 전에 Projection 행렬에 곱해지고 MVP 행렬로서 렌더러에 전달됩니다.

// Java
public void onUpdate() {
    int width = LAppDelegate.getInstance().getWindowWidth();
    int height = LAppDelegate.getInstance().getWindowHeight();
    ...
    CubismMatrix4x4 projectionMatrix = CubismMatrix4x4.create();
    ...
    projectionMatrix.scale(1.0f, (float) height / (float) width);
    ...
    model.draw(projectionMatrix);
}
// Java
public void draw(CubismMatrix4x4 matrix) {
    ...
    matrix.multiplyByMatrix(modelMatrix);
    this.<CubismRendererAndroid>getRenderer().setMvpMatrix(matrix);
    ...
}

정점 업데이트

CubismModel 인스턴스에 대한 파라미터 조작을 아트메쉬의 정점에 반영하기 위해 CubismModel.update 함수를 실행합니다.

// Java)
model.update()

그리기

그리기는 CubismModel 인스턴스에서는 실행하지 않고 연결된 렌더러에 명령하여 실시합니다.

// Java
this.<CubismRendererAndroid>getRenderer.drawModel();

파기

인스턴스를 파기하려면 모든 CubismModel을 파기한 다음 CubismMoc을 파기해야 합니다.
이 순서를 지키기 위해, CubismModel의 파기는 CubismMoc.deleteModel 함수로 삭제합니다.
이 함수를 경유하지 않을 경우 CubismMoc 내부에서 확인하고 있는 모델의 수가 일치하지 않기 때문에 경고가 나옵니다.

// Java
protected void delete() {
    if (moc == null || model == null) {
        return;
    }
    moc.deleteModel(model);

    moc.delete();
    model.close();
    renderer.close();

    moc = null;
    model = null;
    renderer = null;
}
// Java
public void delete() {
    assert (modelCount == 0);
    if (moc ! = null) {
        moc.close();
    }
    moc = null;
}

public void deleteModel(CubismModel model) {
    model.close();
    modelCount--;
}

CubismModel 클래스에서 모델에 존재하지 않는 파라미터 ID 사용

CubismModel 클래스의 파라미터, 파츠 불투명도의 조작에서는 .moc 파일에 존재하지 않는 ID에서도 취급을 실시하는 기능이 있습니다.
이 기능은 CubismMotion 클래스, CubismPose 클래스 등이 이용하고 있으며, 이용해서 새로운 기구를 작성할 때에는 기존의 기능과 충돌하지 않도록 사용하는 ID에 주의해 주세요.
또한 Framework를 읽을 때 작성된 파라미터를 사용하여 다른 기능과 연동할 가능성에 유의하십시오.
※존재하지 않는 최대치, 최소치, 초기치에 대한 액세스는 오류가 발생합니다

파라미터 ID로부터 파라미터 Index를 생성할 때 존재하지 않는 파라미터는 신설된다

// Java
public int getParameterIndex(CubismId parameterId) {
    final CubismParameterView parameterView = model.findParameterView(parameterId.getString());
    if (parameterView ! = null) {
        return parameterView.getIndex();
    }

    // If the parameter does not exist in the model, it searches for it in the non-existent parameter ID list and returns its index.
    if (notExistParameterIds.containsKey(parameterId)) {
        final Integer index = notExistParameterIds.get(parameterId);
        assert index ! = null;
        return index;
    }

    // If the parameter does not exist in the non-existent parameter ID list, add newly the element.
    final int parameterCount = parameterValues.length;
    final int parameterIndex = parameterCount + notExistParameterIds.size();
    notExistParameterIds.put(parameterId, parameterIndex);
    notExistParameterIndices.add(parameterIndex);

    float[] tmp = new float[notExistParameterIndices.size()];
    System.arraycopy(notExistParameterValues, 0, tmp, 0, notExistParameterIndices.size() - 1);
    tmp[notExistParameterIndices.size() - 1] = 0.0f;
    notExistParameterValues = new float[notExistParameterIndices.size()];
    System.arraycopy(tmp, 0, notExistParameterValues, 0, notExistParameterIndices.size());

    return parameterIndex;
}
이 기사가 도움이 되었나요?
아니요
이 기사에 관한 의견 및 요청사항을 보내 주시기 바랍니다.