From f8e1549c427804a72b29501c81f0f11d4f791165 Mon Sep 17 00:00:00 2001 From: fallahn Date: Tue, 12 Nov 2024 14:17:43 +0000 Subject: [PATCH] add mesh rendering for ropes --- samples/golf/src/golf/GameConsts.hpp | 1 + samples/golf/src/golf/MenuState.cpp | 103 +++++++++++++++++++++------ samples/golf/src/golf/MenuState.hpp | 2 +- samples/golf/src/golf/RopeSystem.cpp | 19 +++-- 4 files changed, 95 insertions(+), 30 deletions(-) diff --git a/samples/golf/src/golf/GameConsts.hpp b/samples/golf/src/golf/GameConsts.hpp index d1c39b282..d156ccf03 100644 --- a/samples/golf/src/golf/GameConsts.hpp +++ b/samples/golf/src/golf/GameConsts.hpp @@ -318,6 +318,7 @@ struct ShaderID final LensFlare, PointFlare, Firework, + Rope }; }; diff --git a/samples/golf/src/golf/MenuState.cpp b/samples/golf/src/golf/MenuState.cpp index 36d632e31..47b4b6952 100644 --- a/samples/golf/src/golf/MenuState.cpp +++ b/samples/golf/src/golf/MenuState.cpp @@ -46,6 +46,7 @@ source distribution. #include "HoleData.hpp" #include "League.hpp" #include "RopeSystem.hpp" +#include "../Colordome-32.hpp" #include "../ErrorCheck.hpp" #include @@ -1559,7 +1560,10 @@ void MenuState::addSystems() { auto& mb = getContext().appInstance.getMessageBus(); - m_backgroundScene.addSystem(mb); + //TODO this isn't strictly necessary to add if we're not adding any ropes + m_backgroundScene.addSystem(mb)->setNoiseTexture("assets/golf/images/wind.png", 10.f); + m_backgroundScene.getSystem()->setWind(glm::vec3(0.15f, 0.02f, -0.15f)); + m_backgroundScene.addSystem(mb); m_backgroundScene.addSystem(mb)->setWindVector(glm::vec3(0.25f)); m_backgroundScene.addSystem(mb); @@ -1760,8 +1764,6 @@ void MenuState::loadAssets() void MenuState::createScene() { - createRopes(); - m_backgroundScene.enableSkybox(); cro::AudioMixer::setPrefadeVolume(0.f, MixerChannel::Music); @@ -2290,7 +2292,7 @@ void MenuState::createScene() } } - + createRopes(timeOfDay); createClouds(); //music @@ -2505,37 +2507,94 @@ void MenuState::createClouds() } } -void MenuState::createRopes() +void MenuState::createRopes(std::int32_t timeOfDay) { + static constexpr std::int32_t NodeCount = 6; + static constexpr auto BasePos = glm::vec3(-10.f, 2.8f, 12.f); + + //TODO day/night models. Shadow cast by day, self-illum at night + //TODO could have a version with flags on instead of lanterns? cro::ModelDefinition temp(m_resources); temp.loadFromFile("assets/models/sphere.cmt"); - auto rope = m_backgroundScene.getSystem()->addRope(glm::vec3(-7.f, 3.f, 10.f), glm::vec3(7.f, 3.f, 10.f), 0.5f); - for (auto i = 0; i < 6; ++i) + auto rope1 = m_backgroundScene.getSystem()->addRope(BasePos, glm::vec3(10.f, 2.8f, 12.f), 0.001f); + for (auto i = 0; i < NodeCount; ++i) { auto entity = m_backgroundScene.createEntity(); - entity.addComponent(); - entity.addComponent().ropeID = rope; + entity.addComponent().setOrigin({ 0.f, 0.25f, 0.f }); + entity.addComponent().ropeID = rope1; + temp.createModel(entity); } + + auto rope2 = m_backgroundScene.getSystem()->addRope(BasePos, glm::vec3(-10.f, 3.f, -2.f), 0.001f); + for (auto i = 0; i < NodeCount; ++i) + { + auto entity = m_backgroundScene.createEntity(); + entity.addComponent().setOrigin({ 0.f, 0.25f, 0.f }); + entity.addComponent().ropeID = rope2; - m_backgroundScene.getSystem()->setNoiseTexture("assets/golf/images/wind.png", 10.f); - m_backgroundScene.getSystem()->setWind(glm::vec3(0.15f, 0.02f, -0.15f)); - + temp.createModel(entity); + } - //TODO create a line strip mesh for the rope - //and use the vertex ID to index these values - //as a uniform array. - registerWindow([&, rope]() + + const std::string frag = + R"( +uniform vec4 u_colour = vec4(0.6784, 0.7255, 0.7216, 1.0); +OUTPUT + +void main(){FRAG_OUT = u_colour;} + )"; + + m_resources.shaders.loadFromString(ShaderID::Rope, cro::ModelRenderer::getDefaultVertexShader(cro::ModelRenderer::VertexShaderID::Unlit), frag); + auto matID = m_resources.materials.add(m_resources.shaders.get(ShaderID::Rope)); + auto material = m_resources.materials.get(matID); + material.setProperty("u_colour", CD32::Colours[CD32::GreyLight] * m_sharedData.menuSky.sunColour); + + const auto createRopeMesh = [&](glm::vec3 pos, std::size_t ropeID) { - const auto& pos = m_backgroundScene.getSystem()->getNodePositions(rope); - ImGui::Begin("sdfsd"); - for (auto p : pos) + //position only, triangle strip + auto entity = m_backgroundScene.createEntity(); + entity.addComponent().setPosition(pos); + auto meshID = m_resources.meshes.loadMesh(cro::DynamicMeshBuilder(cro::VertexProperty::Position, 1, GL_LINE_STRIP)); + entity.addComponent(m_resources.meshes.getMesh(meshID), material); + + + //indices are fixed at nodecount + 2 for anchors + std::vector indices; + for (auto i = 0; i < NodeCount + 2; ++i) { - ImGui::Text("Pos: %3.2f, %3.2f, %3.2f", p.x, p.y, p.z); + indices.push_back(i); } - ImGui::End(); - }); + auto* meshData = &entity.getComponent().getMeshData(); + auto* submesh = &meshData->indexData[0]; + submesh->indexCount = static_cast(indices.size()); + glCheck(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, submesh->ibo)); + glCheck(glBufferData(GL_ELEMENT_ARRAY_BUFFER, submesh->indexCount * sizeof(std::uint32_t), indices.data(), GL_DYNAMIC_DRAW)); + glCheck(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + //wildly inaccurate but passes the frustum culling... + meshData->boundingBox = { glm::vec3(0.1f, 0.f, 0.005f), glm::vec3(5.f, 1.f, -0.005f) }; + meshData->boundingSphere = meshData->boundingBox; + + + //verts are updated via callback - we could have a static mesh and set positions + //via a uniform BUT we're still sending the same amount of data every time and + //that would actually require a more expensive shader... + entity.addComponent().active = true; + entity.getComponent().setUserData>(); + entity.getComponent().function = + [&, ropeID, meshData](cro::Entity e, float) + { + const auto& verts = m_backgroundScene.getSystem()->getNodePositions(ropeID); + + meshData->vertexCount = verts.size(); + glCheck(glBindBuffer(GL_ARRAY_BUFFER, meshData->vbo)); + glCheck(glBufferData(GL_ARRAY_BUFFER, meshData->vertexSize * meshData->vertexCount, verts.data(), GL_DYNAMIC_DRAW)); + glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0)); + }; + }; + createRopeMesh(BasePos, rope1); + createRopeMesh(BasePos, rope2); } void MenuState::setVoiceCallbacks() diff --git a/samples/golf/src/golf/MenuState.hpp b/samples/golf/src/golf/MenuState.hpp index 615a9f433..88139d467 100644 --- a/samples/golf/src/golf/MenuState.hpp +++ b/samples/golf/src/golf/MenuState.hpp @@ -255,7 +255,7 @@ class MenuState final : public cro::State, public cro::GuiClient, public cro::Co void loadAssets(); void createScene(); void createClouds(); - void createRopes(); + void createRopes(std::int32_t); void setVoiceCallbacks(); std::array m_voiceEntities; diff --git a/samples/golf/src/golf/RopeSystem.cpp b/samples/golf/src/golf/RopeSystem.cpp index 2914aef70..cc9f7daec 100644 --- a/samples/golf/src/golf/RopeSystem.cpp +++ b/samples/golf/src/golf/RopeSystem.cpp @@ -211,9 +211,9 @@ void Rope::recalculate() float len = glm::length(stride); len /= (m_nodes.size() - 1); - len += (len * m_slack); + //len += (len * m_slack); - m_nodeSpacing = len; + m_nodeSpacing = len + (len * m_slack); stride = glm::normalize(stride) * len; } @@ -225,7 +225,7 @@ void Rope::recalculate() n.prevPosition = position; n.samplePosition = position; n.force = glm::vec3(0.f); - n.fixed = false; + //n.fixed = false; position += stride; } @@ -246,6 +246,7 @@ void Rope::integrate(float dt, glm::vec3 windOffset) //this means we're delayed one frame, but it has to happen //after we apply the constraints from the previous integration node.getComponent().setPosition(n.position); + node.getComponent().setRotation(glm::quat(n.force * 0.01f)); //not at all realistic, but it adds some depth m_nodePositions.push_back(n.position - m_startPoint); if (!n.fixed) @@ -260,20 +261,24 @@ void Rope::integrate(float dt, glm::vec3 windOffset) //hmmm how do we do this without the conditional? if (texturePos.x < 0) { - texturePos.x += mapSize.x; + texturePos.x += (mapSize.x - 1.f); } if (texturePos.y < 0) { - texturePos.y += mapSize.y; + texturePos.y += (mapSize.y - 1.f); } + //ugh we should do this *right* not this hack + texturePos.x = std::clamp(texturePos.x, 0.f, mapSize.x - 1.f); + texturePos.y = std::clamp(texturePos.y, 0.f, mapSize.y - 1.f); + auto index = static_cast(std::floor(texturePos.y) * m_noiseMap->getDimensions().x + std::floor(texturePos.x)); index *= stride; - + //LogI << index << ", " << texturePos << std::endl; const float x = *(m_noiseMap->begin() + index); const float y = *(m_noiseMap->begin() + index + 1); const float z = *(m_noiseMap->begin() + index + 2); - + n.force = { x,y/4.f,z }; n.force *= 5.f; //hmm we want to make this a variable somewhere? }