ADD: animation and primitive test completed
This commit is contained in:
@@ -384,6 +384,99 @@ Docs: `docs/Scene.md`
|
|||||||
- Spawn primitives or dynamic meshes at runtime (e.g. projectiles, props).
|
- Spawn primitives or dynamic meshes at runtime (e.g. projectiles, props).
|
||||||
- Use `setMeshInstanceTransform` every frame to move them based on game logic.
|
- Use `setMeshInstanceTransform` every frame to move them based on game logic.
|
||||||
|
|
||||||
|
### Textured Primitives
|
||||||
|
|
||||||
|
Spawn primitive meshes (cube, sphere, plane, capsule) with custom PBR textures at runtime.
|
||||||
|
|
||||||
|
#### PrimitiveMaterial Structure
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct PrimitiveMaterial
|
||||||
|
{
|
||||||
|
std::string albedoPath; // Color/diffuse texture (relative to assets/)
|
||||||
|
std::string metalRoughPath; // Metallic (R) + Roughness (G) texture
|
||||||
|
std::string normalPath; // Tangent-space normal map
|
||||||
|
std::string occlusionPath; // Ambient occlusion (R channel)
|
||||||
|
std::string emissivePath; // Emissive map
|
||||||
|
|
||||||
|
glm::vec4 colorFactor{1.0f}; // Base color multiplier (RGBA)
|
||||||
|
float metallic{0.0f}; // Metallic factor (0-1)
|
||||||
|
float roughness{0.5f}; // Roughness factor (0-1)
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### PrimitiveType Enum
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
enum class PrimitiveType
|
||||||
|
{
|
||||||
|
Cube,
|
||||||
|
Sphere,
|
||||||
|
Plane,
|
||||||
|
Capsule
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### API Functions
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
bool add_textured_primitive(const std::string& name,
|
||||||
|
PrimitiveType type,
|
||||||
|
const PrimitiveMaterial& material,
|
||||||
|
const Transform& transform = {});
|
||||||
|
|
||||||
|
bool add_textured_primitive(const std::string& name,
|
||||||
|
PrimitiveType type,
|
||||||
|
const PrimitiveMaterial& material,
|
||||||
|
const TransformD& transform); // double-precision
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Usage Example
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
GameAPI::Engine api(&engine);
|
||||||
|
|
||||||
|
// Create material with textures
|
||||||
|
GameAPI::PrimitiveMaterial mat;
|
||||||
|
mat.albedoPath = "textures/brick_albedo.png";
|
||||||
|
mat.normalPath = "textures/brick_normal.png";
|
||||||
|
mat.metalRoughPath = "textures/brick_mro.png"; // Metallic-Roughness-Occlusion packed
|
||||||
|
mat.roughness = 0.7f;
|
||||||
|
mat.metallic = 0.0f;
|
||||||
|
|
||||||
|
// Spawn a textured cube
|
||||||
|
GameAPI::Transform transform;
|
||||||
|
transform.position = glm::vec3(0.0f, 1.0f, -5.0f);
|
||||||
|
transform.scale = glm::vec3(2.0f);
|
||||||
|
|
||||||
|
api.add_textured_primitive("my_brick_cube", GameAPI::PrimitiveType::Cube, mat, transform);
|
||||||
|
|
||||||
|
// Spawn a textured sphere with different material
|
||||||
|
GameAPI::PrimitiveMaterial metalMat;
|
||||||
|
metalMat.albedoPath = "textures/metal_albedo.png";
|
||||||
|
metalMat.normalPath = "textures/metal_normal.png";
|
||||||
|
metalMat.metallic = 1.0f;
|
||||||
|
metalMat.roughness = 0.3f;
|
||||||
|
metalMat.colorFactor = glm::vec4(0.9f, 0.9f, 1.0f, 1.0f); // Slight blue tint
|
||||||
|
|
||||||
|
GameAPI::Transform sphereT;
|
||||||
|
sphereT.position = glm::vec3(3.0f, 1.0f, -5.0f);
|
||||||
|
|
||||||
|
api.add_textured_primitive("chrome_sphere", GameAPI::PrimitiveType::Sphere, metalMat, sphereT);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Notes
|
||||||
|
|
||||||
|
- Texture paths are relative to the `assets/` directory.
|
||||||
|
- If a texture path is empty, the engine uses default placeholder textures:
|
||||||
|
- Albedo: error checkerboard (magenta/black)
|
||||||
|
- Normal: flat normal (0.5, 0.5, 1.0)
|
||||||
|
- MetalRough: white (default values from `metallic`/`roughness` factors)
|
||||||
|
- Occlusion: white (no occlusion)
|
||||||
|
- Emissive: black (no emission)
|
||||||
|
- Textures are loaded asynchronously via `TextureCache`; placeholders appear until upload completes.
|
||||||
|
- For non-textured primitives with solid colors, use `add_primitive_instance()` instead.
|
||||||
|
|
||||||
- GLTF instances (actors)
|
- GLTF instances (actors)
|
||||||
- `void addGLTFInstance(const std::string &name, std::shared_ptr<LoadedGLTF> scene, const glm::mat4 &transform = glm::mat4(1.f));`
|
- `void addGLTFInstance(const std::string &name, std::shared_ptr<LoadedGLTF> scene, const glm::mat4 &transform = glm::mat4(1.f));`
|
||||||
- `bool getGLTFInstanceTransform(const std::string &name, glm::mat4 &outTransform);`
|
- `bool getGLTFInstanceTransform(const std::string &name, glm::mat4 &outTransform);`
|
||||||
|
|||||||
@@ -604,11 +604,52 @@ void VulkanEngine::init_default_data()
|
|||||||
BoundsType::Sphere);
|
BoundsType::Sphere);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test textured primitives
|
||||||
|
{
|
||||||
|
AssetManager::MeshMaterialDesc matDesc;
|
||||||
|
matDesc.kind = AssetManager::MeshMaterialDesc::Kind::Textured;
|
||||||
|
matDesc.options.albedoPath = "textures/grass_albedo.png";
|
||||||
|
matDesc.options.normalPath = "textures/grass_normal.png";
|
||||||
|
matDesc.options.metalRoughPath = "textures/grass_mro.png";
|
||||||
|
matDesc.options.occlusionPath = "textures/grass_ao.png";
|
||||||
|
|
||||||
|
addPrimitiveInstance("textured.cube",
|
||||||
|
AssetManager::MeshGeometryDesc::Type::Cube,
|
||||||
|
glm::translate(glm::mat4(1.f), glm::vec3(0.f, 1.f, -4.f)),
|
||||||
|
matDesc);
|
||||||
|
|
||||||
|
addPrimitiveInstance("textured.sphere",
|
||||||
|
AssetManager::MeshGeometryDesc::Type::Sphere,
|
||||||
|
glm::translate(glm::mat4(1.f), glm::vec3(3.f, 1.f, -4.f)),
|
||||||
|
matDesc);
|
||||||
|
|
||||||
|
addPrimitiveInstance("textured.plane",
|
||||||
|
AssetManager::MeshGeometryDesc::Type::Plane,
|
||||||
|
glm::scale(glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, -6.f)), glm::vec3(4.f)),
|
||||||
|
matDesc);
|
||||||
|
}
|
||||||
|
|
||||||
if (addGLTFInstance("mirage", "mirage2000/scene.gltf", glm::mat4(1.0f)))
|
if (addGLTFInstance("mirage", "mirage2000/scene.gltf", glm::mat4(1.0f)))
|
||||||
{
|
{
|
||||||
preloadInstanceTextures("mirage");
|
preloadInstanceTextures("mirage");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Windmill animation test
|
||||||
|
{
|
||||||
|
glm::mat4 windmillTransform = glm::translate(glm::mat4(1.0f), glm::vec3(10.0f, 0.0f, 0.0f));
|
||||||
|
windmillTransform = glm::scale(windmillTransform, glm::vec3(0.5f));
|
||||||
|
if (addGLTFInstance("windmill", "windmill/scene.gltf", windmillTransform))
|
||||||
|
{
|
||||||
|
preloadInstanceTextures("windmill");
|
||||||
|
// Enable first animation (index 0) with looping
|
||||||
|
if (_sceneManager)
|
||||||
|
{
|
||||||
|
_sceneManager->setGLTFInstanceAnimation("windmill", 0, true);
|
||||||
|
_sceneManager->setGLTFInstanceAnimationLoop("windmill", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_mainDeletionQueue.push_function([&]() {
|
_mainDeletionQueue.push_function([&]() {
|
||||||
_resourceManager->destroy_image(_whiteImage);
|
_resourceManager->destroy_image(_whiteImage);
|
||||||
_resourceManager->destroy_image(_greyImage);
|
_resourceManager->destroy_image(_greyImage);
|
||||||
|
|||||||
@@ -526,6 +526,71 @@ bool Engine::add_primitive_instance(const std::string& name,
|
|||||||
: false;
|
: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Engine::add_textured_primitive(const std::string& name,
|
||||||
|
PrimitiveType type,
|
||||||
|
const PrimitiveMaterial& material,
|
||||||
|
const Transform& transform)
|
||||||
|
{
|
||||||
|
AssetManager::MeshGeometryDesc::Type geomType;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case PrimitiveType::Cube: geomType = AssetManager::MeshGeometryDesc::Type::Cube; break;
|
||||||
|
case PrimitiveType::Sphere: geomType = AssetManager::MeshGeometryDesc::Type::Sphere; break;
|
||||||
|
case PrimitiveType::Plane: geomType = AssetManager::MeshGeometryDesc::Type::Plane; break;
|
||||||
|
case PrimitiveType::Capsule: geomType = AssetManager::MeshGeometryDesc::Type::Capsule; break;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetManager::MeshMaterialDesc matDesc;
|
||||||
|
matDesc.kind = AssetManager::MeshMaterialDesc::Kind::Textured;
|
||||||
|
matDesc.options.albedoPath = material.albedoPath;
|
||||||
|
matDesc.options.metalRoughPath = material.metalRoughPath;
|
||||||
|
matDesc.options.normalPath = material.normalPath;
|
||||||
|
matDesc.options.occlusionPath = material.occlusionPath;
|
||||||
|
matDesc.options.emissivePath = material.emissivePath;
|
||||||
|
matDesc.options.constants.colorFactors = material.colorFactor;
|
||||||
|
matDesc.options.constants.metal_rough_factors = glm::vec4(material.metallic, material.roughness, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
return _engine->addPrimitiveInstance(name, geomType, transform.to_matrix(), matDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Engine::add_textured_primitive(const std::string& name,
|
||||||
|
PrimitiveType type,
|
||||||
|
const PrimitiveMaterial& material,
|
||||||
|
const TransformD& transform)
|
||||||
|
{
|
||||||
|
AssetManager::MeshGeometryDesc::Type geomType;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case PrimitiveType::Cube: geomType = AssetManager::MeshGeometryDesc::Type::Cube; break;
|
||||||
|
case PrimitiveType::Sphere: geomType = AssetManager::MeshGeometryDesc::Type::Sphere; break;
|
||||||
|
case PrimitiveType::Plane: geomType = AssetManager::MeshGeometryDesc::Type::Plane; break;
|
||||||
|
case PrimitiveType::Capsule: geomType = AssetManager::MeshGeometryDesc::Type::Capsule; break;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetManager::MeshMaterialDesc matDesc;
|
||||||
|
matDesc.kind = AssetManager::MeshMaterialDesc::Kind::Textured;
|
||||||
|
matDesc.options.albedoPath = material.albedoPath;
|
||||||
|
matDesc.options.metalRoughPath = material.metalRoughPath;
|
||||||
|
matDesc.options.normalPath = material.normalPath;
|
||||||
|
matDesc.options.occlusionPath = material.occlusionPath;
|
||||||
|
matDesc.options.emissivePath = material.emissivePath;
|
||||||
|
matDesc.options.constants.colorFactors = material.colorFactor;
|
||||||
|
matDesc.options.constants.metal_rough_factors = glm::vec4(material.metallic, material.roughness, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
if (!_engine->addPrimitiveInstance(name, geomType, glm::mat4(1.0f), matDesc))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return _engine->_sceneManager
|
||||||
|
? _engine->_sceneManager->setMeshInstanceTRSWorld(name,
|
||||||
|
WorldVec3(transform.position),
|
||||||
|
transform.rotation,
|
||||||
|
transform.scale)
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Engine::remove_mesh_instance(const std::string& name)
|
bool Engine::remove_mesh_instance(const std::string& name)
|
||||||
{
|
{
|
||||||
return _engine->_sceneManager ? _engine->_sceneManager->removeMeshInstance(name) : false;
|
return _engine->_sceneManager ? _engine->_sceneManager->removeMeshInstance(name) : false;
|
||||||
|
|||||||
@@ -51,6 +51,20 @@ enum class PrimitiveType
|
|||||||
Capsule
|
Capsule
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Material description for textured primitives
|
||||||
|
struct PrimitiveMaterial
|
||||||
|
{
|
||||||
|
std::string albedoPath; // Color/diffuse texture (relative to assets/)
|
||||||
|
std::string metalRoughPath; // Metallic (R) + Roughness (G) texture
|
||||||
|
std::string normalPath; // Tangent-space normal map
|
||||||
|
std::string occlusionPath; // Ambient occlusion (R channel)
|
||||||
|
std::string emissivePath; // Emissive map
|
||||||
|
|
||||||
|
glm::vec4 colorFactor{1.0f}; // Base color multiplier (RGBA)
|
||||||
|
float metallic{0.0f}; // Metallic factor (0-1)
|
||||||
|
float roughness{0.5f}; // Roughness factor (0-1)
|
||||||
|
};
|
||||||
|
|
||||||
// Point light data
|
// Point light data
|
||||||
struct PointLight
|
struct PointLight
|
||||||
{
|
{
|
||||||
@@ -288,6 +302,16 @@ public:
|
|||||||
PrimitiveType type,
|
PrimitiveType type,
|
||||||
const TransformD& transform);
|
const TransformD& transform);
|
||||||
|
|
||||||
|
// Add primitive mesh instance with textures
|
||||||
|
bool add_textured_primitive(const std::string& name,
|
||||||
|
PrimitiveType type,
|
||||||
|
const PrimitiveMaterial& material,
|
||||||
|
const Transform& transform = {});
|
||||||
|
bool add_textured_primitive(const std::string& name,
|
||||||
|
PrimitiveType type,
|
||||||
|
const PrimitiveMaterial& material,
|
||||||
|
const TransformD& transform);
|
||||||
|
|
||||||
// Remove mesh instance (primitives or custom meshes)
|
// Remove mesh instance (primitives or custom meshes)
|
||||||
bool remove_mesh_instance(const std::string& name);
|
bool remove_mesh_instance(const std::string& name);
|
||||||
|
|
||||||
|
|||||||
@@ -244,10 +244,16 @@ std::optional<std::shared_ptr<LoadedGLTF> > loadGltf(VulkanEngine *engine,
|
|||||||
gltf.images.size(),
|
gltf.images.size(),
|
||||||
gltf.samplers.size());
|
gltf.samplers.size());
|
||||||
|
|
||||||
|
// One material descriptor set binds:
|
||||||
|
// - 1x uniform buffer (material constants)
|
||||||
|
// - 5x combined image samplers (baseColor, metalRough, normal, occlusion, emissive)
|
||||||
|
//
|
||||||
|
// The pool must have at least these counts per material. If the ratio is too low
|
||||||
|
// (e.g. 3 samplers) and the asset has only 1 material, allocating the first set
|
||||||
|
// can fail with VK_ERROR_OUT_OF_POOL_MEMORY.
|
||||||
std::vector<DescriptorAllocatorGrowable::PoolSizeRatio> sizes = {
|
std::vector<DescriptorAllocatorGrowable::PoolSizeRatio> sizes = {
|
||||||
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 3},
|
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 5},
|
||||||
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3},
|
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1},
|
||||||
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
file.descriptorPool.init(engine->_deviceManager->device(), gltf.materials.size(), sizes);
|
file.descriptorPool.init(engine->_deviceManager->device(), gltf.materials.size(), sizes);
|
||||||
|
|||||||
Reference in New Issue
Block a user