#include "PlanetObject.h" #include #include #include "OpenGlExtensions.h" #include "Environment.h" #include "StoneObject.h" namespace ZL { PlanetObject::PlanetObject() { } void PlanetObject::init() { // 1. Инициализируем данные (генерация мешей) planetData.init(); // 2. Забираем данные для VBO // Берем максимальный LOD для начальной отрисовки int lodIndex = planetData.getMaxLodIndex(); planetRenderStruct.data = planetData.getLodLevel(lodIndex).vertexData; planetRenderStruct.RefreshVBO(); sandTexture = std::make_unique(CreateTextureDataFromPng("./resources/sand2.png", "")); stoneTexture = std::make_unique(CreateTextureDataFromPng("./resources/rock.png", "")); // Атмосфера planetAtmosphereRenderStruct.data = planetData.getAtmosphereLod().vertexData; planetAtmosphereRenderStruct.RefreshVBO(); } void PlanetObject::prepareDrawData() { if (!drawDataDirty) return; drawDataDirty = false; } void PlanetObject::update(float deltaTimeMs) { // Получаем видимые треугольники, передавая позицию корабля 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; 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) { 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); 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]); } } } } planetRenderYellowStruct.RefreshVBO(); planetStonesRenderStruct.data = CreateConvexPolyhedron(777, planetData.getLodLevel(5), triangleIndicesToDraw); planetStonesRenderStruct.RefreshVBO(); } void PlanetObject::draw(Renderer& renderer) { prepareDrawData(); //-------------------------- drawPlanet(renderer); //drawYellowZone(renderer); drawStones(renderer); drawAtmosphere(renderer); } void PlanetObject::drawPlanet(Renderer& renderer) { static const std::string defaultShaderName = "defaultColor"; static const std::string defaultShaderName2 = "defaultColor2"; 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"; renderer.shaderManager.PushShader(defaultShaderName); renderer.RenderUniform1i(textureUniformName, 0); 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), currentZNear, currentZFar); renderer.PushMatrix(); renderer.LoadIdentity(); renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.RotateMatrix(Environment::inverseShipMatrix); renderer.TranslateMatrix(-Environment::shipPosition); 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); //glEnable(GL_BLEND); //glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID()); renderer.DrawVertexRenderStruct(planetRenderStruct); //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(); } void PlanetObject::drawStones(Renderer& renderer) { static const std::string defaultShaderName = "defaultColor"; static const std::string defaultShaderName2 = "defaultColor2"; 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"; renderer.shaderManager.PushShader(defaultShaderName2); renderer.RenderUniform1i(textureUniformName, 0); 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), currentZNear, currentZFar); renderer.PushMatrix(); renderer.LoadIdentity(); renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.RotateMatrix(Environment::inverseShipMatrix); renderer.TranslateMatrix(-Environment::shipPosition); 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);// Аддитивное смешивание для эффекта свечения if (planetStonesRenderStruct.data.PositionData.size() > 0) { 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(); glClear(GL_DEPTH_BUFFER_BIT); } void PlanetObject::drawYellowZone(Renderer& renderer) { static const std::string defaultShaderName = "defaultColor"; static const std::string defaultShaderName2 = "defaultColor2"; 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"; float dist = planetData.distanceToPlanetSurface(Environment::shipPosition); auto zRange = planetData.calculateZRange(dist); const float currentZNear = zRange.first; const float currentZFar = zRange.second; glClear(GL_DEPTH_BUFFER_BIT); if (planetRenderYellowStruct.data.PositionData.size() > 0) { renderer.shaderManager.PushShader(defaultShaderName2); renderer.RenderUniform1i(textureUniformName, 0); renderer.EnableVertexAttribArray(vPositionName); renderer.EnableVertexAttribArray(vTexCoordName); // 2. Применяем динамическую матрицу проекции renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, static_cast(Environment::width) / static_cast(Environment::height), currentZNear, currentZFar); renderer.PushMatrix(); renderer.LoadIdentity(); renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.RotateMatrix(Environment::inverseShipMatrix); renderer.TranslateMatrix(-Environment::shipPosition); renderer.RenderUniform1f("uDistanceToPlanetSurface", dist); renderer.RenderUniform1f("uCurrentZFar", currentZFar); Vector3f color2 = { 1.0, 1.0, 0.0 }; glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID()); renderer.RenderUniform3fv("uColor", &color2.v[0]); renderer.DrawVertexRenderStruct(planetRenderYellowStruct); //glDisable(GL_BLEND); CheckGlError(); renderer.PopMatrix(); renderer.PopProjectionMatrix(); renderer.DisableVertexAttribArray(vTexCoordName); renderer.DisableVertexAttribArray(vPositionName); renderer.shaderManager.PopShader(); CheckGlError(); } } void PlanetObject::drawAtmosphere(Renderer& renderer) { static const std::string defaultShaderName = "defaultAtmosphere"; static const std::string vPositionName = "vPosition"; static const std::string vNormalName = "vNormal"; //glClear(GL_DEPTH_BUFFER_BIT); glDepthMask(GL_FALSE); renderer.shaderManager.PushShader(defaultShaderName); renderer.EnableVertexAttribArray(vPositionName); renderer.EnableVertexAttribArray(vNormalName); 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), currentZNear, currentZFar); renderer.PushMatrix(); renderer.LoadIdentity(); renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.RotateMatrix(Environment::inverseShipMatrix); renderer.TranslateMatrix(-Environment::shipPosition); const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix(); Vector3f color = { 0.0, 0.5, 1.0 }; renderer.RenderUniform3fv("uColor", &color.v[0]); renderer.RenderUniformMatrix4fv("ModelViewMatrix", false, &viewMatrix.m[0]); renderer.RenderUniform1f("uDistanceToPlanetSurface", dist); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения renderer.DrawVertexRenderStruct(planetAtmosphereRenderStruct); glDisable(GL_BLEND); glDepthMask(GL_TRUE); renderer.PopMatrix(); renderer.PopProjectionMatrix(); renderer.DisableVertexAttribArray(vNormalName); renderer.DisableVertexAttribArray(vPositionName); renderer.shaderManager.PopShader(); CheckGlError(); } float PlanetObject::distanceToPlanetSurface(const Vector3f& viewerPosition) { return planetData.distanceToPlanetSurface(viewerPosition); } } // namespace ZL