diff --git a/CMakeLists.txt b/CMakeLists.txt index 8694744..34b46d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -446,6 +446,8 @@ add_executable(space-game001 Perlin.h StoneObject.cpp StoneObject.h + FrameBuffer.cpp + FrameBuffer.h ) # Установка проекта по умолчанию для Visual Studio diff --git a/FrameBuffer.cpp b/FrameBuffer.cpp new file mode 100644 index 0000000..1cc8462 --- /dev/null +++ b/FrameBuffer.cpp @@ -0,0 +1,49 @@ +#include "FrameBuffer.h" +#include +#include "Environment.h" + +namespace ZL { + + FrameBuffer::FrameBuffer(int w, int h) : width(w), height(h) { + // 1. FBO + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + // 2. , "" + glGenTextures(1, &textureID); + glBindTexture(GL_TEXTURE_2D, textureID); + + // + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // 3. FBO + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0); + + // + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + std::cerr << "Error: Framebuffer is not complete!" << std::endl; + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + FrameBuffer::~FrameBuffer() { + glDeleteFramebuffers(1, &fbo); + glDeleteTextures(1, &textureID); + } + + void FrameBuffer::Bind() { + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glViewport(0, 0, width, height); // : + } + + void FrameBuffer::Unbind() { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + // , + // , Environment::width/height + glViewport(0, 0, Environment::width, Environment::height); + } + +} // namespace ZL \ No newline at end of file diff --git a/FrameBuffer.h b/FrameBuffer.h new file mode 100644 index 0000000..67afb26 --- /dev/null +++ b/FrameBuffer.h @@ -0,0 +1,29 @@ +#pragma once +#include "OpenGlExtensions.h" +#include + +namespace ZL { + + class FrameBuffer { + private: + GLuint fbo = 0; + GLuint textureID = 0; + int width, height; + + public: + FrameBuffer(int w, int h); + ~FrameBuffer(); + + // , VBOHolder + FrameBuffer(const FrameBuffer&) = delete; + FrameBuffer& operator=(const FrameBuffer&) = delete; + + void Bind(); // + void Unbind(); // + + GLuint getTextureID() const { return textureID; } + int getWidth() const { return width; } + int getHeight() const { return height; } + }; + +} // namespace ZL \ No newline at end of file diff --git a/Game.cpp b/Game.cpp index c2e61fa..43de537 100755 --- a/Game.cpp +++ b/Game.cpp @@ -137,6 +137,7 @@ namespace ZL renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("defaultColorPlanet", "./shaders/defaultColorPlanet.vertex", "./shaders/defaultColorPlanet_web.fragment", CONST_ZIP_FILE); #else renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE); @@ -144,7 +145,8 @@ namespace ZL renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env_sky.vertex", "./shaders/env_sky_desktop.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("defaultColor2", "./shaders/defaultColor_fog2.vertex", "./shaders/defaultColor_fog2_desktop.fragment", CONST_ZIP_FILE); - + renderer.shaderManager.AddShaderFromFiles("defaultColorStones", "./shaders/defaultColor_fog_stones.vertex", "./shaders/defaultColor_fog_stones_desktop.fragment", CONST_ZIP_FILE); + //renderer.shaderManager.AddShaderFromFiles("defaultColorBake", "./shaders/defaultColor_fog_bake.vertex", "./shaders/defaultColor_fog_stones_bake.fragment", CONST_ZIP_FILE); #endif cubemapTexture = std::make_shared( @@ -181,8 +183,8 @@ namespace ZL for (int i = 0; i < boxCoordsArr.size(); i++) { - //boxRenderArr[i].AssignFrom(boxBase); - boxRenderArr[i].data = CreateBaseConvexPolyhedron(1999); + boxRenderArr[i].AssignFrom(boxBase); + //boxRenderArr[i].data = CreateBaseConvexPolyhedron(1999); boxRenderArr[i].RefreshVBO(); } @@ -357,8 +359,8 @@ namespace ZL renderer.TranslateMatrix(boxCoordsArr[i].pos); renderer.RotateMatrix(boxCoordsArr[i].m); - //glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID()); - glBindTexture(GL_TEXTURE_2D, rockTexture->getTexID()); + glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID()); + //glBindTexture(GL_TEXTURE_2D, rockTexture->getTexID()); renderer.DrawVertexRenderStruct(boxRenderArr[i]); renderer.PopMatrix(); @@ -624,6 +626,22 @@ namespace ZL } else if (event.type == SDL_KEYUP) { + if (event.key.keysym.sym == SDLK_a) + { + planetObject.x += 1; + } + if (event.key.keysym.sym == SDLK_s) + { + planetObject.x -= 1; + } + if (event.key.keysym.sym == SDLK_q) + { + planetObject.y += 1; + } + if (event.key.keysym.sym == SDLK_w) + { + planetObject.y -= 1; + } if (event.key.keysym.sym == SDLK_i) { Environment::shipVelocity += 500.f; diff --git a/PlanetData.cpp b/PlanetData.cpp index dc334ca..dc3eb5f 100644 --- a/PlanetData.cpp +++ b/PlanetData.cpp @@ -327,10 +327,16 @@ namespace ZL { // UV- // . const std::array triangleUVs = { + Vector2f(0.5f, 1.0f), + Vector2f(0.0f, 1.0f - sqrt(3)*0.5), + Vector2f(1.0f, 1.0f - sqrt(3) * 0.5), + + }; + /*const std::array triangleUVs2 = { Vector2f(0.0f, 0.0f), Vector2f(1.0f, 0.0f), Vector2f(0.0f, 1.0f) - }; + };*/ result.VertexIDs.reserve(geometry.size() * 3); // ID for (const auto& t : geometry) { @@ -341,6 +347,7 @@ namespace ZL { // NormalData ( = ) result.vertexData.NormalData.push_back(t.data[i].normalized()); result.vertexData.TexCoordData.push_back(triangleUVs[i]); + //result.vertexData.TexCoord2Data.push_back(triangleUVs2[i]); // VertexIDs result.VertexIDs.push_back(t.ids[i]); diff --git a/PlanetData.h b/PlanetData.h index 79ff683..553bd3c 100644 --- a/PlanetData.h +++ b/PlanetData.h @@ -16,7 +16,8 @@ namespace ZL { VertexID generateEdgeID(const VertexID& id1, const VertexID& id2); - constexpr static int MAX_LOD_LEVELS = 6; + //constexpr static int MAX_LOD_LEVELS = 6; + constexpr static int MAX_LOD_LEVELS = 1; struct Triangle { diff --git a/PlanetObject.cpp b/PlanetObject.cpp index 5f6d43e..4b08a0b 100644 --- a/PlanetObject.cpp +++ b/PlanetObject.cpp @@ -23,12 +23,25 @@ namespace ZL { planetRenderStruct.data = planetData.getLodLevel(lodIndex).vertexData; planetRenderStruct.RefreshVBO(); - sandTexture = std::make_unique(CreateTextureDataFromPng("./resources/sand2.png", "")); - stoneTexture = std::make_unique(CreateTextureDataFromPng("./resources/rock.png", "")); + planetRenderStructCut.data = planetData.getLodLevel(lodIndex).vertexData; + planetRenderStructCut.data.PositionData.resize(3); + planetRenderStructCut.RefreshVBO(); + //sandTexture = std::make_unique(CreateTextureDataFromPng("./resources/sand2.png", "")); + sandTexture = std::make_unique(CreateTextureDataFromPng("./resources/sandx.png", "")); + stoneTexture = std::make_unique(CreateTextureDataFromPng("./resources/rockx.png", "")); // Атмосфера planetAtmosphereRenderStruct.data = planetData.getAtmosphereLod().vertexData; planetAtmosphereRenderStruct.RefreshVBO(); + + + + planetStones = CreateStoneGroupData(777, planetData.getLodLevel(lodIndex)); + planetStones.inflate({ 0/*,1,2,3,4,5,6,7*/ }); + planetStonesRenderStruct.AssignFrom(planetStones.mesh); + planetStonesRenderStruct.RefreshVBO(); + + } void PlanetObject::prepareDrawData() { @@ -37,81 +50,124 @@ namespace ZL { } void PlanetObject::update(float deltaTimeMs) { - // Получаем видимые треугольники, передавая позицию корабля + // 1. Получаем базовые треугольники под камерой auto lr = planetData.getTrianglesUnderCamera(Environment::shipPosition); int currentLod = planetData.getCurrentLodIndex(); - const auto& fullMesh = planetData.getLodLevel(currentLod).vertexData; - planetRenderYellowStruct.data.PositionData.clear(); - planetRenderYellowStruct.data.TexCoordData.clear(); - - triangleIndicesToDraw.clear(); - std::set usedYellow; + // Временный вектор для сбора новых индексов + std::vector newIndices; + std::set used; + // Рекурсивно (или итеративно, как у тебя) собираем индексы видимых зон for (int i : lr) { - planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3]); - planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3 + 1]); - planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3 + 2]); - planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3]); - planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3 + 1]); - planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3 + 2]); - usedYellow.insert(i); - triangleIndicesToDraw.push_back(i); - } - - for (int i : lr) { + if (used.insert(i).second) newIndices.push_back(i); + auto neighbors = planetData.findNeighbors(i, currentLod); for (int n : neighbors) { - if (usedYellow.count(n) == 0) { - usedYellow.insert(n); - triangleIndicesToDraw.push_back(n); - planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n * 3]); - planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n * 3 + 1]); - planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n * 3 + 2]); - planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n * 3]); - planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n * 3 + 1]); - planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n * 3 + 2]); - } - auto neighbors2 = planetData.findNeighbors(n, currentLod); + if (used.insert(n).second) newIndices.push_back(n); + auto neighbors2 = planetData.findNeighbors(n, currentLod); for (int n2 : neighbors2) { - if (usedYellow.count(n2) == 0) { - usedYellow.insert(n2); - triangleIndicesToDraw.push_back(n2); - planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n2 * 3]); - planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n2 * 3 + 1]); - planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n2 * 3 + 2]); - planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n2 * 3]); - planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n2 * 3 + 1]); - planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n2 * 3 + 2]); - } + if (used.insert(n2).second) newIndices.push_back(n2); } } } - planetRenderYellowStruct.RefreshVBO(); - planetStonesRenderStruct.data = CreateConvexPolyhedron(777, planetData.getLodLevel(5), triangleIndicesToDraw); - planetStonesRenderStruct.RefreshVBO(); + // 2. Сортируем новый список, чтобы порядок не влиял на сравнение + std::sort(newIndices.begin(), newIndices.end()); + + // 3. Сравниваем с тем, что было нарисовано в прошлый раз + if (newIndices != triangleIndicesToDraw) { + // Обновляем список индексов (используем move для эффективности) + triangleIndicesToDraw = std::move(newIndices); + + // --- ОБНОВЛЯЕМ ЖЕЛТУЮ ЗОНУ (только когда изменился состав треугольников) --- + const auto& fullMesh = planetData.getLodLevel(currentLod).vertexData; + planetRenderYellowStruct.data.PositionData.clear(); + planetRenderYellowStruct.data.TexCoordData.clear(); + + for (int i : triangleIndicesToDraw) { + // Копируем геометрию для подсветки + for (int j = 0; j < 3; ++j) { + planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3 + j]); + planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3 + j]); + } + } + planetRenderYellowStruct.RefreshVBO(); + + // --- ОБНОВЛЯЕМ КАМНИ (через новую структуру StoneGroup) --- + //planetStones.inflate(triangleIndicesToDraw); + // Используем AssignFrom, он внутри сам вызывает RefreshVBO + //planetStonesRenderStruct.AssignFrom(planetStones.mesh); + } + } - - void PlanetObject::draw(Renderer& renderer) { + void PlanetObject::bakeStoneTexture(Renderer& renderer) { + // 1. Создаем FB (размер 512x512 для четкости) - prepareDrawData(); - //-------------------------- + glViewport(0, 0, 1024, 1024); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - drawPlanet(renderer); - //drawYellowZone(renderer); - drawStones(renderer); + /* + static const std::string stoneShader = "defaultColor2"; + renderer.shaderManager.PushShader(stoneShader); - drawAtmosphere(renderer); - } + static const std::string vPositionName = "vPosition"; + static const std::string vColorName = "vColor"; + static const std::string vNormalName = "vNormal"; + static const std::string vTexCoordName = "vTexCoord"; + //static const std::string vTexCoord3Name = "vTexCoord3"; + static const std::string textureUniformName = "Texture"; - void PlanetObject::drawPlanet(Renderer& renderer) - { - static const std::string defaultShaderName = "defaultColor"; + renderer.EnableVertexAttribArray(vPositionName); + renderer.EnableVertexAttribArray(vColorName); + renderer.EnableVertexAttribArray(vNormalName); + renderer.EnableVertexAttribArray(vTexCoordName); + + // 2. Очищаем (черный фон - это "нет камня") + glClearColor(0.0f, 0.5f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // 3. Настраиваем камеру (Ортографическая проекция над треугольником) + // Смотрим на плоскость, где лежит эталонный треугольник + renderer.PushProjectionMatrix(0.666667f, 1.777779f, 2000, 200000); + renderer.PushMatrix(); + renderer.LoadIdentity(); + renderer.TranslateMatrix({ 0, 0, -45000.0f }); // Отодвигаемся, чтобы видеть камни + + // 4. Рендерим камни + // Берем семена и параметры из первого треугольника (индекс 0) + // Используем упрощенный вызов отрисовки геометрии камней + + // Рисуем меш камней для ОДНОГО эталонного треугольника + // Здесь используем уже созданную нами функцию inflate для индекса 0 + planetStones.inflate({ 0 }); + VertexRenderStruct tempStoneRender; + tempStoneRender.AssignFrom(planetStones.mesh); + + renderer.DrawVertexRenderStruct(tempStoneRender); + + renderer.PopMatrix(); + renderer.PopProjectionMatrix(); + + //stoneMapFB->Unbind(); + + renderer.DisableVertexAttribArray(vPositionName); + renderer.DisableVertexAttribArray(vColorName); + renderer.DisableVertexAttribArray(vNormalName); + renderer.DisableVertexAttribArray(vTexCoordName); + renderer.shaderManager.PopShader(); + + + + // Восстанавливаем вьюпорт под экран + glViewport(0, 0, Environment::width, Environment::height);*/ + + //static const std::string defaultShaderName = "defaultColor"; static const std::string defaultShaderName2 = "defaultColor2"; static const std::string vPositionName = "vPosition"; static const std::string vColorName = "vColor"; @@ -120,7 +176,10 @@ namespace ZL { //static const std::string vTexCoord3Name = "vTexCoord3"; static const std::string textureUniformName = "Texture"; - renderer.shaderManager.PushShader(defaultShaderName); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + renderer.shaderManager.PushShader(defaultShaderName2); renderer.RenderUniform1i(textureUniformName, 0); renderer.EnableVertexAttribArray(vPositionName); renderer.EnableVertexAttribArray(vColorName); @@ -133,6 +192,166 @@ namespace ZL { const float currentZNear = zRange.first; const float currentZFar = zRange.second; + // 2. Применяем динамическую матрицу проекции + /*renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, + 1.0, + currentZNear, currentZFar);*/ + renderer.PushProjectionMatrix( + -PlanetData::PLANET_RADIUS*sqrt(2)*(1-0/100.f)*0.5, + PlanetData::PLANET_RADIUS * sqrt(2) * (1 - 0 / 100.f) * 0.5, + -PlanetData::PLANET_RADIUS * sqrt(2) * (1 - 0 / 100.f) * 0.5, + PlanetData::PLANET_RADIUS * sqrt(2) * (1 - 0 / 100.f) * 0.5, + currentZNear, currentZFar); + + renderer.PushMatrix(); + renderer.LoadIdentity(); + //renderer.RotateMatrix(Environment::inverseShipMatrix); + renderer.TranslateMatrix(Vector3f{ 0,0,-45000 }); + + + Vector4f q1 = QuatFromRotateAroundX(-M_PI * 45.0 / 180.0); + Vector4f q2 = QuatFromRotateAroundY(M_PI * 45.0 / 180.0); + //Vector4f q3 = {-cos(0.5*M_PI * x / 180.0), -cos(0.5 * M_PI * x / 180.0), -cos(0.5 * M_PI * x / 180.0),sin(0.5 * M_PI * x / 180.0) }; + + Matrix3f r1 = QuatToMatrix(q1); + + Matrix3f r2 = QuatToMatrix(q2); + + //Matrix3f r3 = QuatToMatrix(q3); + + Matrix3f invr = InverseMatrix( MultMatrixMatrix(r2, r1)); + + renderer.RotateMatrix(invr); + + + + const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix(); + + + Vector3f lightDir_World = Vector3f(1.0f, 0.0f, -1.0f).normalized(); + // В OpenGL/шейдерах удобнее работать с вектором, указывающим ОТ источника к поверхности. + Vector3f lightDirection_World = -lightDir_World; // Вектор, направленный от источника + Vector3f lightDirection_View; + + lightDirection_View.v[0] = viewMatrix.m[0] * lightDirection_World.v[0] + viewMatrix.m[4] * lightDirection_World.v[1] + viewMatrix.m[8] * lightDirection_World.v[2]; + lightDirection_View.v[1] = viewMatrix.m[1] * lightDirection_World.v[0] + viewMatrix.m[5] * lightDirection_World.v[1] + viewMatrix.m[9] * lightDirection_World.v[2]; + lightDirection_View.v[2] = viewMatrix.m[2] * lightDirection_World.v[0] + viewMatrix.m[6] * lightDirection_World.v[1] + viewMatrix.m[10] * lightDirection_World.v[2]; + lightDirection_View = lightDirection_View.normalized(); // Нормализуем на всякий случай + + // Установка uniform-переменной + // Предполагается, что RenderUniform3fv определена в Renderer.h + /* + renderer.RenderUniform3fv("uLightDirection", &lightDirection_View.v[0]); + renderer.RenderUniformMatrix4fv("ModelViewMatrix", false, &viewMatrix.m[0]); + + renderer.RenderUniform1f("uDistanceToPlanetSurface", dist); + renderer.RenderUniform1f("uCurrentZFar", currentZFar); + Vector3f color2 = { 1.0, 1.0, 1.0 }; + + renderer.RenderUniform3fv("uColor", &color2.v[0]);*/ + + //glEnable(GL_BLEND); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID()); + + + //planetRenderStructCut.AssignFrom(planetRenderStruct.data); + //planetRenderStructCut.data.PositionData.resize(3); + //planetRenderStructCut.RefreshVBO(); + renderer.DrawVertexRenderStruct(planetRenderStructCut); + + + //planetStones.inflate({0/*,1,2,3,4,5,6,7*/}); + //planetStonesRenderStruct.AssignFrom(planetStones.mesh); + //planetStonesRenderStruct.RefreshVBO(); + + + glClear(GL_DEPTH_BUFFER_BIT); + + if (planetStonesRenderStruct.data.PositionData.size() > 0) + { + + //glBindTexture(GL_TEXTURE_2D, fb->getTextureID()); + glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID()); + renderer.DrawVertexRenderStruct(planetStonesRenderStruct); + //glDisable(GL_BLEND); + CheckGlError(); + } + + + renderer.PopMatrix(); + renderer.PopProjectionMatrix(); + //renderer.DisableVertexAttribArray(vTexCoord3Name); + renderer.DisableVertexAttribArray(vTexCoordName); + renderer.DisableVertexAttribArray(vNormalName); + renderer.DisableVertexAttribArray(vColorName); + renderer.DisableVertexAttribArray(vPositionName); + renderer.shaderManager.PopShader(); + CheckGlError(); + + + //glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + + } + + + void PlanetObject::draw(Renderer& renderer) { + + prepareDrawData(); + + + { + if (stoneMapFB == nullptr) + { + stoneMapFB = std::make_unique(1024, 1024); + } + stoneMapFB->Bind(); + + bakeStoneTexture(renderer); + + stoneMapFB->Unbind(); + + } + + //bakeStoneTexture(renderer); + + glViewport(0, 0, Environment::width, Environment::height); + //-------------------------- + + drawPlanet(renderer); + //drawYellowZone(renderer); + //drawStones(renderer); + + //drawAtmosphere(renderer); + } + + void PlanetObject::drawPlanet(Renderer& renderer) + { + static const std::string defaultShaderName = "defaultColorStones"; + + static const std::string vPositionName = "vPosition"; + static const std::string vColorName = "vColor"; + static const std::string vNormalName = "vNormal"; + static const std::string vTexCoordName = "vTexCoord"; + static const std::string vTexCoord2Name = "vTexCoord2"; + //static const std::string vTexCoord3Name = "vTexCoord3"; + static const std::string textureUniformName = "Texture"; + + renderer.shaderManager.PushShader(defaultShaderName); + + renderer.EnableVertexAttribArray(vPositionName); + renderer.EnableVertexAttribArray(vColorName); + renderer.EnableVertexAttribArray(vNormalName); + renderer.EnableVertexAttribArray(vTexCoordName); + //renderer.EnableVertexAttribArray(vTexCoord3Name); + + float dist = planetData.distanceToPlanetSurface(Environment::shipPosition); + auto zRange = planetData.calculateZRange(dist); + const float currentZNear = zRange.first; + const float currentZFar = zRange.second; + // 2. Применяем динамическую матрицу проекции renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, static_cast(Environment::width) / static_cast(Environment::height), @@ -146,7 +365,6 @@ namespace ZL { const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix(); - Vector3f lightDir_World = Vector3f(1.0f, 0.0f, -1.0f).normalized(); // В OpenGL/шейдерах удобнее работать с вектором, указывающим ОТ источника к поверхности. Vector3f lightDirection_World = -lightDir_World; // Вектор, направленный от источника @@ -164,10 +382,20 @@ namespace ZL { renderer.RenderUniform1f("uDistanceToPlanetSurface", dist); renderer.RenderUniform1f("uCurrentZFar", currentZFar); - //glEnable(GL_BLEND); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения + renderer.RenderUniform1f("testShift1", x/500.f); + renderer.RenderUniform1f("testShift2", y / 5000.f); + renderer.RenderUniform1i("Texture", 0); + + renderer.RenderUniform1i("StoneMap", 1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, stoneMapFB->getTextureID()); + + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID()); + + + renderer.DrawVertexRenderStruct(planetRenderStruct); //glDisable(GL_BLEND); CheckGlError(); @@ -176,6 +404,7 @@ namespace ZL { renderer.PopMatrix(); renderer.PopProjectionMatrix(); //renderer.DisableVertexAttribArray(vTexCoord3Name); + renderer.DisableVertexAttribArray(vTexCoord2Name); renderer.DisableVertexAttribArray(vTexCoordName); renderer.DisableVertexAttribArray(vNormalName); renderer.DisableVertexAttribArray(vColorName); @@ -188,7 +417,7 @@ namespace ZL { void PlanetObject::drawStones(Renderer& renderer) { - static const std::string defaultShaderName = "defaultColor"; + //static const std::string defaultShaderName = "defaultColor"; static const std::string defaultShaderName2 = "defaultColor2"; static const std::string vPositionName = "vPosition"; static const std::string vColorName = "vColor"; @@ -223,7 +452,6 @@ namespace ZL { const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix(); - Vector3f lightDir_World = Vector3f(1.0f, 0.0f, -1.0f).normalized(); // В OpenGL/шейдерах удобнее работать с вектором, указывающим ОТ источника к поверхности. Vector3f lightDirection_World = -lightDir_World; // Вектор, направленный от источника @@ -250,6 +478,7 @@ namespace ZL { if (planetStonesRenderStruct.data.PositionData.size() > 0) { + //glBindTexture(GL_TEXTURE_2D, fb->getTextureID()); glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID()); renderer.DrawVertexRenderStruct(planetStonesRenderStruct); //glDisable(GL_BLEND); diff --git a/PlanetObject.h b/PlanetObject.h index af16c8c..41b3afb 100644 --- a/PlanetObject.h +++ b/PlanetObject.h @@ -15,6 +15,8 @@ #include #include "Perlin.h" #include "PlanetData.h" +#include "StoneObject.h" +#include "FrameBuffer.h" namespace ZL { @@ -25,9 +27,11 @@ namespace ZL { // Данные только для рендеринга (OpenGL specific) VertexRenderStruct planetRenderStruct; + VertexRenderStruct planetRenderStructCut; VertexRenderStruct planetRenderYellowStruct; VertexRenderStruct planetAtmosphereRenderStruct; VertexRenderStruct planetStonesRenderStruct; + StoneGroup planetStones; std::vector triangleIndicesToDraw; @@ -37,11 +41,17 @@ namespace ZL { bool drawDataDirty = true; void prepareDrawData(); + std::unique_ptr stoneMapFB; + public: PlanetObject(); + int x = 0; + int y = 0; + void init(); void update(float deltaTimeMs); + void bakeStoneTexture(Renderer& renderer); void draw(Renderer& renderer); void drawStones(Renderer& renderer); void drawPlanet(Renderer& renderer); diff --git a/Renderer.cpp b/Renderer.cpp index 69a206b..6b4a6c9 100755 --- a/Renderer.cpp +++ b/Renderer.cpp @@ -294,6 +294,18 @@ namespace ZL { glBufferData(GL_ARRAY_BUFFER, data.TexCoordData.size() * 8, &data.TexCoordData[0], GL_STATIC_DRAW); } + /*if (data.TexCoord2Data.size() > 0) + { + if (!texCoord2VBO) + { + texCoord2VBO = std::make_shared(); + } + + glBindBuffer(GL_ARRAY_BUFFER, texCoord2VBO->getBuffer()); + + glBufferData(GL_ARRAY_BUFFER, data.TexCoord2Data.size() * 8, &data.TexCoord2Data[0], GL_STATIC_DRAW); + }*/ + if (data.TexCoord3Data.size() > 0) { if (!texCoord3VBO) @@ -442,6 +454,18 @@ namespace ZL { throw std::runtime_error("Projection matrix stack overflow!!!!"); } } + + void Renderer::PushProjectionMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar) + { + Matrix4f m = MakeOrthoMatrix(xmin, xmax, ymin, ymax, zNear, zFar); + ProjectionMatrixStack.push(m); + SetMatrix(); + + if (ProjectionMatrixStack.size() > CONST_MATRIX_STACK_SIZE) + { + throw std::runtime_error("Projection matrix stack overflow!!!!"); + } + } void Renderer::PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar) { @@ -764,6 +788,7 @@ namespace ZL { static const std::string vBinormal("vBinormal"); static const std::string vColor("vColor"); static const std::string vTexCoord("vTexCoord"); + //static const std::string vTexCoord2("vTexCoord2"); static const std::string vTexCoord3("vTexCoord3"); static const std::string vPosition("vPosition"); @@ -798,7 +823,7 @@ namespace ZL { if (VertexRenderStruct.data.TexCoord3Data.size() > 0) { glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoord3VBO->getBuffer()); - VertexAttribPointer2fv(vTexCoord3, 0, NULL); + VertexAttribPointer3fv(vTexCoord3, 0, NULL); } glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.positionVBO->getBuffer()); diff --git a/Renderer.h b/Renderer.h index c102d77..edc3a8e 100755 --- a/Renderer.h +++ b/Renderer.h @@ -44,6 +44,7 @@ namespace ZL { { std::vector PositionData; std::vector TexCoordData; + //std::vector TexCoord2Data; std::vector TexCoord3Data; std::vector NormalData; std::vector TangentData; @@ -64,6 +65,7 @@ namespace ZL { std::shared_ptr vao; std::shared_ptr positionVBO; std::shared_ptr texCoordVBO; + //std::shared_ptr texCoord2VBO; std::shared_ptr texCoord3VBO; std::shared_ptr normalVBO; std::shared_ptr tangentVBO; @@ -95,6 +97,7 @@ namespace ZL { void InitOpenGL(); void PushProjectionMatrix(float width, float height, float zNear = 0.f, float zFar = 1.f); + void PushProjectionMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar); void PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar); void PopProjectionMatrix(); diff --git a/ShaderManager.cpp b/ShaderManager.cpp index c293acf..b953977 100755 --- a/ShaderManager.cpp +++ b/ShaderManager.cpp @@ -39,6 +39,7 @@ namespace ZL { glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled); glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog); + if (!vertexShaderCompiled) { throw std::runtime_error("Failed to compile vertex shader code!"); diff --git a/StoneObject.cpp b/StoneObject.cpp index 7273b38..d6db66b 100644 --- a/StoneObject.cpp +++ b/StoneObject.cpp @@ -47,7 +47,7 @@ namespace ZL { // --- ( ) --- //const float BASE_SCALE = 3.0f; // - const float BASE_SCALE = 20.0f; // + const float BASE_SCALE = 800.0f; // const float MIN_AXIS_SCALE = 0.5f; // / const float MAX_AXIS_SCALE = 1.5f; // / const float MIN_PERTURBATION = 0.05f; // @@ -201,107 +201,70 @@ namespace ZL { return result; } - VertexDataStruct CreateConvexPolyhedron(uint64_t seed, const LodLevel& planetLodLevel, const std::vector& triangleIndices) { - - VertexDataStruct finalMesh; + StoneGroup CreateStoneGroupData(uint64_t globalSeed, const LodLevel& planetLodLevel) { + StoneGroup group; const int STONES_PER_TRIANGLE = 100; + + // LOD + group.allInstances.resize(planetLodLevel.triangles.size()); - // ( , ) - const float MIN_AXIS_SCALE = 0.5f; - const float MAX_AXIS_SCALE = 1.5f; + for (size_t tIdx = 0; tIdx < planetLodLevel.triangles.size(); ++tIdx) { + const Triangle& tri = planetLodLevel.triangles[tIdx]; + std::mt19937 engine(static_cast(globalSeed)); - // 1. , - // seed , , - // seed . - uint64_t baseSeed = 1337; // seed - VertexDataStruct baseStone = CreateBaseConvexPolyhedron(baseSeed); + for (int i = 0; i < STONES_PER_TRIANGLE; ++i) { + StoneInstance instance; + instance.seed = globalSeed;// + tIdx * 1000 + i; // + + instance.position = GetRandomPointOnTriangle(tri, engine); - // 2. - for (int triangleIndex : triangleIndices) { - - std::mt19937 engine(static_cast(seed)); - - - if (triangleIndex >= planetLodLevel.triangles.size()) { - // - continue; - } - - const Triangle& currentTriangle = planetLodLevel.triangles[triangleIndex]; - - // 3. 100 - for (int i = 0; i < STONES_PER_TRIANGLE; i++) { - - // --- 3.1. --- - Vector3f stoneCenter = GetRandomPointOnTriangle(currentTriangle, engine); - - // --- 3.2. ( + ) --- - - // - Vector3f scaleFactors = { - getRandomFloat(engine, MIN_AXIS_SCALE, MAX_AXIS_SCALE), - getRandomFloat(engine, MIN_AXIS_SCALE, MAX_AXIS_SCALE), - getRandomFloat(engine, MIN_AXIS_SCALE, MAX_AXIS_SCALE) + // + instance.scale = { + getRandomFloat(engine, 0.5f, 1.5f), + getRandomFloat(engine, 0.5f, 1.5f), + getRandomFloat(engine, 0.5f, 1.5f) }; - // (, ) - // , . - // '' . - - // 1. (currentTriangle.normal) - float angle = getRandomFloat(engine, 0.0f, 360.0f); - // ( Matrix4f::Identity, - // QuaternionFromAxisAngle Normal) - - // --- : --- 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)); - Vector4f qFinal = slerp(qx, qy, 0.5f); - qFinal = slerp(qFinal, qz, 0.5f).normalized(); - Matrix3f rotationMatrix = QuatToMatrix(qFinal); + instance.rotation = slerp(slerp(qx, qy, 0.5f), qz, 0.5f).normalized(); - - // --- 3.3. --- - - // - VertexDataStruct currentStone = baseStone; - - // , , - for (size_t j = 0; j < currentStone.PositionData.size(); j++) { - Vector3f& pos = currentStone.PositionData[j]; - Vector3f& norm = currentStone.NormalData[j]; - - // 1. - pos.v[0] *= scaleFactors.v[0]; - pos.v[1] *= scaleFactors.v[1]; - pos.v[2] *= scaleFactors.v[2]; - - // 2. - pos = MultMatrixVector(rotationMatrix, pos); - norm = MultMatrixVector(rotationMatrix, norm); - - // 3. (Translation) - pos = pos + stoneCenter; - } - - // --- 3.4. --- - finalMesh.PositionData.insert(finalMesh.PositionData.end(), - currentStone.PositionData.begin(), - currentStone.PositionData.end()); - - finalMesh.NormalData.insert(finalMesh.NormalData.end(), - currentStone.NormalData.begin(), - currentStone.NormalData.end()); - - finalMesh.TexCoordData.insert(finalMesh.TexCoordData.end(), - currentStone.TexCoordData.begin(), - currentStone.TexCoordData.end()); - - // ... (Tangent, Binormal, Color) + group.allInstances[tIdx].push_back(instance); } } + return group; + } - return finalMesh; + void StoneGroup::inflate(const std::vector& triangleIndices) { + // 1. + mesh.PositionData.clear(); + mesh.NormalData.clear(); + mesh.TexCoordData.clear(); + + static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337); + + // 2. + for (int tIdx : triangleIndices) { + if (tIdx >= allInstances.size()) continue; + + for (const auto& inst : allInstances[tIdx]) { + Matrix3f rotMat = QuatToMatrix(inst.rotation); + + for (size_t j = 0; j < baseStone.PositionData.size(); ++j) { + Vector3f p = baseStone.PositionData[j]; + Vector3f n = baseStone.NormalData[j]; + + // -> -> + p.v[0] *= inst.scale.v[0]; + p.v[1] *= inst.scale.v[1]; + p.v[2] *= inst.scale.v[2]; + + mesh.PositionData.push_back(MultMatrixVector(rotMat, p) + inst.position); + mesh.NormalData.push_back(MultMatrixVector(rotMat, n)); + mesh.TexCoordData.push_back(baseStone.TexCoordData[j]); + } + } + } } } // namespace ZL diff --git a/StoneObject.h b/StoneObject.h index ff0afec..ebc35ce 100644 --- a/StoneObject.h +++ b/StoneObject.h @@ -5,7 +5,26 @@ namespace ZL { - VertexDataStruct CreateBaseConvexPolyhedron(uint64_t seed); - VertexDataStruct CreateConvexPolyhedron(uint64_t seed, const LodLevel& planetLodLevel, const std::vector& triangleIndices); + struct StoneInstance { + uint64_t seed; + Vector3f position; + Vector3f scale; + Vector4f rotation; + }; + + struct StoneGroup { + // mesh.PositionData inflate() + VertexDataStruct mesh; + + // , + // + std::vector> allInstances; + + // + void inflate(const std::vector& triangleIndices); + }; + + // , + StoneGroup CreateStoneGroupData(uint64_t globalSeed, const LodLevel& planetLodLevel); } // namespace ZL diff --git a/ZLMath.cpp b/ZLMath.cpp index 4077cd9..954b783 100644 --- a/ZLMath.cpp +++ b/ZLMath.cpp @@ -189,6 +189,38 @@ namespace ZL { return r; } + Matrix4f MakeOrthoMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar) + { + float width = xmax - xmin; + float height = ymax - ymin; + float depthRange = zFar - zNear; + + if (width <= 0 || height <= 0 || depthRange <= 0) + { + throw std::runtime_error("Invalid dimensions for orthogonal matrix"); + } + + Matrix4f r; + + // Масштабирование + r.m[0] = 2.f / width; + r.m[5] = 2.f / height; + r.m[10] = -1.f / depthRange; + + // Обнуление неиспользуемых компонентов + r.m[1] = r.m[2] = r.m[3] = 0; + r.m[4] = r.m[6] = r.m[7] = 0; + r.m[8] = r.m[9] = r.m[11] = 0; + + // Трансляция (смещение) + r.m[12] = -(xmax + xmin) / width; + r.m[13] = -(ymax + ymin) / height; + r.m[14] = zNear / depthRange; + r.m[15] = 1.f; + + return r; + } + Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar) { float tanHalfFovy = tan(fovY / 2.f); diff --git a/ZLMath.h b/ZLMath.h index d5c7534..49d022c 100755 --- a/ZLMath.h +++ b/ZLMath.h @@ -153,6 +153,7 @@ namespace ZL { Matrix4f operator*(const Matrix4f& m1, const Matrix4f& m2); Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar); + Matrix4f MakeOrthoMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar); Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar); diff --git a/resources/rockx.png b/resources/rockx.png new file mode 100644 index 0000000..17542e5 --- /dev/null +++ b/resources/rockx.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28f148fac847891fac04c61c962bc98d3a9ed16dd58f156e9e6da7e79e422de4 +size 512801 diff --git a/resources/sandx.png b/resources/sandx.png new file mode 100644 index 0000000..bb7681b --- /dev/null +++ b/resources/sandx.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c3de9f5340a36a14654ee8124ebf16a394056805b1f5fab1a0045b0e5d7aad1 +size 390884 diff --git a/shaders/defaultColor_fog2_desktop.fragment b/shaders/defaultColor_fog2_desktop.fragment index aec32f5..5aa22ad 100644 --- a/shaders/defaultColor_fog2_desktop.fragment +++ b/shaders/defaultColor_fog2_desktop.fragment @@ -90,8 +90,8 @@ void main() // 4. Смешивание цвета с туманом //vec3 mountainColor = vec3((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.5,0.0); - gl_FragColor = mix(vec4(uColor* finalColor.rgb, 1.0), FOG_COLOR, fogFactor); + //gl_FragColor = mix(vec4(uColor* finalColor.rgb, 1.0), FOG_COLOR, fogFactor); //gl_FragColor = vec4((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.0,0.0, 1.0); //gl_FragColor = vec4(fogFactor, 0.5,0.5, 1.0); - //gl_FragColor = vec4(uColor*textureColor.rgb, 1.0); + gl_FragColor = vec4(textureColor.rgb, 1.0); } \ No newline at end of file diff --git a/shaders/defaultColor_fog_stones.vertex b/shaders/defaultColor_fog_stones.vertex new file mode 100644 index 0000000..1873051 --- /dev/null +++ b/shaders/defaultColor_fog_stones.vertex @@ -0,0 +1,18 @@ +// Вершинный шейдер (Vertex Shader) + +attribute vec3 vPosition; +attribute vec2 vTexCoord; + + +varying vec2 TexCoord; + +uniform mat4 ProjectionModelViewMatrix; + + +void main() +{ + + gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0); + + TexCoord = vTexCoord; +} \ No newline at end of file diff --git a/shaders/defaultColor_fog_stones_desktop.fragment b/shaders/defaultColor_fog_stones_desktop.fragment new file mode 100644 index 0000000..983e62d --- /dev/null +++ b/shaders/defaultColor_fog_stones_desktop.fragment @@ -0,0 +1,24 @@ +// Fragment Shader +varying vec2 TexCoord; +uniform sampler2D Texture; // sandTexture +uniform sampler2D StoneMap; // Наша запеченная текстура +uniform float testShift1; +uniform float testShift2; +void main() +{ + vec2 newTexCoord; + newTexCoord.x = TexCoord.x; + //newTexCoord.y = 1.0 - TexCoord.y - 0.0122; + //newTexCoord.y = TexCoord.y * (1.0+testShift) + 0.0122; + //newTexCoord.y = (TexCoord.y + 0.0122)*(1.0 +x/500.0); + newTexCoord.y = TexCoord.y * (1.0-6.0/500.0) + 0.0122+ (11.0/500.0) *0.1 -6/5000.0; + //newTexCoord.y = TexCoord.y; + vec4 sandColor = texture2D(Texture, TexCoord); + vec4 stoneData = texture2D(StoneMap, newTexCoord); + + //vec3 finalColor = sandColor.rgb*0.5 + stoneData.rgb*0.5; + vec3 finalColor = stoneData.rgb; + //vec3 finalColor = sandColor.rgb; + + gl_FragColor = vec4(finalColor, 1.0); +} \ No newline at end of file