diff --git a/proj-windows/CMakeLists.txt b/proj-windows/CMakeLists.txt index 36e6ee7..64a3758 100644 --- a/proj-windows/CMakeLists.txt +++ b/proj-windows/CMakeLists.txt @@ -18,6 +18,8 @@ add_executable(space-game001 ../src/Environment.h ../src/render/Renderer.cpp ../src/render/Renderer.h + ../src/render/Camera.cpp + ../src/render/Camera.h ../src/render/ShaderManager.cpp ../src/render/ShaderManager.h ../src/render/TextureManager.cpp diff --git a/src/Game.cpp b/src/Game.cpp index f4a569a..82306df 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -1,3 +1,4 @@ +#include "GameConfig.h" #include "Game.h" #include "AnimatedModel.h" #include "BoneAnimatedModel.h" @@ -250,12 +251,7 @@ namespace ZL renderer, CONST_ZIP_FILE, "resources/joystick_base.png", "resources/joystick_knob.png"); - /*uiManager.setSliderCallback("musicVolumeSlider", [this](const std::string& name, float value) { - std::cerr << "Music volume slider changed to: " << value << std::endl; - musicVolume = value; - Environment::shipVelocity = musicVolume * 20.0f; - }); - //#endif*/ + cubemapTexture = std::make_shared( std::array{ @@ -275,24 +271,17 @@ namespace ZL //Load texture - //spaceshipTexture = std::make_unique(CreateTextureDataFromPng("resources/DefaultMaterial_BaseColor_shine.png", CONST_ZIP_FILE)); - //spaceshipBase = LoadFromTextFile02("resources/spaceship006.txt", CONST_ZIP_FILE); - //spaceshipBase.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI / 2.0, Eigen::Vector3f::UnitY())).toRotationMatrix());// QuatFromRotateAroundY(M_PI / 2.0).toRotationMatrix()); - //spaceshipTexture = std::make_unique(CreateTextureDataFromPng("./resources/cap_D.png", CONST_ZIP_FILE)); - //spaceshipBase = LoadFromTextFile02("./resources/spaceship006x.txt", CONST_ZIP_FILE); - //spaceshipBase.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI / 2.0, Eigen::Vector3f::UnitY())).toRotationMatrix());// QuatFromRotateAroundY(M_PI / 2.0).toRotationMatrix()); spaceshipTexture = std::make_unique(CreateTextureDataFromPng("resources/MainCharacter_Base_color_sRGB.png", CONST_ZIP_FILE)); spaceshipBase = LoadFromTextFile02("resources/spaceshipnew001.txt", CONST_ZIP_FILE); spaceshipBase.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY())).toRotationMatrix());// QuatFromRotateAroundY(M_PI / 2.0).toRotationMatrix()); - //spaceshipBase.Move(Vector3f{ 1.2, 0, -5 }); - //spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 }); + spaceshipBase.Move(Vector3f{ -0.52998, 0, -10 }); - //spaceshipBase.Move(Vector3f{ 1.2, 0, -5 }); + spaceship.AssignFrom(spaceshipBase); @@ -308,7 +297,7 @@ namespace ZL for (int i = 0; i < boxCoordsArr.size(); i++) { boxRenderArr[i].AssignFrom(boxBase); - //boxRenderArr[i].data = CreateBaseConvexPolyhedron(1999); + boxRenderArr[i].RefreshVBO(); } @@ -351,8 +340,13 @@ namespace ZL static_cast(Environment::width) / static_cast(Environment::height), Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR); renderer.PushMatrix(); + renderer.LoadIdentity(); - renderer.RotateMatrix(Environment::inverseShipMatrix); + + // Для скайбокса берем только вращение от камеры + Matrix4f view = camera.getViewMatrix(); + view.block<3, 1>(0, 3) = Vector3f::Zero(); // Убираем смещение + renderer.PushSpecialMatrix(view); Vector3f worldLightDir = Vector3f(1.0f, -1.0f, -1.0f).normalized(); @@ -392,7 +386,8 @@ namespace ZL CheckGlError(); - renderer.PopMatrix(); + renderer.PopMatrix(); // Pop special matrix + renderer.PopMatrix(); // Pop original push renderer.PopProjectionMatrix(); renderer.DisableVertexAttribArray(vPositionName); @@ -417,20 +412,20 @@ namespace ZL static_cast(Environment::width) / static_cast(Environment::height), Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR); renderer.PushMatrix(); + renderer.LoadIdentity(); - renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); - renderer.TranslateMatrix({ 0, -6.f, 0 }); //Ship camera offset + + renderer.PushSpecialMatrix(camera.getViewMatrix()); - // Корабль рисуется с учётом разницы между его ориентацией и камерой - // shipWorldOrientation - куда смотрит корабль в мире - // Environment::inverseShipMatrix - обратная матрица камеры - Matrix3f shipRelativeToCamera = Environment::inverseShipMatrix * shipWorldOrientation; - renderer.RotateMatrix(shipRelativeToCamera); + renderer.PushMatrix(); + renderer.TranslateMatrix(Environment::shipState.position); + renderer.RotateMatrix(shipWorldOrientation); if (shipAlive) { glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID()); renderer.DrawVertexRenderStruct(spaceship); } + renderer.PopMatrix(); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -453,7 +448,8 @@ namespace ZL } glDisable(GL_BLEND); - renderer.PopMatrix(); + renderer.PopMatrix(); // Pop special matrix + renderer.PopMatrix(); // Pop original push renderer.PopProjectionMatrix(); renderer.DisableVertexAttribArray(vPositionName); renderer.DisableVertexAttribArray(vTexCoordName); @@ -479,15 +475,17 @@ namespace ZL static_cast(Environment::width) / static_cast(Environment::height), Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR); + renderer.PushMatrix(); + renderer.LoadIdentity(); + renderer.PushSpecialMatrix(camera.getViewMatrix()); + for (int i = 0; i < boxCoordsArr.size(); i++) { if (!boxAlive[i]) continue; renderer.PushMatrix(); - renderer.LoadIdentity(); - renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); - renderer.RotateMatrix(Environment::inverseShipMatrix); - renderer.TranslateMatrix(-Environment::shipState.position); + // Коробки рисуются в мировых координатах + // Но у них есть offset { 0.f, 0.f, 45000.f } renderer.TranslateMatrix({ 0.f, 0.f, 45000.f }); renderer.TranslateMatrix(boxCoordsArr[i].pos); renderer.RotateMatrix(boxCoordsArr[i].m); @@ -498,6 +496,8 @@ namespace ZL renderer.PopMatrix(); } + renderer.PopMatrix(); // Pop special matrix + renderer.PopMatrix(); // Pop original push renderer.PopProjectionMatrix(); renderer.DisableVertexAttribArray(vPositionName); renderer.DisableVertexAttribArray(vTexCoordName); @@ -542,8 +542,15 @@ namespace ZL glViewport(0, 0, Environment::width, Environment::height); + glViewport(0, 0, Environment::width, Environment::height); + CheckGlError(); + + // Обновляем камеру + // camera.follow(Environment::shipState.position, shipWorldOrientation, Environment::zoom, 6.0f); + camera.followOrbit(Environment::shipState.position, camYaw, camPitch, Environment::zoom, 6.0f); + float skyPercent = 0.0; float distance = planetObject.distanceToPlanetSurface(Environment::shipState.position); if (distance > 1500.f) @@ -567,7 +574,9 @@ namespace ZL glClear(GL_DEPTH_BUFFER_BIT); } drawShip(); +#if ENABLE_REMOTE_SHIPS drawRemoteShips(); +#endif drawBoxes(); drawUI(); @@ -615,21 +624,20 @@ namespace ZL renderer.PushMatrix(); renderer.LoadIdentity(); + renderer.PushSpecialMatrix(camera.getViewMatrix()); - renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); - renderer.TranslateMatrix({ 0, -6.f, 0 }); //Ship camera offset - renderer.RotateMatrix(Environment::inverseShipMatrix); - renderer.TranslateMatrix(-Environment::shipState.position); - - - Eigen::Vector3f relativePos = playerState.position;// -Environment::shipPosition; - renderer.TranslateMatrix(relativePos); + renderer.PushMatrix(); + // Позиция удаленного игрока в мире + renderer.TranslateMatrix(playerState.position); // 3. Поворот врага renderer.RotateMatrix(playerState.rotation); renderer.DrawVertexRenderStruct(spaceship); renderer.PopMatrix(); + + renderer.PopMatrix(); + renderer.PopMatrix(); } renderer.PopProjectionMatrix(); @@ -668,126 +676,82 @@ namespace ZL sparkEmitter.update(static_cast(delta)); planetObject.update(static_cast(delta)); + + + + + + // Управление: Джойстик (движение) vs Камера (орбита) + + float discreteMag = 0.0f; int discreteAngle = -1; - float discreteMag = 0; + // 1. Joystick Logic (Movement) auto joystick = uiManager.findJoystick("shipJoystick"); - if (joystick && joystick->isActive) { - float joyX = joystick->getDirectionX(); // -1..1 - float joyY = joystick->getDirectionY(); // -1..1 - float magnitude = joystick->getMagnitude(); // 0..1 - - discreteMag = roundf(magnitude * 10) * 0.1f; - - float angleY = std::atan2(-joyX, -joyY); - - discreteAngle = static_cast(angleY * 180.0f / M_PI); - if (discreteAngle < 0) discreteAngle += 360; - - } - - - - -//<<<<<<< HEAD - // Управление кораблём через джойстик - /*auto joystick = uiManager.findJoystick("shipJoystick"); - if (joystick && joystick->isActive) { - float joyX = joystick->getDirectionX(); // -1..1 - float joyY = joystick->getDirectionY(); // -1..1 - float magnitude = joystick->getMagnitude(); // 0..1 + if (isUsingJoystick && joystick && joystick->isActive) { + float joyX = joystick->getDirectionX(); + float joyY = joystick->getDirectionY(); + float magnitude = joystick->getMagnitude(); if (magnitude > 0.1f) { - // Скорость пропорциональна отклонению джойстика - Environment::shipState.velocity = magnitude * 500.0f * static_cast(delta) / 100.0f; + // Movement logic + Environment::shipState.velocity = 0.0f; - // Направление джойстика относительно камеры - // joyY отрицательный = вперёд, joyX = влево/вправо - float angleY = std::atan2(-joyX, -joyY); + float moveSpeed = 0.5f; - // Локальный поворот в пространстве камеры - Eigen::Quaternionf localRotation(Eigen::AngleAxisf(angleY, Eigen::Vector3f::UnitY())); - Matrix3f localRotMat = localRotation.toRotationMatrix(); + // Local movement vector + Vector3f localMove(joyX, 0.0f, joyY); + + // Transform to world space using current ship rotation + Vector3f worldMove = Environment::shipState.rotation * localMove; - // Преобразуем в мировую ориентацию: камера * локальный_поворот - shipWorldOrientation = Environment::shipState.rotation * localRotMat; - } - else { - Environment::shipState.velocity = 0.0f; - } - } - else if (Environment::tapDownHold && !uiManager.isUiInteraction()) - { - float diffx = Environment::tapDownCurrentPos(0) - Environment::tapDownStartPos(0); - float diffy = Environment::tapDownCurrentPos(1) - Environment::tapDownStartPos(1); + // Apply to position + Environment::shipState.position += worldMove * moveSpeed * static_cast(delta); - // Только управление камерой через drag (вне зоны джойстика) - if (isDraggingCamera) { - if (std::abs(diffy) > 5.0f || std::abs(diffx) > 5.0f) - { - float rotationPower = std::sqrt(diffx * diffx + diffy * diffy); - float deltaAlpha = rotationPower * static_cast(delta) * static_cast(M_PI) / 15000.f; - - Eigen::Vector3f rotationDirection(diffy, diffx, 0.0f); - rotationDirection.normalize(); - - Eigen::Quaternionf rotateQuat(Eigen::AngleAxisf(deltaAlpha, rotationDirection)); - Matrix3f rotateMat = rotateQuat.toRotationMatrix(); - - Environment::shipState.rotation = Environment::shipState.rotation * rotateMat; - Environment::inverseShipMatrix = Environment::shipState.rotation.inverse(); - - // плавное вращение (ВАЖНО!) - Environment::tapDownStartPos = Environment::tapDownCurrentPos; - } - } - } - - float discreteMag; - int discreteAngle; - - if (Environment::tapDownHold) { - float diffx = Environment::tapDownCurrentPos(0) - Environment::tapDownStartPos(0); - float diffy = Environment::tapDownCurrentPos(1) - Environment::tapDownStartPos(1); - - float rawMag = sqrtf(diffx * diffx + diffy * diffy); - float maxRadius = 200.0f; // Максимальный вынос джойстика - - if (rawMag > 10.0f) { // Мертвая зона - // 1. Дискретизируем отклонение (0.0 - 1.0 с шагом 0.1) - float normalizedMag = min(rawMag / maxRadius, 1.0f); - discreteMag = std::round(normalizedMag * 10.0f) / 10.0f; - - // 2. Дискретизируем угол (0-359 градусов) - // atan2 возвращает радианы, переводим в градусы - float radians = atan2f(diffy, diffx); + // Calculate discrete values for network + // Angle 0-359 + float radians = atan2f(joyY, joyX); discreteAngle = static_cast(radians * 180.0f / M_PI); if (discreteAngle < 0) discreteAngle += 360; - - } - else - { - discreteAngle = -1; - discreteMag = 0.0f; + + // Magnitude 0.0-1.0 + discreteMag = (std::min)(magnitude, 1.0f); + discreteMag = std::round(discreteMag * 10.0f) / 10.0f; } } - else - { - discreteAngle = -1; - discreteMag = 0.0f; ->>>>>>> main*/ - //} + // 2. Camera Drag Logic + else if (isDraggingCamera && Environment::tapDownHold && !uiManager.isUiInteraction()) { + float diffx = Environment::tapDownCurrentPos(0) - Environment::tapDownStartPos(0); + float diffy = Environment::tapDownCurrentPos(1) - Environment::tapDownStartPos(1); - + if (std::abs(diffx) > 1.0f || std::abs(diffy) > 1.0f) { + float sensitivity = 0.01f; // Radians per pixel + + camYaw -= diffx * sensitivity; // Yaw: Horizontal drag + camPitch -= diffy * sensitivity; // Pitch: Vertical drag + + // Clamp pitch to avoid flipping + // -80 to 80 degrees in radians + float pitchLimit = 80.0f * static_cast(M_PI) / 180.0f; + if (camPitch > pitchLimit) camPitch = pitchLimit; + if (camPitch < -pitchLimit) camPitch = -pitchLimit; + + // Reset for incremental update + Environment::tapDownStartPos = Environment::tapDownCurrentPos; + } + } + + // Network Update if (discreteAngle != Environment::shipState.discreteAngle || discreteMag != Environment::shipState.discreteMag) { Environment::shipState.discreteAngle = discreteAngle; Environment::shipState.discreteMag = discreteMag; std::string msg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent(); networkClient->Send(msg); - std::cout << "Sending: " << msg << std::endl; + //std::cout << "Sending: " << msg << std::endl; } + Environment::shipState.simulate_physics(delta); Environment::inverseShipMatrix = Environment::shipState.rotation.inverse(); @@ -814,6 +778,7 @@ namespace ZL projectileEmitter.setEmissionPoints(std::vector()); } + std::vector shipCameraPoints; for (const auto& lp : shipLocalEmissionPoints) { Vector3f adjusted = lp + Vector3f{ 0.0f, -Environment::zoom * 0.03f, 0.0f }; @@ -1174,24 +1139,20 @@ namespace ZL uiManager.onMouseDown(uiX, uiY); - bool uiHandled = false; - - for (const auto& button : uiManager.findButton("") ? std::vector>{} : std::vector>{}) { - (void)button; + // Check if joystick became active + auto joystick = uiManager.findJoystick("shipJoystick"); + if (joystick && joystick->isActive) { + isUsingJoystick = true; + isDraggingCamera = false; + Environment::tapDownHold = false; // Don't trigger camera drag } - - auto pressedSlider = [&]() -> std::shared_ptr { - for (const auto& slider : uiManager.findSlider("") ? std::vector>{} : std::vector>{}) { - (void)slider; - } - return nullptr; - }(); - - if (!uiManager.isUiInteraction()) { - // Джойстик обрабатывает управление кораблём, поэтому - // любое нажатие вне UI элементов - это управление камерой - isDraggingShip = false; + else if (!uiManager.isUiInteraction()) { + // No UI interaction (and no joystick), so it's camera drag + isUsingJoystick = false; isDraggingCamera = true; + Environment::tapDownHold = true; + Environment::tapDownStartPos = Vector2f(static_cast(mx), static_cast(my)); + Environment::tapDownCurrentPos = Environment::tapDownStartPos; } } @@ -1200,33 +1161,14 @@ namespace ZL int uiX = mx; int uiY = Environment::height - my; - // Проверяем был ли активен джойстик до отпускания - auto joystick = uiManager.findJoystick("shipJoystick"); - bool wasJoystickActive = joystick && joystick->isActive; - uiManager.onMouseUp(uiX, uiY); - // Сбрасываем состояние если отпустили джойстик - /* - if (wasJoystickActive) { - Environment::shipVelocity = 0.0f; - shipMoveLockActive = false; - rotateShipMat = Matrix3f::Identity(); + if (isUsingJoystick) { + isUsingJoystick = false; } - - if (!uiManager.isUiInteraction()) { - Environment::tapDownHold = false; - Environment::shipVelocity = 0.0f; - - shipMoveLockActive = false; - - if (isDraggingCamera) { - rotateShipMat = Matrix3f::Identity(); - } - - isDraggingShip = false; - isDraggingCamera = false; - }*/ + + isDraggingCamera = false; + Environment::tapDownHold = false; } void Game::handleMotion(int mx, int my) @@ -1236,9 +1178,9 @@ namespace ZL uiManager.onMouseMove(uiX, uiY); - if (Environment::tapDownHold && !uiManager.isUiInteraction()) { - Environment::tapDownCurrentPos(0) = mx; - Environment::tapDownCurrentPos(1) = my; + if (isDraggingCamera && !uiManager.isUiInteraction()) { + Environment::tapDownCurrentPos(0) = static_cast(mx); + Environment::tapDownCurrentPos(1) = static_cast(my); } } diff --git a/src/Game.h b/src/Game.h index 2d6e22d..c3aed2a 100644 --- a/src/Game.h +++ b/src/Game.h @@ -3,6 +3,7 @@ #include "render/Renderer.h" #include "Environment.h" #include "render/TextureManager.h" +#include "render/Camera.h" #include "SparkEmitter.h" #include "planet/PlanetObject.h" #include "UiManager.h" @@ -33,6 +34,7 @@ namespace ZL { bool shouldExit() const { return Environment::exitGameLoop; } Renderer renderer; + Camera camera; TaskManager taskManager; MainThreadHandler mainThreadHandler; @@ -95,6 +97,11 @@ namespace ZL { bool isDraggingShip = false; bool isDraggingCamera = false; + bool isUsingJoystick = false; + + float camYaw = 0.0f; + float camPitch = 0.0f; + Matrix3f rotateShipMat = Matrix3f::Identity(); // Локальный поворот от джойстика Matrix3f shipWorldOrientation = Matrix3f::Identity(); // Ориентация корабля в мире (независимо от камеры) bool shipMoveLockActive = false; diff --git a/src/GameConfig.h b/src/GameConfig.h new file mode 100644 index 0000000..d0e7ba8 --- /dev/null +++ b/src/GameConfig.h @@ -0,0 +1,5 @@ +#pragma once + +// Feature flags to temporarily disable unstable features +#define ENABLE_STONES 0 +#define ENABLE_REMOTE_SHIPS 0 diff --git a/src/planet/PlanetObject.cpp b/src/planet/PlanetObject.cpp index 1216607..cf5c374 100644 --- a/src/planet/PlanetObject.cpp +++ b/src/planet/PlanetObject.cpp @@ -1,4 +1,5 @@ -#include "PlanetObject.h" +#include "GameConfig.h" +#include "PlanetObject.h" #include #include #include "render/OpenGlExtensions.h" @@ -73,7 +74,7 @@ namespace ZL { int lodIndex = planetData.getMaxLodIndex(); planetRenderStruct.data = planetData.getLodLevel(lodIndex).vertexData; - //planetRenderStruct.data.PositionData.resize(9); + planetRenderStruct.RefreshVBO(); @@ -111,34 +112,30 @@ namespace ZL { // 2. Получаем список видимых треугольников auto newIndices = planetData.getTrianglesUnderCameraNew2(Environment::shipState.position); std::sort(newIndices.begin(), newIndices.end()); + // 3. Запуск генерации для новых индексов + for (int idx : newIndices) { + if (planetStones.statuses[idx] == ChunkStatus::Empty) { + planetStones.statuses[idx] = ChunkStatus::Generating; - // 3. Анализируем, что нужно загрузить - for (int triIdx : newIndices) { - if (planetStones.statuses[triIdx] == ChunkStatus::Empty) { - // Помечаем, чтобы не спамить задачами - planetStones.statuses[triIdx] = ChunkStatus::Generating; + // Запускаем задачу в фоне + + taskManager.EnqueueBackgroundTask([this, idx]() { + // Имитация тяжелой работы (генерация меша) + // Тут мы просто копируем базовый камень + скейл/поворот + VertexDataStruct newData = planetStones.inflateOneDataOnly(idx, 0.75f); // 0.75f - scaleModifier - // Отправляем тяжелую математику в TaskManager - taskManager.EnqueueBackgroundTask([this, triIdx]() { - // Выполняется в фоновом потоке: только генерация геометрии в RAM - float scaleModifier = 1.0f; - VertexDataStruct generatedData = planetStones.inflateOneDataOnly(triIdx, scaleModifier); - - // Передаем задачу на загрузку в GPU в очередь главного потока - this->mainThreadHandler.EnqueueMainThreadTask([this, triIdx, data = std::move(generatedData)]() mutable { - // Проверяем актуальность: если треугольник всё еще в списке видимых - auto it = std::find(triangleIndicesToDraw.begin(), triangleIndicesToDraw.end(), triIdx); - if (it != triangleIndicesToDraw.end()) { - stonesToRender[triIdx].data = std::move(data); - stonesToRender[triIdx].RefreshVBO(); // OpenGL вызов - planetStones.statuses[triIdx] = ChunkStatus::Live; + // Когда готово — перекидываем в главный поток для загрузки в GPU + mainThreadHandler.EnqueueMainThreadTask([this, idx, data = std::move(newData)]() mutable { + // Проверяем, всё ли еще актуален этот чанк (вдруг игрок улетел) + // Но пока упростим: всегда грузим, а чистильщик (пункт 4) потом удалит если что + if (planetStones.statuses[idx] == ChunkStatus::Generating) { + stonesToRender[idx].data = std::move(data); + stonesToRender[idx].RefreshVBO(); + planetStones.statuses[idx] = ChunkStatus::Live; } - else { - // Если уже не нужен — просто сбрасываем статус - planetStones.statuses[triIdx] = ChunkStatus::Empty; - } - }); }); + }); + } } @@ -212,8 +209,7 @@ namespace ZL { float centerX = (minX + maxX) * 0.5f; float centerY = (minY + maxY) * 0.5f; - //width = width * 0.995; - //height = height * 0.995; + renderer.PushProjectionMatrix( centerX - width*0.5, centerX + width * 0.5, @@ -263,7 +259,7 @@ namespace ZL { { if (stoneMapFB == nullptr) { - //stoneMapFB = std::make_unique(512, 512, true); + stoneMapFB = std::make_unique(512, 512); } stoneMapFB->Bind(); @@ -281,7 +277,9 @@ namespace ZL { drawPlanet(renderer); +#if ENABLE_STONES drawStones(renderer); +#endif drawAtmosphere(renderer); } @@ -429,15 +427,6 @@ namespace ZL { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID()); - /* - for (int i : triangleIndicesToDraw) - //for (int i = 0; i < stonesToRender.size(); i++) - { - if (stonesToRender[i].data.PositionData.size() > 0) - { - renderer.DrawVertexRenderStruct(stonesToRender[i]); - } - }*/ for (int i : triangleIndicesToDraw) { // КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ: // Проверяем, что данные не просто существуют, а загружены в GPU diff --git a/src/planet/StoneObject.cpp b/src/planet/StoneObject.cpp index babd177..5e361f4 100644 --- a/src/planet/StoneObject.cpp +++ b/src/planet/StoneObject.cpp @@ -110,18 +110,7 @@ namespace ZL { v(2) *= scaleFactors(2); } - /* - // Случайный поворот (например, вокруг трех осей) - Vector4f qx = Eigen::Quaternionf(Eigen::AngleAxisf(getRandomFloat(engine, 0.0f, 360.0f), Eigen::Vector3f::UnitX()));//QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f)); - Vector4f qy = Eigen::Quaternionf(Eigen::AngleAxisf(getRandomFloat(engine, 0.0f, 360.0f), Eigen::Vector3f::UnitY()));//QuatFromRotateAroundY(getRandomFloat(engine, 0.0f, 360.0f)); - Vector4f qz = Eigen::Quaternionf(Eigen::AngleAxisf(getRandomFloat(engine, 0.0f, 360.0f), Eigen::Vector3f::UnitZ()));//QuatFromRotateAroundZ(getRandomFloat(engine, 0.0f, 360.0f)); - Vector4f qFinal = slerp(qx, qy, 0.5f); // Простой пример комбинирования - qFinal = slerp(qFinal, qz, 0.5f).normalized(); - Matrix3f rotationMatrix = QuatToMatrix(qFinal); - for (Vector3f& v : initialVertices) { - v = MultMatrixVector(rotationMatrix, v); - }*/ // 3. Сглаженные Нормали и Формирование Mesh VertexDataStruct result; @@ -259,18 +248,7 @@ namespace ZL { getRandomFloat(engine, SCALE_MIN, SCALE_MAX) }; - /* - if (tIdx == 0) - { - instance.scale = instance.scale * 0.7f; - }*/ - /* - Vector4f qx = QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f)); - Vector4f qy = QuatFromRotateAroundY(getRandomFloat(engine, 0.0f, 360.0f)); - Vector4f qz = QuatFromRotateAroundZ(getRandomFloat(engine, 0.0f, 360.0f)); - instance.rotation = slerp(slerp(qx, qy, 0.5f), qz, 0.5f).normalized(); - */ instance.rotation = Vector4f(0.f, 0.f, 0.f, 1.f); group.allInstances[tIdx].push_back(instance); } @@ -291,9 +269,15 @@ namespace ZL { return result; } + // Helper to get the singleton base stone data + const VertexDataStruct& GetBaseStone() { + static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337); + return baseStone; + } + VertexRenderStruct StoneGroup::inflateOne(int index, float scaleModifier) { - static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337); + const VertexDataStruct& baseStone = GetBaseStone(); VertexRenderStruct result; @@ -324,10 +308,11 @@ namespace ZL { VertexDataStruct StoneGroup::inflateOneDataOnly(int index, float scaleModifier) { - static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337); + const VertexDataStruct& baseStone = GetBaseStone(); VertexDataStruct result; - + // Pre-reserve logic? Optional but good. + // Since we don't know exact size (depends on stone count), maybe just standard push_back. for (const auto& inst : allInstances[index]) { Matrix3f rotMat = inst.rotation.toRotationMatrix(); @@ -342,7 +327,13 @@ namespace ZL { result.PositionData.push_back(rotMat * p + inst.position); result.NormalData.push_back(rotMat * n); - result.TexCoordData.push_back(baseStone.TexCoordData[j]); + + if (j < baseStone.TexCoordData.size()) { + result.TexCoordData.push_back(baseStone.TexCoordData[j]); + } + else { + result.TexCoordData.push_back({ 0.f, 0.f }); + } } } diff --git a/src/render/Camera.cpp b/src/render/Camera.cpp new file mode 100644 index 0000000..347beb9 --- /dev/null +++ b/src/render/Camera.cpp @@ -0,0 +1,57 @@ +#include "render/Camera.h" + +namespace ZL { + + using Eigen::Vector3f; + using Eigen::Matrix3f; + using Eigen::Matrix4f; + + Camera::Camera() + : position(Vector3f::Zero()) + , rotation(Matrix3f::Identity()) + { + } + + void Camera::follow(const Vector3f& targetPos, const Matrix3f& targetRot, float distance, float height) + { + Vector3f offset(0.0f, height, distance); + Vector3f globalOffset = targetRot * offset; + + position = targetPos + globalOffset; + rotation = targetRot; + } + + void Camera::followOrbit(const Vector3f& targetPos, float yaw, float pitch, float distance, float height) + { + // Convert yaw/pitch to rotation matrix + // Yaw (Y-axis), Pitch (X-axis) + + Eigen::AngleAxisf yawRot(yaw, Vector3f::UnitY()); + Eigen::AngleAxisf pitchRot(pitch, Vector3f::UnitX()); + + // Combine rotations: Yaw * Pitch (order matters) + Eigen::Quaternionf q = yawRot * pitchRot; + rotation = q.toRotationMatrix(); + + Vector3f offset(0.0f, height, distance); + Vector3f globalOffset = rotation * offset; + + position = targetPos + globalOffset; + } + + Matrix4f Camera::getViewMatrix() const + { + // View Matrix = (Translate * Rotate)^-1 + // = Rotate^-1 * Translate^-1 + + Matrix3f R_inv = rotation.transpose(); + Vector3f T_inv = -position; + + Matrix4f view = Matrix4f::Identity(); + + view.block<3,3>(0,0) = R_inv; + view.block<3,1>(0,3) = R_inv * T_inv; + + return view; + } +} diff --git a/src/render/Camera.h b/src/render/Camera.h new file mode 100644 index 0000000..09c37ff --- /dev/null +++ b/src/render/Camera.h @@ -0,0 +1,25 @@ +#pragma once +#include + +namespace ZL { + + class Camera { + public: + Camera(); + + // Обновление позиции камеры (например, слежение за кораблем) + void follow(const Eigen::Vector3f& targetPos, const Eigen::Matrix3f& targetRot, float distance, float height); + + // Follow target with orbital rotation (yaw/pitch) independent of target rotation + void followOrbit(const Eigen::Vector3f& targetPos, float yaw, float pitch, float distance, float height); + + // Получить матрицу вида (View Matrix) для шейдера + Eigen::Matrix4f getViewMatrix() const; + + Eigen::Vector3f getPosition() const { return position; } + + private: + Eigen::Vector3f position; + Eigen::Matrix3f rotation; // Ориентация камеры + }; +}