mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 18:56:16 +03:00
768 lines
19 KiB
C++
768 lines
19 KiB
C++
#include "Pch.h"
|
|
#include "PMXComponent.h"
|
|
|
|
// TODO: Optimize and clean me, this is a temp version code.
|
|
#include "AssetSystem/TextureManager.h"
|
|
#include "Engine.h"
|
|
#include "AssetSystem/AssetSystem.h"
|
|
#include "AssetSystem/AsyncUploader.h"
|
|
#include <Saba/Base/Path.h>
|
|
#include <Saba/Base/File.h>
|
|
#include <Saba/Base/UnicodeUtil.h>
|
|
#include <Saba/Base/Time.h>
|
|
#include "../../Renderer/RendererInterface.h"
|
|
#include "../SceneArchive.h"
|
|
|
|
#include "../../Renderer/ShadingModel.h"
|
|
|
|
// NOTE: MMD asset is free but no MIT license.
|
|
// So reading every time from raw asset.
|
|
namespace Flower
|
|
{
|
|
void PMXMeshProxy::release()
|
|
{
|
|
vkDeviceWaitIdle(RHI::Device);
|
|
|
|
m_mmdModel.reset();
|
|
m_vmdAnim.reset();
|
|
m_indexBuffer.reset();
|
|
m_vertexBuffer.reset();
|
|
m_stageBuffer.reset();
|
|
}
|
|
|
|
bool PMXMeshProxy::prepareVMD()
|
|
{
|
|
auto vmdAnim = std::make_unique<saba::VMDAnimation>();
|
|
if (!vmdAnim->Create(m_mmdModel))
|
|
{
|
|
LOG_ERROR("Failed to create VMDAnimation.");
|
|
return false;
|
|
}
|
|
|
|
bool bExistOneVmd = false;
|
|
for (const auto& vmdPath : m_vmdPath)
|
|
{
|
|
saba::VMDFile vmdFile;
|
|
if (!saba::ReadVMDFile(&vmdFile, vmdPath.c_str()))
|
|
{
|
|
LOG_ERROR("Failed to read VMD file {0}.", vmdPath);
|
|
return false;
|
|
}
|
|
|
|
if (!vmdAnim->Add(vmdFile))
|
|
{
|
|
LOG_ERROR("Failed to add VMDAnimation {0}.", vmdPath);
|
|
return false;
|
|
}
|
|
|
|
bExistOneVmd = true;
|
|
if (!vmdFile.m_cameras.empty())
|
|
{
|
|
LOG_ERROR("You can't use camera as pmx vmd {0}.", vmdPath);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
vmdAnim->SyncPhysics(0.0f);
|
|
m_vmdAnim = std::move(vmdAnim);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool PMXMeshProxy::preparePMX()
|
|
{
|
|
auto ext = saba::PathUtil::GetExt(m_pmxPath);
|
|
if (ext != "pmx")
|
|
{
|
|
LOG_ERROR("Must select one pmx file.");
|
|
return false;
|
|
}
|
|
|
|
auto pmxModel = std::make_unique<saba::PMXModel>();
|
|
|
|
std::string resourceDir = saba::PathUtil::GetExecutablePath();
|
|
resourceDir = saba::PathUtil::GetDirectoryName(resourceDir);
|
|
resourceDir = saba::PathUtil::Combine(resourceDir, "media");
|
|
std::string mmdDir = saba::PathUtil::Combine(resourceDir, "mmd");
|
|
|
|
if (!pmxModel->Load(m_pmxPath, mmdDir))
|
|
{
|
|
LOG_ERROR("Failed to load pmx file {0}.", m_pmxPath);
|
|
return false;
|
|
}
|
|
|
|
m_mmdModel = std::move(pmxModel);
|
|
m_mmdModel->InitializeAnimation();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool PMXMeshProxy::prepareMaterial()
|
|
{
|
|
// prepare material and upload texture to bindless descriptor set here.
|
|
size_t matCount = m_mmdModel->GetMaterialCount();
|
|
|
|
const saba::MMDMaterial* materials = m_mmdModel->GetMaterials();
|
|
|
|
// PMX material can keep same name, so can't simple use set and map.
|
|
// Update materials from pmx file.
|
|
m_component->m_materials.reserve(std::max(m_component->m_materials.size(), matCount));
|
|
for (size_t i = 0; i < matCount; i++)
|
|
{
|
|
if (m_component->m_materials.size() <= i)
|
|
{
|
|
m_component->m_materials.push_back(PMXDrawMaterial{ .material = materials[i] });
|
|
|
|
m_component->m_materials[i].bTranslucent = m_component->m_materials[i].material.m_alpha < 0.999f;
|
|
|
|
}
|
|
else
|
|
{
|
|
m_component->m_materials[i].material = materials[i];
|
|
}
|
|
}
|
|
|
|
|
|
std::set<std::string> texLoaded{};
|
|
|
|
// Load all material's texture.
|
|
|
|
auto isFileExist = [](const std::string& path)
|
|
{
|
|
return std::filesystem::exists(path) && !std::filesystem::is_directory(path);
|
|
};
|
|
|
|
for (size_t i = 0; i < matCount; i++)
|
|
{
|
|
saba::MMDMaterial matMMD = materials[i];
|
|
auto& workingMat = m_component->m_materials.at(i);
|
|
|
|
CHECK(workingMat.material.m_name == matMMD.m_name);
|
|
CHECK(workingMat.material.m_enName == matMMD.m_enName);
|
|
|
|
// texture.
|
|
if (!matMMD.m_texture.empty() && isFileExist(matMMD.m_texture)
|
|
&& !texLoaded.contains(matMMD.m_texture) && !TextureManager::get()->isAssetExist(matMMD.m_texture))
|
|
{
|
|
auto task = RawAssetTextureLoadTask::build(
|
|
matMMD.m_texture, //
|
|
matMMD.m_texture, // UUID use path here.
|
|
VK_FORMAT_R8G8B8A8_SRGB);
|
|
GEngine->getRuntimeModule<AssetSystem>()->addUploadTask(task);
|
|
|
|
texLoaded.insert(matMMD.m_texture);
|
|
}
|
|
|
|
// Sp texture.
|
|
if (!matMMD.m_spTexture.empty() && isFileExist(matMMD.m_spTexture)
|
|
&& !texLoaded.contains(matMMD.m_spTexture) && !TextureManager::get()->isAssetExist(matMMD.m_spTexture))
|
|
{
|
|
auto task = RawAssetTextureLoadTask::build(
|
|
matMMD.m_spTexture,
|
|
matMMD.m_spTexture, // UUID use path here.
|
|
VK_FORMAT_R8G8B8A8_SRGB);
|
|
GEngine->getRuntimeModule<AssetSystem>()->addUploadTask(task);
|
|
|
|
texLoaded.insert(matMMD.m_spTexture);
|
|
}
|
|
|
|
// toon texture.
|
|
if (!matMMD.m_toonTexture.empty() && isFileExist(matMMD.m_toonTexture)
|
|
&& !texLoaded.contains(matMMD.m_toonTexture) && !TextureManager::get()->isAssetExist(matMMD.m_toonTexture))
|
|
{
|
|
auto task = RawAssetTextureLoadTask::build(
|
|
matMMD.m_toonTexture,
|
|
matMMD.m_toonTexture, // UUID use path here.
|
|
VK_FORMAT_R8G8B8A8_SRGB);
|
|
GEngine->getRuntimeModule<AssetSystem>()->addUploadTask(task);
|
|
|
|
texLoaded.insert(matMMD.m_toonTexture);
|
|
}
|
|
}
|
|
|
|
GEngine->getRuntimeModule<AssetSystem>()->flushUploadTask();
|
|
|
|
for (size_t i = 0; i < matCount; i++)
|
|
{
|
|
saba::MMDMaterial matMMD = materials[i];
|
|
auto& workingMat = m_component->m_materials.at(i);
|
|
|
|
CHECK(workingMat.material.m_name == matMMD.m_name);
|
|
CHECK(workingMat.material.m_enName == matMMD.m_enName);
|
|
|
|
const uint32_t fallbackWhite = TextureManager::get()->getImage(EngineTextures::GWhiteTextureUUID).get()->getBindlessIndex();
|
|
|
|
// texture.
|
|
if (!matMMD.m_texture.empty() && isFileExist(matMMD.m_texture))
|
|
{
|
|
workingMat.mmdTex = TextureManager::get()->getImage(matMMD.m_texture).get()->getBindlessIndex();
|
|
}
|
|
else
|
|
{
|
|
LOG_WARN("Lose tex {} in material {}, use fallback white.", matMMD.m_texture, matMMD.m_name);
|
|
workingMat.mmdTex = fallbackWhite;
|
|
}
|
|
|
|
// Sp texture.
|
|
if (!matMMD.m_spTexture.empty() && isFileExist(matMMD.m_spTexture))
|
|
{
|
|
workingMat.mmdSphereTex = TextureManager::get()->getImage(matMMD.m_spTexture).get()->getBindlessIndex();
|
|
}
|
|
else
|
|
{
|
|
LOG_WARN("Lose sp tex {} in material {}, use fallback white.", matMMD.m_spTexture, matMMD.m_name);
|
|
workingMat.mmdSphereTex = ~0;
|
|
}
|
|
|
|
// toon texture.
|
|
if (!matMMD.m_toonTexture.empty() && isFileExist(matMMD.m_toonTexture))
|
|
{
|
|
workingMat.mmdToonTex = TextureManager::get()->getImage(matMMD.m_toonTexture).get()->getBindlessIndex();
|
|
}
|
|
else
|
|
{
|
|
LOG_WARN("Lose toon tex {} in material {}, use fallback white.", matMMD.m_toonTexture, matMMD.m_name);
|
|
workingMat.mmdToonTex = ~0;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool PMXMeshProxy::prepareVertexBuffer()
|
|
{
|
|
auto bufferFlagBasic = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
|
VmaAllocationCreateFlags bufferFlagVMA = {};
|
|
|
|
auto vbMemSize = uint32_t(sizeof(Vertex) * m_mmdModel->GetVertexCount());
|
|
m_vertexBuffer = VulkanBuffer::create2(
|
|
m_pmxPath.c_str(),
|
|
bufferFlagBasic | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
bufferFlagVMA,
|
|
vbMemSize
|
|
);
|
|
|
|
m_stageBuffer = VulkanBuffer::create(
|
|
"CopyBuffer",
|
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
|
EVMAUsageFlags::StageCopyForUpload,
|
|
vbMemSize
|
|
);
|
|
|
|
// Index Buffer
|
|
{
|
|
if (m_mmdModel->GetIndexElementSize() == 1)
|
|
{
|
|
LOG_ERROR("Vulkan is not supported uint8_t index.");
|
|
return false;
|
|
}
|
|
else if (m_mmdModel->GetIndexElementSize() == 2)
|
|
{
|
|
m_indexType = VK_INDEX_TYPE_UINT16;
|
|
}
|
|
else if (m_mmdModel->GetIndexElementSize() == 4)
|
|
{
|
|
m_indexType = VK_INDEX_TYPE_UINT32;
|
|
}
|
|
else
|
|
{
|
|
LOG_ERROR("Unknown index size.[{0}].", m_mmdModel->GetIndexElementSize());
|
|
return false;
|
|
}
|
|
|
|
// Create buffer
|
|
auto ibMemSize = uint32_t(m_mmdModel->GetIndexElementSize() * m_mmdModel->GetIndexCount());
|
|
m_indexBuffer = VulkanBuffer::create2(
|
|
m_pmxPath.c_str(),
|
|
bufferFlagBasic | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
bufferFlagVMA,
|
|
ibMemSize
|
|
);
|
|
|
|
// Copy index to GPU.
|
|
|
|
auto stageBuffer = VulkanBuffer::create(
|
|
"CopyBuffer",
|
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
|
EVMAUsageFlags::StageCopyForUpload,
|
|
ibMemSize,
|
|
const_cast<void*>(m_mmdModel->GetIndices())
|
|
);
|
|
|
|
m_indexBuffer->stageCopyFrom(
|
|
stageBuffer->getVkBuffer(),
|
|
ibMemSize,
|
|
0,
|
|
0
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void PMXMeshProxy::UpdateAnimation(float vmdFrameTime, float physicElapsed)
|
|
{
|
|
m_mmdModel->BeginAnimation();
|
|
m_mmdModel->UpdateAllAnimation(m_vmdAnim.get(), vmdFrameTime * 30.0f, physicElapsed);
|
|
m_mmdModel->EndAnimation();
|
|
}
|
|
|
|
PMXMeshProxy::PMXMeshProxy(PMXComponent* InComp)
|
|
: m_component(InComp)
|
|
{
|
|
}
|
|
|
|
bool PMXMeshProxy::Ready()
|
|
{
|
|
return
|
|
m_mmdModel &&
|
|
m_vmdAnim &&
|
|
m_vertexBuffer &&
|
|
m_indexBuffer &&
|
|
m_stageBuffer;
|
|
}
|
|
|
|
// TODO: Can optimize.
|
|
void PMXMeshProxy::UpdateVertex(VkCommandBuffer cmd)
|
|
{
|
|
size_t vtxCount = m_mmdModel->GetVertexCount();
|
|
|
|
std::vector<glm::vec3> positionLast = m_mmdModel->getUpdatePositions();
|
|
m_mmdModel->Update();
|
|
const glm::vec3* position = m_mmdModel->GetUpdatePositions();
|
|
const glm::vec3* normal = m_mmdModel->GetUpdateNormals();
|
|
const glm::vec2* uv = m_mmdModel->GetUpdateUVs();
|
|
|
|
glm::vec3* positionLastPtr = &positionLast[0];
|
|
// Update vertices
|
|
|
|
auto bufferSize = VkDeviceSize(sizeof(Vertex) * vtxCount);
|
|
|
|
// copy vertex buffer gpu.
|
|
m_stageBuffer->map();
|
|
{
|
|
void* vbStMem = m_stageBuffer->mapped;
|
|
auto v = static_cast<Vertex*>(vbStMem);
|
|
for (size_t i = 0; i < vtxCount; i++)
|
|
{
|
|
v->position = *position;
|
|
v->normal = *normal;
|
|
v->uv = *uv;
|
|
v->positionLast = *positionLastPtr;
|
|
v++;
|
|
position++;
|
|
normal++;
|
|
uv++;
|
|
positionLastPtr++;
|
|
}
|
|
}
|
|
m_stageBuffer->unmap();
|
|
|
|
// copy to gpu
|
|
VkBufferCopy copyRegion{};
|
|
copyRegion.srcOffset = 0;
|
|
copyRegion.dstOffset = 0;
|
|
copyRegion.size = bufferSize;
|
|
vkCmdCopyBuffer(cmd, m_stageBuffer->getVkBuffer(), m_vertexBuffer->getVkBuffer(), 1, ©Region);
|
|
}
|
|
|
|
void PMXMeshProxy::OnRenderTick(VkCommandBuffer cmd)
|
|
{
|
|
if (!Ready()) return;
|
|
UpdateVertex(cmd);
|
|
}
|
|
|
|
void PMXMeshProxy::Setup(PMXInitTrait initTrait)
|
|
{
|
|
m_pmxPath = initTrait.pmxPath;
|
|
m_vmdPath = initTrait.vmdPath;
|
|
release();
|
|
|
|
preparePMX();
|
|
prepareVMD();
|
|
prepareMaterial();
|
|
prepareVertexBuffer();
|
|
|
|
CHECK(Ready());
|
|
}
|
|
|
|
void PMXMeshProxy::SetupCamera(std::string cameraPath)
|
|
{
|
|
m_cameraPath = cameraPath;
|
|
vmdCameraAnim.reset();
|
|
|
|
saba::VMDFile vmdFile;
|
|
if (!saba::ReadVMDFile(&vmdFile, cameraPath.c_str()))
|
|
{
|
|
LOG_ERROR("Failed to read VMD file {0}.", cameraPath);
|
|
return;
|
|
}
|
|
if (vmdFile.m_cameras.empty())
|
|
{
|
|
LOG_ERROR("Vmd file {0} no contain camera.", cameraPath);
|
|
return;
|
|
}
|
|
|
|
vmdCameraAnim = std::make_unique<saba::VMDCameraAnimation>();
|
|
if (!vmdCameraAnim->Create(vmdFile))
|
|
{
|
|
LOG_ERROR("Failed to create VMDCameraAnimation.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
void PMXMeshProxy::OnSceneTick(float vmdFrameTime, float physicElapsed)
|
|
{
|
|
if (!Ready()) return;
|
|
UpdateAnimation(vmdFrameTime, physicElapsed);
|
|
m_currentFrameCameraData = {};
|
|
|
|
// updata camera data.
|
|
if (vmdCameraAnim)
|
|
{
|
|
m_currentFrameCameraData.bValidData = true;
|
|
vmdCameraAnim->Evaluate(vmdFrameTime * 30.0f);
|
|
}
|
|
}
|
|
|
|
PerFrameMMDCamera PMXMeshProxy::GetCurrentFrameCameraData(float width, float height, float zNear, float zFar, glm::mat4 worldMatrix)
|
|
{
|
|
if (vmdCameraAnim)
|
|
{
|
|
const auto mmdCam = vmdCameraAnim->GetCamera();
|
|
saba::MMDLookAtCamera lookAtCam(mmdCam);
|
|
|
|
const bool bReverseZ = true;
|
|
|
|
// update current Frame camera data.
|
|
m_currentFrameCameraData.bValidData = true;
|
|
|
|
glm::vec3 eyeWorldPos = worldMatrix * glm::vec4(lookAtCam.m_eye, 1.0f);
|
|
glm::vec3 centerWorldPos = worldMatrix * glm::vec4(lookAtCam.m_center, 1.0f);
|
|
glm::vec3 upWorld = worldMatrix * glm::vec4(lookAtCam.m_up, 0.0f);
|
|
|
|
m_currentFrameCameraData.viewMat = glm::lookAt(eyeWorldPos, centerWorldPos, upWorld);
|
|
|
|
|
|
auto fov = mmdCam.m_fov;
|
|
|
|
m_currentFrameCameraData.projMat = glm::perspectiveFovRH(
|
|
fov,
|
|
width,
|
|
height,
|
|
bReverseZ ? zFar : zNear,
|
|
bReverseZ ? zNear : zFar
|
|
);
|
|
|
|
m_currentFrameCameraData.fovy = fov;
|
|
m_currentFrameCameraData.worldPos = eyeWorldPos;
|
|
|
|
return m_currentFrameCameraData;
|
|
}
|
|
else
|
|
{
|
|
PerFrameMMDCamera ret{};
|
|
ret.bValidData = false;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
void PMXMeshProxy::OnRenderCollect(
|
|
RendererInterface* renderer,
|
|
VkCommandBuffer cmd,
|
|
VkPipelineLayout pipelinelayout,
|
|
const glm::mat4& modelMatrix,
|
|
const glm::mat4& modelMatrixPrev,
|
|
bool bTranslucentPass)
|
|
{
|
|
if (!Ready()) return;
|
|
|
|
VkBuffer vertexBuffer = m_vertexBuffer->getVkBuffer();
|
|
VkBuffer indexBuffer = m_indexBuffer->getVkBuffer();
|
|
const VkDeviceSize offset = 0;
|
|
vkCmdBindIndexBuffer(cmd, indexBuffer, 0, m_indexType);
|
|
vkCmdBindVertexBuffers(cmd, 0, 1, &vertexBuffer, &offset);
|
|
|
|
// then draw every submesh.
|
|
size_t subMeshCount = m_mmdModel->GetSubMeshCount();
|
|
for (uint32_t i = 0; i < subMeshCount; i++)
|
|
{
|
|
const auto& subMesh = m_mmdModel->GetSubMeshes()[i];
|
|
const auto& material = m_component->m_materials.at(subMesh.m_materialID);
|
|
|
|
if (material.bHide)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bool bShouldDraw = true;
|
|
if (bTranslucentPass)
|
|
{
|
|
bShouldDraw = material.bTranslucent;
|
|
}
|
|
else
|
|
{
|
|
bShouldDraw = !material.bTranslucent;
|
|
}
|
|
|
|
if (!bShouldDraw)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
uint32_t dynamicOffset = renderer->getDynamicBufferRing()->alloc(sizeof(PMXGpuParams));
|
|
|
|
|
|
PMXGpuParams params{};
|
|
params.modelMatrix = modelMatrix;
|
|
params.modelMatrixPrev = modelMatrixPrev;
|
|
|
|
|
|
params.texId = material.mmdTex;
|
|
params.spTexID = material.mmdSphereTex;
|
|
params.toonTexID = material.mmdToonTex;
|
|
params.pixelDepthOffset = material.pixelDepthOffset;
|
|
params.pmxObjectID = i;
|
|
params.shadingModel = PMXShadingModelToParam((EPMXShadingModel)material.pmxShadingModel);
|
|
|
|
memcpy((char*)(renderer->getDynamicBufferRing()->getBuffer()->mapped) + dynamicOffset, ¶ms, sizeof(PMXGpuParams));
|
|
|
|
auto set = renderer->getDynamicBufferRing()->getSet();
|
|
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelinelayout, 0, 1, &set, 1, &dynamicOffset);
|
|
|
|
|
|
vkCmdDrawIndexed(cmd, subMesh.m_vertexCount, 1, subMesh.m_beginIndex, 0, 0);
|
|
}
|
|
}
|
|
|
|
void PMXMeshProxy::OnShadowRenderCollect(
|
|
RendererInterface* renderer,
|
|
VkCommandBuffer cmd,
|
|
VkPipelineLayout pipelinelayout,
|
|
uint32_t cascadeIndex,
|
|
const glm::mat4& modelMatrix,
|
|
const glm::mat4& modelMatrixPrev)
|
|
{
|
|
if (!Ready()) return;
|
|
|
|
VkBuffer vertexBuffer = m_vertexBuffer->getVkBuffer();
|
|
VkBuffer indexBuffer = m_indexBuffer->getVkBuffer();
|
|
const VkDeviceSize offset = 0;
|
|
vkCmdBindIndexBuffer(cmd, indexBuffer, 0, m_indexType);
|
|
vkCmdBindVertexBuffers(cmd, 0, 1, &vertexBuffer, &offset);
|
|
|
|
// then draw every submesh.
|
|
size_t subMeshCount = m_mmdModel->GetSubMeshCount();
|
|
for (uint32_t i = 0; i < subMeshCount; i++)
|
|
{
|
|
const auto& subMesh = m_mmdModel->GetSubMeshes()[i];
|
|
const auto& material = m_component->m_materials.at(subMesh.m_materialID);
|
|
|
|
if (material.bHide)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (material.bTranslucent) // TODO: translucent shadow.
|
|
{
|
|
continue;
|
|
}
|
|
|
|
uint32_t dynamicOffset = renderer->getDynamicBufferRing()->alloc(sizeof(PMXGpuParams));
|
|
|
|
|
|
PMXGpuParams params{};
|
|
params.modelMatrix = modelMatrix;
|
|
params.modelMatrixPrev = modelMatrixPrev;
|
|
|
|
|
|
params.texId = material.mmdTex;
|
|
params.spTexID = material.mmdSphereTex;
|
|
params.toonTexID = material.mmdToonTex;
|
|
params.pixelDepthOffset = material.pixelDepthOffset;
|
|
params.pmxObjectID = i;
|
|
|
|
memcpy((char*)(renderer->getDynamicBufferRing()->getBuffer()->mapped) + dynamicOffset, ¶ms, sizeof(PMXGpuParams));
|
|
|
|
auto set = renderer->getDynamicBufferRing()->getSet();
|
|
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelinelayout, 7, 1, &set, 1, &dynamicOffset);
|
|
|
|
|
|
vkCmdDrawIndexed(cmd, subMesh.m_vertexCount, 1, subMesh.m_beginIndex, 0, 0);
|
|
}
|
|
}
|
|
|
|
PerFrameMMDCamera PMXComponent::getCurrentFrameCameraData(float width, float height, float zNear, float zFar)
|
|
{
|
|
glm::mat4 worldMatrix = m_node.lock()->getTransform()->getWorldMatrix();
|
|
|
|
return getProxy()->GetCurrentFrameCameraData(width, height, zNear, zFar, worldMatrix);
|
|
}
|
|
|
|
void PMXComponent::onRenderCollect(
|
|
RendererInterface* renderer,
|
|
VkCommandBuffer cmd,
|
|
VkPipelineLayout pipelinelayout,
|
|
bool bTranslucentPass)
|
|
{
|
|
if (auto node = m_node.lock())
|
|
{
|
|
auto modelMatrix = node->getTransform()->getWorldMatrix();
|
|
auto modelMatrixPrev = node->getTransform()->getPrevWorldMatrix();
|
|
getProxy()->OnRenderCollect(
|
|
renderer, cmd, pipelinelayout, modelMatrix, modelMatrixPrev, bTranslucentPass);
|
|
}
|
|
}
|
|
|
|
bool PMXComponent::isPMXCameraPlaying() const
|
|
{
|
|
return m_bPlayAnimation && bCameraSetupReady;
|
|
}
|
|
|
|
void PMXComponent::onShadowRenderCollect(RendererInterface* renderer, VkCommandBuffer cmd, VkPipelineLayout pipelinelayout, uint32_t cascadeIndex)
|
|
{
|
|
if (auto node = m_node.lock())
|
|
{
|
|
auto modelMatrix = node->getTransform()->getWorldMatrix();
|
|
|
|
getProxy()->OnShadowRenderCollect(renderer, cmd, pipelinelayout, cascadeIndex, modelMatrix, node->getTransform()->getPrevWorldMatrix());
|
|
}
|
|
}
|
|
|
|
void PMXComponent::onRenderTick(VkCommandBuffer cmd)
|
|
{
|
|
if (auto node = m_node.lock())
|
|
{
|
|
getProxy()->OnRenderTick(cmd);
|
|
}
|
|
}
|
|
|
|
void PMXComponent::tick(const RuntimeModuleTickData& tickData)
|
|
{
|
|
float dt = tickData.deltaTime;
|
|
if (dt > 1.0f / 30.0f)
|
|
{
|
|
dt = 1.0f / 30.0f;
|
|
}
|
|
|
|
if (auto node = m_node.lock())
|
|
{
|
|
if (m_bPMXMeshChanged && !m_pmxPath.empty())
|
|
{
|
|
m_bPMXMeshChanged = false;
|
|
PMXInitTrait initTrait{};
|
|
initTrait.pmxPath = m_pmxPath;
|
|
|
|
if (!m_vmdPath.empty())
|
|
{
|
|
initTrait.vmdPath.push_back(m_vmdPath);
|
|
}
|
|
|
|
|
|
getProxy()->Setup(initTrait);
|
|
}
|
|
|
|
if (m_bCameraPathChanged && !m_cameraPath.empty())
|
|
{
|
|
m_bCameraPathChanged = false;
|
|
bCameraSetupReady = true;
|
|
getProxy()->SetupCamera(m_cameraPath);
|
|
}
|
|
|
|
if (m_bPlayAnimation)
|
|
{
|
|
m_animationPlayTime += dt;
|
|
}
|
|
|
|
m_elapsed = dt;
|
|
getProxy()->OnSceneTick(m_animationPlayTime, m_elapsed);
|
|
}
|
|
}
|
|
|
|
PMXMeshProxy* PMXComponent::getProxy()
|
|
{
|
|
if (m_proxy == nullptr)
|
|
{
|
|
m_proxy = std::make_unique<PMXMeshProxy>(this);
|
|
}
|
|
return m_proxy.get();
|
|
}
|
|
|
|
|
|
void PMXComponent::resetAnimation()
|
|
{
|
|
m_animationPlayTime = 0.0f;
|
|
GEngine->getSoundEngine()->stopAllSounds();
|
|
}
|
|
|
|
void PMXComponent::setPlayAnimationState(bool bState)
|
|
{
|
|
if (m_bPlayAnimation != bState)
|
|
{
|
|
if (m_bPlayAnimation)
|
|
{
|
|
GEngine->getSoundEngine()->setAllSoundsPaused();
|
|
}
|
|
else
|
|
{
|
|
GEngine->getSoundEngine()->play2D(m_wavPath.c_str(), false);
|
|
}
|
|
|
|
m_bPlayAnimation = bState;
|
|
}
|
|
}
|
|
|
|
////
|
|
|
|
PMXComponent::~PMXComponent()
|
|
{
|
|
|
|
}
|
|
|
|
void PMXComponent::setPmxPath(std::string newPath)
|
|
{
|
|
if (m_pmxPath != newPath)
|
|
{
|
|
m_pmxPath = newPath;
|
|
m_bPMXMeshChanged = true;
|
|
markDirty();
|
|
}
|
|
}
|
|
|
|
void PMXComponent::setVmdPath(std::string vmdPath)
|
|
{
|
|
if (m_vmdPath != vmdPath)
|
|
{
|
|
m_vmdPath = vmdPath;
|
|
m_bPMXMeshChanged = true;
|
|
markDirty();
|
|
}
|
|
}
|
|
|
|
void PMXComponent::setWavPath(std::string wavPath)
|
|
{
|
|
if (m_wavPath != wavPath)
|
|
{
|
|
m_wavPath = wavPath;
|
|
m_bWaveChanged = true;
|
|
|
|
markDirty();
|
|
}
|
|
}
|
|
|
|
void PMXComponent::setCameraPath(std::string cameraPath)
|
|
{
|
|
if (m_cameraPath != cameraPath)
|
|
{
|
|
m_cameraPath = cameraPath;
|
|
m_bCameraPathChanged = true;
|
|
markDirty();
|
|
}
|
|
}
|
|
|
|
|
|
} |