400 lines
16 KiB
C++
400 lines
16 KiB
C++
#include "PlanetObject.h"
|
||
#include <random>
|
||
#include <cmath>
|
||
#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<Texture>(CreateTextureDataFromPng("./resources/sand2.png", ""));
|
||
stoneTexture = std::make_unique<Texture>(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<int> 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<float>(Environment::width) / static_cast<float>(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<float>(Environment::width) / static_cast<float>(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<float>(Environment::width) / static_cast<float>(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<float>(Environment::width) / static_cast<float>(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
|