Begin collision rewrite

This commit is contained in:
Bailey Harrison 2023-02-02 17:32:19 +00:00
parent ca02bf6084
commit bb7d70e79e
22 changed files with 274 additions and 192 deletions

6
debug.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
set -e
cd Debug
cmake --build .
cd test
./enginetest

View File

@ -5,38 +5,29 @@
namespace engine {
class PhysicsSystem;
enum class ColliderType {
SPHERE,
PLANE,
struct AABB {
glm::vec3 pos1;
glm::vec3 pos2;
};
class PhysicsSystem;
struct ColliderComponent {
friend PhysicsSystem;
ColliderType colliderType;
ColliderComponent()
{
union {
struct {
float r;
} sphereCollider;
} colliders;
}
auto getIsColliding() { return m_isColliding; }
auto getJustCollided() { return m_justCollided; }
auto getJustUncollided() { return m_justUncollided; }
auto getLastEntityCollided() { return m_lastEntityCollided; }
auto getLastCollisionNormal() { return m_lastCollisionNormal; }
auto getLastCollisionPoint() { return m_lastCollisionPoint; }
bool isStatic;
AABB aabb;
glm::vec3 getLastCollisionNormal() { return {0.0f, 1.0f, 0.0f}; }
glm::vec3 getLastCollisionPoint() { return {}; }
bool getIsColliding() { return true; }
bool getJustUncollided() { return false; }
private:
bool m_isColliding;
bool m_justCollided;
bool m_justUncollided;
uint32_t m_lastEntityCollided;
glm::vec3 m_lastCollisionNormal;
glm::vec3 m_lastCollisionPoint;
};
}

View File

@ -43,6 +43,7 @@ namespace engine {
}
}
private:
std::map<uint32_t, T> m_componentArray{};
};
@ -57,6 +58,9 @@ namespace engine {
virtual void onUpdate(float ts) = 0;
virtual void onComponentInsert(uint32_t) {}
virtual void onComponentRemove(uint32_t) {}
Scene* const m_scene;
std::bitset<MAX_COMPONENTS> m_signature;

View File

@ -28,14 +28,11 @@ namespace engine {
sinks.emplace_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(log_path.string(), true));
#ifndef NDEBUG
// DEBUG
sinks.emplace_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
#endif
auto logger = std::make_shared<spdlog::logger>(appName, sinks.begin(), sinks.end());
logger->set_level(spdlog::level::trace);
logger->set_level(spdlog::level::trace); // Logs below INFO are ignored through macros in release (see log.hpp)
spdlog::register_logger(logger);
spdlog::set_default_logger(logger);

View File

@ -59,7 +59,7 @@ namespace engine {
size_t hash = typeid(T).hash_code();
auto array = getComponentArray<T>();
array->insertData(entity, T{});
array->insertData(entity, T{}); // errors if entity already exists in array
// set the component bit for this entity
size_t componentSignaturePosition = m_componentSignaturePositions.at(hash);
@ -68,8 +68,10 @@ namespace engine {
for (auto& [systemName, system] : m_systems)
{
if (system->m_entities.contains(entity)) continue;
if ((system->m_signature & signatureRef) == system->m_signature) {
system->m_entities.insert(entity);
system->onComponentInsert(entity);
}
}

View File

@ -2,6 +2,10 @@
#include "ecs_system.hpp"
#include "components/collider.hpp"
#include <glm/mat4x4.hpp>
namespace engine {
class PhysicsSystem : public System {
@ -11,6 +15,21 @@ namespace engine {
void onUpdate(float ts) override;
void onComponentInsert(uint32_t entity) override;
private:
// dyanmic arrays to avoid realloc on every frame
struct CollisionInfo {
uint32_t entity;
AABB aabb;
// output
bool isMaybeColliding; // broad phase
bool isColliding; // narrow phase
};
std::vector<CollisionInfo> m_staticInfos{};
std::vector<CollisionInfo> m_dynamicInfos{};
};
}

View File

@ -138,7 +138,7 @@ namespace engine {
bool m_keyboardFocus = true;
// size in screen coordinates
glm::ivec2 m_winSize = glm::vec2(640, 480);
glm::ivec2 m_winSize = glm::vec2(1024, 768);
// performance counter frequency
uint64_t m_counterFreq;

9
prebuild.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
set -e
mkdir -p Debug
cd Debug
cmake -G Ninja -D CMAKE_BUILD_TYPE=Debug -D CMAKE_EXPORT_COMPILE_COMMANDS=ON ..
cd ..
mkdir -p Release
cd Release
cmake -G Ninja -D CMAKE_BUILD_TYPE=Release -D CMAKE_EXPORT_COMPILE_COMMANDS=ON ..

6
release.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
set -e
cd Release
cmake --build .
cd test
./enginetest

View File

@ -0,0 +1,15 @@
#version 450
layout(location = 0) in vec2 fragUV;
layout(location = 0) out vec4 outColor;
layout(set = 1, binding = 0) uniform sampler2D texSampler;
void main() {
gl_FragDepth = 0.9999;
outColor = texture(texSampler, fragUV);
}

View File

@ -0,0 +1,24 @@
#version 450
layout(binding = 0) uniform UBO {
mat4 proj;
} ubo;
layout( push_constant ) uniform Constants {
mat4 model;
mat4 view;
} constants;
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inNorm;
layout(location = 2) in vec2 inUV;
layout(location = 0) out vec2 fragUV;
void main() {
mat4 myView = constants.view;
myView[3] = vec4(0.0, 0.0, 0.0, 1.0);
vec4 pos = ubo.proj * myView * constants.model * vec4(inPosition, 1.0);
gl_Position = pos;
fragUV = inUV;
}

3
run.sh
View File

@ -1,3 +0,0 @@
#!/bin/sh
cd "Debug/test"
./enginetest

View File

@ -87,6 +87,20 @@ namespace engine {
);
getResourceManager<resources::Shader>()->addPersistent("engine.textured", std::move(texturedShader));
}
{
resources::Shader::VertexParams vertParams{};
vertParams.hasNormal = true;
vertParams.hasUV0 = true;
auto texturedShader = std::make_unique<resources::Shader>(
gfx(),
getResourcePath("engine/shaders/skybox.vert").c_str(),
getResourcePath("engine/shaders/skybox.frag").c_str(),
vertParams,
false,
true
);
getResourceManager<resources::Shader>()->addPersistent("engine.skybox", std::move(texturedShader));
}
{
auto whiteTexture = std::make_unique<resources::Texture>(
gfx(),

View File

@ -22,7 +22,13 @@ namespace engine {
registerSystem<RenderSystem>();
}
Scene::~Scene() {}
Scene::~Scene()
{
INFO("Entity signatures:");
for (auto [entity, signature] : m_signatures) {
INFO("entity {}, signature: {}", entity, signature.to_string());
}
}
uint32_t Scene::createEntity(const std::string& tag, uint32_t parent)
{
@ -54,7 +60,6 @@ namespace engine {
void Scene::update(float ts)
{
for (auto& [name, system] : m_systems) {
system->onUpdate(ts);
}

View File

@ -9,128 +9,96 @@
namespace engine {
// static functions
static bool checkCollisionFast(AABB a, AABB b)
{
if (a.pos1.x > a.pos2.x) std::swap(a.pos1.x, a.pos2.x);
if (a.pos1.y > a.pos2.y) std::swap(a.pos1.y, a.pos2.y);
if (a.pos1.z > a.pos2.z) std::swap(a.pos1.z, a.pos2.z);
if (b.pos1.x > b.pos2.x) std::swap(b.pos1.x, b.pos2.x);
if (b.pos1.y > b.pos2.y) std::swap(b.pos1.y, b.pos2.y);
if (b.pos1.z > b.pos2.z) std::swap(b.pos1.z, b.pos2.z);
return (
a.pos1.x <= b.pos2.x &&
a.pos2.x >= b.pos1.x &&
a.pos1.y <= b.pos2.y &&
a.pos2.y >= b.pos1.y &&
a.pos1.z <= b.pos2.z &&
a.pos2.z >= b.pos1.z
);
}
// class methods
PhysicsSystem::PhysicsSystem(Scene* scene)
: System(scene, { typeid(TransformComponent).hash_code(), typeid(ColliderComponent).hash_code() })
{
}
void PhysicsSystem::onComponentInsert(uint32_t entity)
{
(void)entity;
m_staticInfos.reserve(m_entities.size());
m_dynamicInfos.reserve(m_entities.size());
TRACE("added entity {} to collider system", entity);
}
void PhysicsSystem::onUpdate(float ts)
{
(void)ts;
using glm::vec3;
m_staticInfos.clear();
m_dynamicInfos.clear();
struct CollisionInfo {
uint32_t entity;
TransformComponent* t;
ColliderComponent* c;
TRACE("Getting collider entities:");
for (uint32_t entity : m_entities) {
TRACE(" has entity: {}", entity);
const auto t = m_scene->getComponent<TransformComponent>(entity);
const auto c = m_scene->getComponent<ColliderComponent>(entity);
vec3 pos;
const glm::vec3 globalPosition = t->worldMatrix[3];
const AABB localBoundingBox = c->aabb;
AABB globalBoundingBox;
globalBoundingBox.pos1 = globalPosition + localBoundingBox.pos1;
globalBoundingBox.pos2 = globalPosition + localBoundingBox.pos2;
TRACE(" global bounding box:");
TRACE(" pos1: {} {} {}", globalBoundingBox.pos1.x, globalBoundingBox.pos1.y, globalBoundingBox.pos1.z);
TRACE(" pos2: {} {} {}", globalBoundingBox.pos2.x, globalBoundingBox.pos2.y, globalBoundingBox.pos2.z);
CollisionInfo info{
.entity = entity,
.aabb = globalBoundingBox,
.isMaybeColliding = false,
.isColliding = false
};
if (c->isStatic) {
m_staticInfos.push_back(info);
} else {
m_dynamicInfos.push_back(info);
}
}
/* BROAD PHASE */
TRACE("Starting broad phase collision test");
struct PossibleCollision {
bool wasColliding;
};
std::vector<CollisionInfo> entityColliders(m_entities.size());
uint32_t i = 0;
for (uint32_t entity : m_entities) {
auto t = m_scene->getComponent<TransformComponent>(entity);
auto c = m_scene->getComponent<ColliderComponent>(entity);
entityColliders[i].entity = entity;
entityColliders[i].t = t;
entityColliders[i].c = c;
entityColliders[i].wasColliding = c->getIsColliding();
c->m_isColliding = false;
c->m_justCollided = false;
c->m_justUncollided = false;
vec3 pos = reinterpret_cast<vec3&>(t->worldMatrix[3]);
entityColliders[i].pos = pos;
i++;
// Check every static collider against every dynamic collider, and every dynamic collider against every other one
// This technique is inefficient for many entities.
for (size_t i = 0; i < m_staticInfos.size(); i++) {
for (size_t j = 0; j < m_dynamicInfos.size(); j++) {
if (checkCollisionFast(m_staticInfos[i].aabb, m_dynamicInfos[j].aabb)) {
m_staticInfos[i].isMaybeColliding = true;
m_dynamicInfos[i].isMaybeColliding = true;
TRACE("Collision detected between {} and {}", m_staticInfos[i].entity, m_dynamicInfos[j].entity);
}
}
}
// compares every entity to every other entity, but pairs are never repeated
for (size_t i = 0; i < entityColliders.size(); i++) {
auto* ec1 = &entityColliders[i];
for (size_t j = i + 1; j < entityColliders.size(); j++) {
auto* ec2 = &entityColliders[j];
if ( ec1->c->colliderType == ColliderType::SPHERE &&
ec2->c->colliderType == ColliderType::SPHERE ) {
const vec3 v = ec2->pos - ec1->pos;
const float distanceSquared = v.x * v.x + v.y * v.y + v.z * v.z;
const float sumOfRadii = ec1->c->colliders.sphereCollider.r + ec2->c->colliders.sphereCollider.r;
const float sumOfRadiiSquared = sumOfRadii * sumOfRadii;
if (distanceSquared < sumOfRadiiSquared) {
ec1->c->m_isColliding = true;
ec1->c->m_lastEntityCollided = ec2->entity;
ec1->c->m_lastCollisionNormal = glm::normalize(v);
ec1->c->m_lastCollisionPoint = ec1->pos + (v * ec1->c->colliders.sphereCollider.r / glm::sqrt(distanceSquared));
ec2->c->m_isColliding = true;
ec2->c->m_lastEntityCollided = ec1->entity;
ec2->c->m_lastCollisionNormal = -ec1->c->m_lastCollisionNormal;
ec2->c->m_lastCollisionPoint = ec1->c->m_lastCollisionPoint;
}
} else if ( (ec1->c->colliderType == ColliderType::PLANE &&
ec2->c->colliderType == ColliderType::SPHERE) ||
(ec1->c->colliderType == ColliderType::SPHERE &&
ec2->c->colliderType == ColliderType::PLANE)) {
CollisionInfo *plane, *sphere;
if (ec1->c->colliderType == ColliderType::PLANE) {
plane = ec1;
sphere = ec2;
} else {
sphere = ec1;
plane = ec2;
}
float distance = plane->pos.y - sphere->pos.y;
if (distance < 0.0f) distance = -distance; // make positive
if (distance < sphere->c->colliders.sphereCollider.r) {
plane->c->m_isColliding = true;
plane->c->m_lastEntityCollided = sphere->entity;
plane->c->m_lastCollisionNormal = {0.0f, -1.0f, 0.0f};
plane->c->m_lastCollisionPoint = {sphere->pos.x, plane->pos.y, sphere->pos.z};
sphere->c->m_isColliding = true;
sphere->c->m_lastEntityCollided = plane->entity;
sphere->c->m_lastCollisionNormal = {0.0f, 1.0f, 0.0f};
sphere->c->m_lastCollisionPoint = plane->c->m_lastCollisionPoint;
}
} else {
throw std::runtime_error("Collision combination not supported!");
}
}
if (ec1->wasColliding != ec1->c->getIsColliding()) {
if (ec1->c->getIsColliding()) {
ec1->c->m_justCollided = true;
} else {
ec1->c->m_justUncollided = true;
}
}
if (ec1->c->getJustCollided()) {
TRACE("'{}' has collided!", ec1->t->tag);
auto r = m_scene->getComponent<RenderableComponent>(ec1->entity);
if (r != nullptr) {
r->shown = true;
}
}
if (ec1->c->getJustUncollided()) {
TRACE("'{}' has stopped colliding!", ec1->t->tag);
auto r = m_scene->getComponent<RenderableComponent>(ec1->entity);
if (r != nullptr) {
r->shown = false;
}
}
}
}
}

View File

@ -51,7 +51,7 @@ namespace engine::util {
return buffer;
}
// returns false if unable to open file
// Read an image file into a vector byte buffer. PNG and JPG support at a minimum
std::unique_ptr<std::vector<uint8_t>> readImageFile(const std::string& path, int *width, int *height)
{
int x, y, n;

BIN
test/res/textures/space.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -42,6 +42,7 @@ void CameraControllerSystem::onUpdate(float ts)
const float dt = ts;
/*
constexpr float G = 9.8f;
// constexpr float MAX_SLOPE_ANGLE = glm::radians(20.0f);
constexpr float MAX_SLOPE_ANGLE = glm::radians(1000.0f); // treat every collider as a floor, (TODO: get wall collisions working so this can be removed)
@ -89,11 +90,15 @@ void CameraControllerSystem::onUpdate(float ts)
c->dy += dt * c->thrust;
}
*/
// in metres per second
//constexpr float SPEED = 1.5f;
float SPEED = c->walk_speed;
if (m_scene->app()->inputManager()->getButton("sprint")) SPEED *= 10.0f;
if (m_scene->app()->inputManager()->getButton("fire")) t->position.y += dt * SPEED;
if (m_scene->app()->inputManager()->getButton("aim")) t->position.y -= dt * SPEED;
float dx = m_scene->app()->inputManager()->getAxis("movex");
float dz = (-m_scene->app()->inputManager()->getAxis("movey"));
@ -113,9 +118,10 @@ void CameraControllerSystem::onUpdate(float ts)
const glm::vec3 d2xRotated = glm::rotateY(glm::vec3{ dx, 0.0f, 0.0f }, c->m_yaw);
const glm::vec3 d2zRotated = glm::rotateY(glm::vec3{ 0.0f, 0.0f, dz }, c->m_yaw);
glm::vec3 hVel = (d2xRotated + d2zRotated);
if (isSliding) {
/* if (isSliding) {
hVel = glm::vec3{norm.z, 0.0f, -norm.x};
}
*/
hVel *= SPEED;
t->position += hVel * dt;
t->position.y += c->dy * dt;
@ -158,8 +164,7 @@ void CameraControllerSystem::onUpdate(float ts)
" y: " + std::to_string(t->position.y) +
" z: " + std::to_string(t->position.z)
};
// m_scene->app()->window()->infoBox("POSITION", pos_string);
m_scene->app()->window()->infoBox("POSITION", std::to_string(slope));
m_scene->app()->window()->infoBox("POSITION", pos_string);
INFO("position: " + pos_string);
}

View File

@ -42,7 +42,7 @@ void playGame()
{
engine::Application app(PROJECT_NAME, PROJECT_VERSION);
app.setFrameLimiter(true);
app.setFrameLimiter(false);
// configure window
app.window()->setRelativeMouseMode(true);
@ -51,20 +51,22 @@ void playGame()
auto myScene = app.sceneManager()->createEmptyScene();
myScene->registerComponent<CameraControllerComponent>();
myScene->registerSystem<CameraControllerSystem>();
/* create camera */
{
myScene->registerComponent<CameraControllerComponent>();
myScene->registerSystem<CameraControllerSystem>();
auto camera = myScene->createEntity("camera");
myScene->getComponent<engine::TransformComponent>(camera)->position.y = 8.0f;
auto cameraCollider = myScene->addComponent<engine::ColliderComponent>(camera);
cameraCollider->colliderType = engine::ColliderType::SPHERE;
cameraCollider->colliders.sphereCollider.r = 1.8f;
myScene->addComponent<CameraControllerComponent>(camera);
auto camera = myScene->createEntity("camera");
myScene->getComponent<engine::TransformComponent>(camera)->position.y = 8.0f;
auto cameraCollider = myScene->addComponent<engine::ColliderComponent>(camera);
cameraCollider->isStatic = false;
cameraCollider->aabb = { { -0.2f, -1.5f, -0.2f }, { 0.2f, 0.2f, 0.2f} }; // Origin is at eye level
myScene->addComponent<CameraControllerComponent>(camera);
myScene->getSystem<engine::RenderSystem>()->setCameraEntity(camera);
// engine::util::loadMeshFromFile(myScene, app.getResourcePath("models/van/van.dae"));
myScene->getSystem<engine::RenderSystem>()->setCameraEntity(camera);
}
/* shared resources */
auto grassTexture = std::make_shared<engine::resources::Texture>(
app.gfx(),
app.getResourcePath("textures/grass.jpg"),
@ -72,39 +74,53 @@ void playGame()
true,
true
);
auto spaceTexture = std::make_shared<engine::resources::Texture>(
app.gfx(),
app.getResourcePath("textures/space2.png"),
engine::resources::Texture::Filtering::ANISOTROPIC,
true,
true
);
uint32_t enemy = myScene->createEntity("enemy");
auto enemyRenderable = myScene->addComponent<engine::RenderableComponent>(enemy);
enemyRenderable->material = std::make_unique<engine::resources::Material>(app.getResource<engine::resources::Shader>("engine.textured"));
enemyRenderable->material->m_texture = app.getResource<engine::resources::Texture>("engine.white");
enemyRenderable->mesh = genSphereMesh(app.gfx(), 5.0f, 50, false);
auto enemyT = myScene->getComponent<engine::TransformComponent>(enemy);
enemyT->position.x += 10.0f;
enemyT->position.y += 2.0f;
enemyT->position.z += 14.0f;
auto enemyCollider = myScene->addComponent<engine::ColliderComponent>(enemy);
enemyCollider->colliderType = engine::ColliderType::SPHERE;
enemyCollider->colliders.sphereCollider.r = 5.0f;
/* skybox */
{
uint32_t skybox = myScene->createEntity("skybox");
auto skyboxRenderable = myScene->addComponent<engine::RenderableComponent>(skybox);
skyboxRenderable->material = std::make_unique<engine::resources::Material>(app.getResource<engine::resources::Shader>("engine.skybox"));
skyboxRenderable->material->m_texture = spaceTexture;
// skyboxRenderable->mesh = genSphereMesh(app.gfx(), 1.0f, 50, true);
skyboxRenderable->mesh = genCuboidMesh(app.gfx(), 2.0f, 2.0f, 2.0f, 1.0f, true);
myScene->getComponent<engine::TransformComponent>(skybox)->position = { -1.0f, -1.0f, -1.0f };
}
uint32_t sphere = myScene->createEntity("sphere");
auto sphereRenderable = myScene->addComponent<engine::RenderableComponent>(sphere);
sphereRenderable->material = std::make_unique<engine::resources::Material>(app.getResource<engine::resources::Shader>("engine.textured"));
sphereRenderable->material->m_texture = app.getResource<engine::resources::Texture>("engine.white");
sphereRenderable->mesh = genSphereMesh(app.gfx(), 100.0f, 50, true);
/* enemy sphere */
{
uint32_t enemy = myScene->createEntity("enemy");
auto enemyRenderable = myScene->addComponent<engine::RenderableComponent>(enemy);
enemyRenderable->material = std::make_unique<engine::resources::Material>(app.getResource<engine::resources::Shader>("engine.textured"));
enemyRenderable->material->m_texture = app.getResource<engine::resources::Texture>("engine.white");
enemyRenderable->mesh = genSphereMesh(app.gfx(), 5.0f, 50, false);
auto enemyTransform = myScene->getComponent<engine::TransformComponent>(enemy);
enemyTransform->position.x = 10.0f;
enemyTransform->position.y = 0.0f;
enemyTransform->position.z = 14.0f;
auto enemyCollider = myScene->addComponent<engine::ColliderComponent>(enemy);
enemyCollider->isStatic = true;
enemyCollider->aabb = { { -5.0f, -5.0f, -5.0f }, { 5.0f, 5.0f, 5.0f } }; // A box enclosing the sphere
}
uint32_t light = myScene->createEntity("light");
myScene->getComponent<engine::TransformComponent>(light)->position = glm::vec3{-10.0f, 10.0f, 10.0f};
auto lightRenderable = myScene->addComponent<engine::RenderableComponent>(light);
lightRenderable->material = sphereRenderable->material;
lightRenderable->mesh = genSphereMesh(app.gfx(), 0.5f, 40, false, true);
uint32_t floor = myScene->createEntity("floor");
myScene->getComponent<engine::TransformComponent>(floor)->position = glm::vec3{-50.0f, -0.1f, -50.0f};
auto floorRenderable = myScene->addComponent<engine::RenderableComponent>(floor);
floorRenderable->material = std::make_shared<engine::resources::Material>(*sphereRenderable->material);
floorRenderable->material->m_texture = grassTexture;
floorRenderable->mesh = genCuboidMesh(app.gfx(), 100.0f, 0.1f, 100.0f);
myScene->addComponent<engine::ColliderComponent>(floor)->colliderType = engine::ColliderType::PLANE;
/* floor */
{
uint32_t floor = myScene->createEntity("floor");
myScene->getComponent<engine::TransformComponent>(floor)->position = glm::vec3{-50.0f, -0.1f, -50.0f};
auto floorRenderable = myScene->addComponent<engine::RenderableComponent>(floor);
floorRenderable->material = std::make_shared<engine::resources::Material>(app.getResource<engine::resources::Shader>("engine.textured"));
floorRenderable->material->m_texture = grassTexture;
floorRenderable->mesh = genCuboidMesh(app.gfx(), 100.0f, 0.1f, 100.0f, 128.0f);
auto floorCollider = myScene->addComponent<engine::ColliderComponent>(floor);
floorCollider->isStatic = true;
floorCollider->aabb = { { 0.0f, 0.0f, 0.0f }, { 100.0f, 0.1f, 100.0f } };
}
app.gameLoop();

View File

@ -88,7 +88,7 @@ std::unique_ptr<engine::resources::Mesh> genSphereMesh(engine::GFXDevice* gfx, f
return std::make_unique<engine::resources::Mesh>(gfx, vertices);
}
std::unique_ptr<engine::resources::Mesh> genCuboidMesh(engine::GFXDevice* gfx, float x, float y, float z)
std::unique_ptr<engine::resources::Mesh> genCuboidMesh(engine::GFXDevice* gfx, float x, float y, float z, float tiling, bool windInside)
{
// x goes ->
@ -99,8 +99,6 @@ std::unique_ptr<engine::resources::Mesh> genCuboidMesh(engine::GFXDevice* gfx, f
std::vector<engine::Vertex> v{};
const float tiling = 128.0f;
// front
v.push_back({{x, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {tiling, 0.0f}});
v.push_back({{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f}});
@ -149,6 +147,12 @@ std::unique_ptr<engine::resources::Mesh> genCuboidMesh(engine::GFXDevice* gfx, f
v.push_back({{0.0f, y, z}, {0.0f, 1.0f, 0.0f}, {0.0f, tiling}});
v.push_back({{x, y, z}, {0.0f, 1.0f, 0.0f}, {tiling, tiling}});
if (windInside) {
for (size_t i = 0; i < v.size(); i += 3) {
std::swap(v[i], v[i + 2]);
}
}
return std::make_unique<engine::resources::Mesh>(gfx, v);
}

View File

@ -5,4 +5,4 @@
// generates a UV sphere
std::unique_ptr<engine::resources::Mesh> genSphereMesh(engine::GFXDevice* gfx, float r, int detail, bool windInside = false, bool flipNormals = false);
std::unique_ptr<engine::resources::Mesh> genCuboidMesh(engine::GFXDevice* gfx, float x, float y, float z);
std::unique_ptr<engine::resources::Mesh> genCuboidMesh(engine::GFXDevice* gfx, float x, float y, float z, float tiling = 1.0f, bool windInside = false);