Compare commits
No commits in common. "main" and "spark" have entirely different histories.
@ -438,8 +438,6 @@ add_executable(space-game001
|
||||
Utils.h
|
||||
SparkEmitter.cpp
|
||||
SparkEmitter.h
|
||||
PlanetObject.cpp
|
||||
PlanetObject.h
|
||||
)
|
||||
|
||||
# Установка проекта по умолчанию для Visual Studio
|
||||
|
||||
@ -8,7 +8,7 @@ namespace ZL {
|
||||
int Environment::windowHeaderHeight = 0;
|
||||
int Environment::width = 0;
|
||||
int Environment::height = 0;
|
||||
float Environment::zoom = 18.f;
|
||||
float Environment::zoom = 6.f;
|
||||
|
||||
bool Environment::leftPressed = false;
|
||||
bool Environment::rightPressed = false;
|
||||
@ -31,13 +31,9 @@ bool Environment::tapDownHold = false;
|
||||
Vector2f Environment::tapDownStartPos = { 0, 0 };
|
||||
Vector2f Environment::tapDownCurrentPos = { 0, 0 };
|
||||
|
||||
Vector3f Environment::shipPosition = {0,0,45000.f};
|
||||
Vector3f Environment::shipPosition = {0,0,0};
|
||||
|
||||
float Environment::shipVelocity = 0.f;
|
||||
|
||||
|
||||
const float Environment::CONST_Z_NEAR = 5.f;
|
||||
const float Environment::CONST_Z_FAR = 5000.f;
|
||||
|
||||
|
||||
} // namespace ZL
|
||||
|
||||
@ -37,10 +37,6 @@ public:
|
||||
static Vector3f shipPosition;
|
||||
static float shipVelocity;
|
||||
|
||||
static const float CONST_Z_NEAR;
|
||||
static const float CONST_Z_FAR;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
228
Game.cpp
228
Game.cpp
@ -152,13 +152,11 @@ namespace ZL
|
||||
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE);
|
||||
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);
|
||||
|
||||
#else
|
||||
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor_fog.vertex", "./shaders/defaultColor_fog_desktop.fragment", CONST_ZIP_FILE);
|
||||
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("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_desktop.fragment", CONST_ZIP_FILE);
|
||||
|
||||
#endif
|
||||
|
||||
@ -204,87 +202,24 @@ namespace ZL
|
||||
|
||||
sparkEmitter.setTexture(sparkTexture);
|
||||
|
||||
|
||||
buttonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/button.png", CONST_ZIP_FILE));
|
||||
|
||||
button.data.PositionData.push_back({ 100, 100, 0 });
|
||||
button.data.PositionData.push_back({ 100, 150, 0 });
|
||||
button.data.PositionData.push_back({ 300, 150, 0 });
|
||||
button.data.PositionData.push_back({ 100, 100, 0 });
|
||||
button.data.PositionData.push_back({ 300, 150, 0 });
|
||||
button.data.PositionData.push_back({ 300, 100, 0 });
|
||||
|
||||
button.data.TexCoordData.push_back({ 0,0 });
|
||||
button.data.TexCoordData.push_back({ 0,1 });
|
||||
button.data.TexCoordData.push_back({ 1,1 });
|
||||
button.data.TexCoordData.push_back({ 0,0 });
|
||||
button.data.TexCoordData.push_back({ 1,1 });
|
||||
button.data.TexCoordData.push_back({ 1,0 });
|
||||
|
||||
button.RefreshVBO();
|
||||
|
||||
musicVolumeBarTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarTexture.png", CONST_ZIP_FILE));
|
||||
|
||||
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1190, 600, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
|
||||
musicVolumeBar.data.PositionData.push_back({ 1200, 100, 0 });
|
||||
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 0,1 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBar.data.TexCoordData.push_back({ 1,0 });
|
||||
|
||||
musicVolumeBar.RefreshVBO();
|
||||
|
||||
|
||||
musicVolumeBarButtonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarButton.png", CONST_ZIP_FILE));
|
||||
|
||||
float musicVolumeBarButtonButtonCenterY = 350.0f;
|
||||
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
|
||||
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
|
||||
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 0,1 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
|
||||
musicVolumeBarButton.data.TexCoordData.push_back({ 1,0 });
|
||||
|
||||
musicVolumeBarButton.RefreshVBO();
|
||||
renderer.InitOpenGL();
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
planetObject.init();
|
||||
|
||||
}
|
||||
|
||||
void Game::drawCubemap(float skyPercent)
|
||||
void Game::drawCubemap()
|
||||
{
|
||||
static const std::string defaultShaderName = "default";
|
||||
static const std::string envShaderName = "env";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
static const std::string skyPercentUniformName = "skyPercent";
|
||||
|
||||
renderer.shaderManager.PushShader(envShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.RenderUniform1f(skyPercentUniformName, skyPercent);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||
1, 1000);
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||
@ -320,7 +255,7 @@ namespace ZL
|
||||
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||
1, 1000);
|
||||
renderer.PushMatrix();
|
||||
|
||||
renderer.LoadIdentity();
|
||||
@ -329,6 +264,7 @@ namespace ZL
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(spaceship);
|
||||
|
||||
sparkEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
|
||||
|
||||
renderer.PopMatrix();
|
||||
@ -355,7 +291,7 @@ namespace ZL
|
||||
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||
1, 1000);
|
||||
|
||||
for (int i = 0; i < boxCoordsArr.size(); i++)
|
||||
{
|
||||
@ -380,77 +316,6 @@ namespace ZL
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
void Game::UpdateVolumeKnob() {
|
||||
float musicVolumeBarButtonButtonCenterY = volumeBarMinY + musicVolume * (volumeBarMaxY - volumeBarMinY);
|
||||
|
||||
auto& pos = musicVolumeBarButton.data.PositionData;
|
||||
|
||||
pos[0] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
|
||||
pos[1] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
|
||||
pos[2] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
|
||||
pos[3] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
|
||||
pos[4] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
|
||||
pos[5] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
|
||||
|
||||
musicVolumeBarButton.RefreshVBO();
|
||||
|
||||
}
|
||||
|
||||
void Game::UpdateVolumeFromMouse(int mouseX, int mouseY) {
|
||||
|
||||
int uiX = mouseX;
|
||||
int uiY = Environment::height - mouseY;
|
||||
Environment::shipVelocity = (musicVolume) * (20.0);
|
||||
if (uiY < volumeBarMinY || uiY > volumeBarMaxY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float t = (uiY - volumeBarMinY) / (volumeBarMaxY - volumeBarMinY);
|
||||
if (t < 0.0f) t = 0.0f;
|
||||
if (t > 1.0f) t = 1.0f;
|
||||
musicVolume = t;
|
||||
UpdateVolumeKnob();
|
||||
}
|
||||
void Game::drawUI()
|
||||
{
|
||||
static const std::string defaultShaderName = "default";
|
||||
static const std::string envShaderName = "env";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.PushProjectionMatrix(Environment::width, Environment::height, -1, 1);
|
||||
renderer.PushMatrix();
|
||||
|
||||
renderer.LoadIdentity();
|
||||
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, buttonTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(button);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, musicVolumeBarTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(musicVolumeBar);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, musicVolumeBarButtonTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(musicVolumeBarButton);
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
void Game::drawScene() {
|
||||
static const std::string defaultShaderName = "default";
|
||||
@ -459,38 +324,16 @@ namespace ZL
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
glClearColor(0.0f, 0.5f, 1.0f, 1.0f);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glViewport(0, 0, Environment::width, Environment::height);
|
||||
|
||||
CheckGlError();
|
||||
|
||||
float skyPercent = 0.0;
|
||||
float distance = planetObject.distanceToPlanetSurface();
|
||||
if (distance > 2000.f)
|
||||
{
|
||||
skyPercent = 0.0f;
|
||||
}
|
||||
else if (distance < 1000.f)
|
||||
{
|
||||
skyPercent = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
skyPercent = (2000.f - distance) / 1000.f;
|
||||
}
|
||||
|
||||
drawCubemap(skyPercent);
|
||||
planetObject.draw(renderer);
|
||||
if (planetObject.planetIsFar())
|
||||
{
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
drawCubemap();
|
||||
drawShip();
|
||||
//drawBoxes();
|
||||
|
||||
drawUI();
|
||||
drawBoxes();
|
||||
|
||||
CheckGlError();
|
||||
}
|
||||
@ -576,43 +419,20 @@ namespace ZL
|
||||
}
|
||||
else if (event.type == SDL_MOUSEBUTTONDOWN) {
|
||||
// 1. Îáðàáîòêà íàæàòèÿ êíîïêè ìûøè
|
||||
|
||||
int mx = event.button.x;
|
||||
int my = event.button.y;
|
||||
|
||||
std::cout << mx << " " << my << '\n';
|
||||
int uiX = mx;
|
||||
int uiY = Environment::height - my;
|
||||
if (uiX >= volumeBarMinX - 40 && uiX <= volumeBarMaxX + 40 &&
|
||||
uiY >= volumeBarMinY - 40 && uiY <= volumeBarMaxY + 40) {
|
||||
isDraggingVolume = true;
|
||||
UpdateVolumeFromMouse(mx, my);
|
||||
}
|
||||
else {
|
||||
Environment::tapDownHold = true;
|
||||
// Êîîðäèíàòû íà÷àëüíîãî íàæàòèÿ
|
||||
Environment::tapDownStartPos.v[0] = event.button.x;
|
||||
Environment::tapDownStartPos.v[1] = event.button.y;
|
||||
// Íà÷àëüíàÿ ïîçèöèÿ òàêæå ñòàíîâèòñÿ òåêóùåé
|
||||
Environment::tapDownCurrentPos.v[0] = event.button.x;
|
||||
Environment::tapDownCurrentPos.v[1] = event.button.y;
|
||||
}
|
||||
|
||||
Environment::tapDownHold = true;
|
||||
// Êîîðäèíàòû íà÷àëüíîãî íàæàòèÿ
|
||||
Environment::tapDownStartPos.v[0] = event.button.x;
|
||||
Environment::tapDownStartPos.v[1] = event.button.y;
|
||||
// Íà÷àëüíàÿ ïîçèöèÿ òàêæå ñòàíîâèòñÿ òåêóùåé
|
||||
Environment::tapDownCurrentPos.v[0] = event.button.x;
|
||||
Environment::tapDownCurrentPos.v[1] = event.button.y;
|
||||
}
|
||||
else if (event.type == SDL_MOUSEBUTTONUP) {
|
||||
// 2. Îáðàáîòêà îòïóñêàíèÿ êíîïêè ìûøè
|
||||
isDraggingVolume = false;
|
||||
Environment::tapDownHold = false;
|
||||
}
|
||||
else if (event.type == SDL_MOUSEMOTION) {
|
||||
// 3. Îáðàáîòêà ïåðåìåùåíèÿ ìûøè
|
||||
int mx = event.motion.x;
|
||||
int my = event.motion.y;
|
||||
|
||||
if (isDraggingVolume) {
|
||||
// Äâèãàåì ìûøü ïî ñëàéäåðó — ìåíÿåì ãðîìêîñòü è ïîçèöèþ êðóæêà
|
||||
UpdateVolumeFromMouse(mx, my);
|
||||
}
|
||||
if (Environment::tapDownHold) {
|
||||
// Îáíîâëåíèå òåêóùåé ïîçèöèè, åñëè êíîïêà óäåðæèâàåòñÿ
|
||||
Environment::tapDownCurrentPos.v[0] = event.motion.x;
|
||||
@ -635,23 +455,15 @@ namespace ZL
|
||||
{
|
||||
if (event.key.keysym.sym == SDLK_i)
|
||||
{
|
||||
Environment::shipVelocity += 500.f;
|
||||
Environment::shipVelocity += 1.f;
|
||||
}
|
||||
if (event.key.keysym.sym == SDLK_k)
|
||||
{
|
||||
Environment::shipVelocity -= 500.f;
|
||||
}
|
||||
if (event.key.keysym.sym == SDLK_o)
|
||||
{
|
||||
Environment::shipVelocity += 50.f;
|
||||
}
|
||||
if (event.key.keysym.sym == SDLK_l)
|
||||
{
|
||||
Environment::shipVelocity -= 50.f;
|
||||
Environment::shipVelocity -= 1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
} // namespace ZL
|
||||
36
Game.h
36
Game.h
@ -5,7 +5,6 @@
|
||||
#include "Environment.h"
|
||||
#include "TextureManager.h"
|
||||
#include "SparkEmitter.h"
|
||||
#include "PlanetObject.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@ -26,16 +25,14 @@ namespace ZL {
|
||||
void update();
|
||||
void render();
|
||||
|
||||
|
||||
bool shouldExit() const { return Environment::exitGameLoop; }
|
||||
|
||||
private:
|
||||
void processTickCount();
|
||||
void drawScene();
|
||||
void drawCubemap(float skyPercent);
|
||||
void drawCubemap();
|
||||
void drawShip();
|
||||
void drawBoxes();
|
||||
void drawUI();
|
||||
|
||||
SDL_Window* window;
|
||||
SDL_GLContext glContext;
|
||||
@ -44,32 +41,6 @@ namespace ZL {
|
||||
size_t newTickCount;
|
||||
size_t lastTickCount;
|
||||
|
||||
|
||||
std::vector<BoxCoords> boxCoordsArr;
|
||||
std::vector<VertexRenderStruct> boxRenderArr;
|
||||
|
||||
|
||||
std::shared_ptr<Texture> buttonTexture;
|
||||
VertexRenderStruct button;
|
||||
|
||||
std::shared_ptr<Texture> musicVolumeBarTexture;
|
||||
VertexRenderStruct musicVolumeBar;
|
||||
|
||||
std::shared_ptr<Texture> musicVolumeBarButtonTexture;
|
||||
VertexRenderStruct musicVolumeBarButton;
|
||||
|
||||
|
||||
bool isDraggingVolume = false;
|
||||
float musicVolume = 0.0f;
|
||||
float volumeBarMinX = 1190.0f;
|
||||
float volumeBarMaxX = 1200.0f;
|
||||
float volumeBarMinY = 100.0f;
|
||||
float volumeBarMaxY = 600.0f;
|
||||
float musicVolumeBarButtonButtonCenterX = 1195.0f;
|
||||
float musicVolumeBarButtonButtonRadius = 25.0f;
|
||||
void UpdateVolumeFromMouse(int mouseX, int mouseY);
|
||||
void UpdateVolumeKnob();
|
||||
|
||||
static const size_t CONST_TIMER_INTERVAL = 10;
|
||||
static const size_t CONST_MAX_TIME_INTERVAL = 1000;
|
||||
|
||||
@ -84,9 +55,10 @@ namespace ZL {
|
||||
std::shared_ptr<Texture> boxTexture;
|
||||
VertexDataStruct boxBase;
|
||||
|
||||
std::vector<BoxCoords> boxCoordsArr;
|
||||
std::vector<VertexRenderStruct> boxRenderArr;
|
||||
|
||||
SparkEmitter sparkEmitter;
|
||||
PlanetObject planetObject;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ZL
|
||||
582
PlanetObject.cpp
582
PlanetObject.cpp
@ -1,582 +0,0 @@
|
||||
#include "PlanetObject.h"
|
||||
#include <random>
|
||||
#include <cmath>
|
||||
#include "OpenGlExtensions.h"
|
||||
#include "Environment.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
static constexpr float PLANET_RADIUS = 20000.f;
|
||||
static Vector3f PLANET_CENTER_OFFSET = Vector3f{ 0.f, 0.f, 0.0f };
|
||||
//static Vector3f PLANET_CENTER_OFFSET = Vector3f{ 0.f, 0.f, -45000.f };
|
||||
|
||||
// --- 1. Дальний диапазон (FAR) ---
|
||||
static constexpr float FAR_Z_NEAR = 2000.0f;
|
||||
static constexpr float FAR_Z_FAR = 200000.0f;
|
||||
|
||||
// Дистанция, где НАЧИНАЕТСЯ переход FAR -> MIDDLE
|
||||
static constexpr float TRANSITION_FAR_START = 3000.0f;
|
||||
|
||||
// --- 2. Средний диапазон (MIDDLE) ---
|
||||
static constexpr float MIDDLE_Z_NEAR = 500.f;
|
||||
static constexpr float MIDDLE_Z_FAR = 50000.f;
|
||||
|
||||
|
||||
// Дистанция, где ЗАВЕРШАЕТСЯ переход FAR -> MIDDLE и НАЧИНАЕТСЯ MIDDLE -> NEAR
|
||||
static constexpr float TRANSITION_MIDDLE_START = 500.f;
|
||||
|
||||
// --- 3. Ближний диапазон (NEAR) ---
|
||||
// Новые константы для максимальной точности
|
||||
static constexpr float NEAR_Z_NEAR = 100.0f;
|
||||
static constexpr float NEAR_Z_FAR = 10000.0f;
|
||||
|
||||
|
||||
// Дистанция, где ЗАВЕРШАЕТСЯ переход MIDDLE -> NEAR
|
||||
static constexpr float TRANSITION_NEAR_END = 100.f;
|
||||
|
||||
// --- 3. Ближний диапазон (NEAR) ---
|
||||
// Новые константы для максимальной точности
|
||||
static constexpr float SUPER_NEAR_Z_NEAR = 5.0f;
|
||||
static constexpr float SUPER_NEAR_Z_FAR = 5000.0f;
|
||||
|
||||
|
||||
// Дистанция, где ЗАВЕРШАЕТСЯ переход MIDDLE -> NEAR
|
||||
static constexpr float TRANSITION_SUPER_NEAR_END = 10.f;
|
||||
|
||||
std::pair<float, float> calculateZRange(const Vector3f& shipPosition) {
|
||||
|
||||
// 1. Вычисление расстояния до поверхности планеты
|
||||
const Vector3f planetWorldPosition = PLANET_CENTER_OFFSET;
|
||||
const float distanceToPlanetCenter = (planetWorldPosition - shipPosition).length();
|
||||
const float distanceToPlanetSurface = distanceToPlanetCenter - PLANET_RADIUS;
|
||||
std::cout << "distanceToPlanetSurface " << distanceToPlanetSurface << std::endl;
|
||||
|
||||
float currentZNear;
|
||||
float currentZFar;
|
||||
float alpha; // Коэффициент интерполяции для текущего сегмента
|
||||
|
||||
// Диапазон I: Далеко (FAR) -> Средне (MIDDLE)
|
||||
if (distanceToPlanetSurface >= TRANSITION_FAR_START) {
|
||||
// Полностью дальний диапазон
|
||||
currentZNear = FAR_Z_NEAR;
|
||||
currentZFar = FAR_Z_FAR;
|
||||
|
||||
}
|
||||
else if (distanceToPlanetSurface > TRANSITION_MIDDLE_START) {
|
||||
// Плавный переход от FAR к MIDDLE
|
||||
const float transitionLength = TRANSITION_FAR_START - TRANSITION_MIDDLE_START;
|
||||
|
||||
// Нормализация расстояния, 0 при TRANSITION_FAR_START (Далеко), 1 при TRANSITION_MIDDLE_START (Близко)
|
||||
float normalizedDist = (distanceToPlanetSurface - TRANSITION_MIDDLE_START) / transitionLength;
|
||||
alpha = 1.0f - normalizedDist; // alpha = 0 (Далеко) ... 1 (Близко)
|
||||
|
||||
// Интерполяция: FAR * (1-alpha) + MIDDLE * alpha
|
||||
currentZNear = FAR_Z_NEAR * (1.0f - alpha) + MIDDLE_Z_NEAR * alpha;
|
||||
currentZFar = FAR_Z_FAR * (1.0f - alpha) + MIDDLE_Z_FAR * alpha;
|
||||
|
||||
// Диапазон II: Средне (MIDDLE) -> Близко (NEAR)
|
||||
}
|
||||
else if (distanceToPlanetSurface > TRANSITION_NEAR_END) {
|
||||
// Плавный переход от MIDDLE к NEAR
|
||||
const float transitionLength = TRANSITION_MIDDLE_START - TRANSITION_NEAR_END;
|
||||
|
||||
// Нормализация расстояния, 0 при TRANSITION_MIDDLE_START (Далеко), 1 при TRANSITION_NEAR_END (Близко)
|
||||
float normalizedDist = (distanceToPlanetSurface - TRANSITION_NEAR_END) / transitionLength;
|
||||
alpha = 1.0f - normalizedDist; // alpha = 0 (Далеко) ... 1 (Близко)
|
||||
|
||||
// Интерполяция: MIDDLE * (1-alpha) + NEAR * alpha
|
||||
currentZNear = MIDDLE_Z_NEAR * (1.0f - alpha) + NEAR_Z_NEAR * alpha;
|
||||
currentZFar = MIDDLE_Z_FAR * (1.0f - alpha) + NEAR_Z_FAR * alpha;
|
||||
|
||||
}
|
||||
else if (distanceToPlanetSurface > TRANSITION_SUPER_NEAR_END) {
|
||||
// Плавный переход от MIDDLE к NEAR
|
||||
const float transitionLength = TRANSITION_NEAR_END - TRANSITION_SUPER_NEAR_END;
|
||||
|
||||
// Нормализация расстояния, 0 при TRANSITION_MIDDLE_START (Далеко), 1 при TRANSITION_NEAR_END (Близко)
|
||||
float normalizedDist = (distanceToPlanetSurface - TRANSITION_SUPER_NEAR_END) / transitionLength;
|
||||
alpha = 1.0f - normalizedDist; // alpha = 0 (Далеко) ... 1 (Близко)
|
||||
|
||||
// Интерполяция: MIDDLE * (1-alpha) + NEAR * alpha
|
||||
currentZNear = NEAR_Z_NEAR * (1.0f - alpha) + SUPER_NEAR_Z_NEAR * alpha;
|
||||
currentZFar = NEAR_Z_FAR * (1.0f - alpha) + SUPER_NEAR_Z_FAR * alpha;
|
||||
|
||||
}
|
||||
else {
|
||||
// Полностью ближний диапазон (distanceToPlanetSurface <= TRANSITION_NEAR_END)
|
||||
currentZNear = SUPER_NEAR_Z_NEAR;
|
||||
currentZFar = SUPER_NEAR_Z_FAR;
|
||||
}
|
||||
|
||||
return { currentZNear, currentZFar };
|
||||
}
|
||||
|
||||
PerlinNoise::PerlinNoise() {
|
||||
p.resize(256);
|
||||
std::iota(p.begin(), p.end(), 0);
|
||||
// Перемешиваем для случайности (можно задать seed)
|
||||
std::default_random_engine engine(77777);
|
||||
std::shuffle(p.begin(), p.end(), engine);
|
||||
p.insert(p.end(), p.begin(), p.end()); // Дублируем для переполнения
|
||||
}
|
||||
|
||||
PerlinNoise::PerlinNoise(uint64_t seed) {
|
||||
p.resize(256);
|
||||
std::iota(p.begin(), p.end(), 0);
|
||||
// Перемешиваем для случайности (используем переданный seed)
|
||||
std::default_random_engine engine(seed); // <-- Использование сида
|
||||
std::shuffle(p.begin(), p.end(), engine);
|
||||
p.insert(p.end(), p.begin(), p.end()); // Дублируем для переполнения
|
||||
}
|
||||
|
||||
float PerlinNoise::fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); }
|
||||
float PerlinNoise::lerp(float t, float a, float b) { return a + t * (b - a); }
|
||||
float PerlinNoise::grad(int hash, float x, float y, float z) {
|
||||
int h = hash & 15;
|
||||
float u = h < 8 ? x : y;
|
||||
float v = h < 4 ? y : (h == 12 || h == 14 ? x : z);
|
||||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
||||
}
|
||||
|
||||
float PerlinNoise::noise(float x, float y, float z) {
|
||||
int X = (int)floor(x) & 255;
|
||||
int Y = (int)floor(y) & 255;
|
||||
int Z = (int)floor(z) & 255;
|
||||
|
||||
|
||||
x -= floor(x);
|
||||
y -= floor(y);
|
||||
z -= floor(z);
|
||||
|
||||
float u = fade(x);
|
||||
float v = fade(y);
|
||||
float w = fade(z);
|
||||
|
||||
int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z;
|
||||
int B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;
|
||||
|
||||
return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), grad(p[BA], x - 1, y, z)),
|
||||
lerp(u, grad(p[AB], x, y - 1, z), grad(p[BB], x - 1, y - 1, z))),
|
||||
lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), grad(p[BA + 1], x - 1, y, z - 1)),
|
||||
lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1))));
|
||||
}
|
||||
|
||||
float PerlinNoise::getSurfaceHeight(Vector3f pos) {
|
||||
// Частота шума (чем больше, тем больше "холмов")
|
||||
float frequency = 7.0f;
|
||||
|
||||
|
||||
// Получаем значение шума (обычно от -1 до 1)
|
||||
float noiseValue = noise(pos.v[0] * frequency, pos.v[1] * frequency, pos.v[2] * frequency);
|
||||
|
||||
// Переводим из диапазона [-1, 1] в [0, 1]
|
||||
//noiseValue = (noiseValue + 1.0f) * 0.5f;
|
||||
|
||||
// Масштабируем: хотим отклонение от 1.0 до 1.1
|
||||
// Значит амплитуда = 0.1
|
||||
float height = 1.0f; // * 0.2 даст вариацию высоты
|
||||
//float height = 1.0f - (noiseValue * 0.01f); // * 0.2 даст вариацию высоты
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool PlanetObject::planetIsFar()
|
||||
{
|
||||
const Vector3f planetWorldPosition = PLANET_CENTER_OFFSET;
|
||||
const float distanceToPlanetCenter = (planetWorldPosition - Environment::shipPosition).length();
|
||||
const float distanceToPlanetSurface = distanceToPlanetCenter - PLANET_RADIUS;
|
||||
|
||||
return distanceToPlanetSurface > 0.1*TRANSITION_MIDDLE_START;
|
||||
}
|
||||
|
||||
float PlanetObject::distanceToPlanetSurface()
|
||||
{
|
||||
const Vector3f planetWorldPosition = PLANET_CENTER_OFFSET;
|
||||
const float distanceToPlanetCenter = (planetWorldPosition - Environment::shipPosition).length();
|
||||
const float distanceToPlanetSurface = distanceToPlanetCenter - PLANET_RADIUS;
|
||||
return distanceToPlanetSurface;
|
||||
|
||||
}
|
||||
|
||||
|
||||
PlanetObject::PlanetObject()
|
||||
: perlin(77777)
|
||||
, colorPerlin(123123)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PlanetObject::init() {
|
||||
|
||||
planetMesh = generateSphere(8);
|
||||
|
||||
planetMesh.Scale(PLANET_RADIUS);
|
||||
planetMesh.Move(PLANET_CENTER_OFFSET);
|
||||
|
||||
planetRenderStruct.data = planetMesh;
|
||||
planetRenderStruct.RefreshVBO();
|
||||
|
||||
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand.png", ""));
|
||||
//sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", ""));
|
||||
|
||||
planetAtmosphere.data = generateSphere(5);
|
||||
planetAtmosphere.data.Scale(PLANET_RADIUS*1.03);
|
||||
planetAtmosphere.data.Move(PLANET_CENTER_OFFSET);
|
||||
|
||||
planetAtmosphere.RefreshVBO();
|
||||
}
|
||||
|
||||
void PlanetObject::prepareDrawData() {
|
||||
if (!drawDataDirty) return;
|
||||
|
||||
drawDataDirty = false;
|
||||
}
|
||||
|
||||
void PlanetObject::draw(Renderer& renderer) {
|
||||
|
||||
prepareDrawData();
|
||||
|
||||
static const std::string defaultShaderName = "defaultColor";
|
||||
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);
|
||||
|
||||
const auto zRange = calculateZRange(Environment::shipPosition);
|
||||
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]);
|
||||
|
||||
float dist = distanceToPlanetSurface();
|
||||
|
||||
|
||||
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();
|
||||
|
||||
drawAtmosphere(renderer);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
|
||||
const auto zRange = calculateZRange(Environment::shipPosition);
|
||||
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]);
|
||||
|
||||
float dist = distanceToPlanetSurface();
|
||||
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения
|
||||
|
||||
renderer.DrawVertexRenderStruct(planetAtmosphere);
|
||||
glDisable(GL_BLEND);
|
||||
glDepthMask(GL_TRUE);
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
|
||||
renderer.DisableVertexAttribArray(vNormalName);
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
|
||||
}
|
||||
|
||||
void PlanetObject::update(float deltaTimeMs) {
|
||||
|
||||
}
|
||||
|
||||
std::vector<Triangle> PlanetObject::subdivideTriangles(const std::vector<Triangle>& inputTriangles) {
|
||||
std::vector<Triangle> output;
|
||||
output.reserve(inputTriangles.size() * 4);
|
||||
|
||||
for (const auto& t : inputTriangles) {
|
||||
Vector3f a = t.data[0];
|
||||
Vector3f b = t.data[1];
|
||||
Vector3f c = t.data[2];
|
||||
|
||||
// 1. Вычисляем "сырые" середины
|
||||
Vector3f m_ab = (a + b) * 0.5f;
|
||||
Vector3f m_bc = (b + c) * 0.5f;
|
||||
Vector3f m_ac = (a + c) * 0.5f;
|
||||
|
||||
// 2. Нормализуем их (получаем идеальную сферу радиуса 1)
|
||||
m_ab = m_ab.normalized();
|
||||
m_bc = m_bc.normalized();
|
||||
m_ac = m_ac.normalized();
|
||||
|
||||
// 3. ПРИМЕНЯЕМ ШУМ: Смещаем точку по радиусу
|
||||
m_ab = m_ab * perlin.getSurfaceHeight(m_ab);
|
||||
m_bc = m_bc * perlin.getSurfaceHeight(m_bc);
|
||||
m_ac = m_ac * perlin.getSurfaceHeight(m_ac);
|
||||
|
||||
// 4. Формируем новые треугольники
|
||||
output.emplace_back(a, m_ab, m_ac);
|
||||
output.emplace_back(m_ab, b, m_bc);
|
||||
output.emplace_back(m_ac, m_bc, c);
|
||||
output.emplace_back(m_ab, m_bc, m_ac);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
Vector3f PlanetObject::calculateSurfaceNormal(Vector3f p_sphere) {
|
||||
// p_sphere - это нормализованный вектор (точка на идеальной сфере)
|
||||
|
||||
float theta = 0.01f; // Шаг для "щупанья" соседей (epsilon)
|
||||
|
||||
// Нам нужно найти два вектора, касательных к сфере в точке p_sphere.
|
||||
// Для этого берем любой вектор (например UP), делаем Cross Product, чтобы получить касательную.
|
||||
// Если p_sphere совпадает с UP, берем RIGHT.
|
||||
Vector3f up = Vector3f(0.0f, 1.0f, 0.0f);
|
||||
if (abs(p_sphere.dot(up)) > 0.99f) {
|
||||
up = Vector3f(1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
Vector3f tangentX = (up.cross(p_sphere)).normalized();
|
||||
Vector3f tangentY = (p_sphere.cross(tangentX)).normalized();
|
||||
|
||||
// Точки на идеальной сфере со смещением
|
||||
Vector3f p0_dir = p_sphere;
|
||||
Vector3f p1_dir = (p_sphere + tangentX * theta).normalized();
|
||||
Vector3f p2_dir = (p_sphere + tangentY * theta).normalized();
|
||||
|
||||
// Реальные точки на искаженной поверхности
|
||||
// p = dir * height(dir)
|
||||
Vector3f p0 = p0_dir * perlin.getSurfaceHeight(p0_dir);
|
||||
Vector3f p1 = p1_dir * perlin.getSurfaceHeight(p1_dir);
|
||||
Vector3f p2 = p2_dir * perlin.getSurfaceHeight(p2_dir);
|
||||
|
||||
// Вектора от центральной точки к соседям
|
||||
Vector3f v1 = p1 - p0;
|
||||
Vector3f v2 = p2 - p0;
|
||||
|
||||
// Нормаль - это перпендикуляр к этим двум векторам
|
||||
// Порядок (v2, v1) или (v1, v2) зависит от системы координат,
|
||||
// здесь подбираем так, чтобы нормаль смотрела наружу.
|
||||
return (-v2.cross(v1)).normalized();
|
||||
}
|
||||
|
||||
VertexDataStruct PlanetObject::trianglesToVertices(const std::vector<Triangle>& triangles) {
|
||||
VertexDataStruct buffer;
|
||||
buffer.PositionData.reserve(triangles.size() * 3);
|
||||
buffer.NormalData.reserve(triangles.size() * 3);
|
||||
buffer.TexCoordData.reserve(triangles.size() * 3); // <-- РЕЗЕРВИРУЕМ
|
||||
//buffer.TexCoord3Data.reserve(triangles.size() * 3); // <-- РЕЗЕРВИРУЕМ
|
||||
|
||||
// Стандартные UV-координаты для покрытия одного треугольника
|
||||
// Покрывает текстурой всю грань.
|
||||
const std::array<Vector2f, 3> triangleUVs = {
|
||||
Vector2f(0.0f, 0.0f),
|
||||
Vector2f(1.0f, 0.0f),
|
||||
Vector2f(0.0f, 1.0f)
|
||||
};
|
||||
/*
|
||||
const std::array<Vector3f, 3> barycentricCoords = {
|
||||
Vector3f(1.0f, 0.0f, 0.0f), // Вершина 1
|
||||
Vector3f(0.0f, 1.0f, 0.0f), // Вершина 2
|
||||
Vector3f(0.0f, 0.0f, 1.0f) // Вершина 3
|
||||
};*/
|
||||
|
||||
for (const auto& t : triangles) {
|
||||
// Проходим по всем 3 вершинам треугольника
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// p_geometry - это уже точка на поверхности (с шумом)
|
||||
Vector3f p_geometry = t.data[i];
|
||||
|
||||
// Нам нужно восстановить направление от центра к этой точке,
|
||||
// чтобы передать его в функцию расчета нормали.
|
||||
// Так как (0,0,0) - центр, то normalize(p) даст нам направление.
|
||||
Vector3f p_dir = p_geometry.normalized();
|
||||
|
||||
// Считаем аналитическую нормаль для этой конкретной точки
|
||||
Vector3f normal = calculateSurfaceNormal(p_dir);
|
||||
|
||||
buffer.PositionData.push_back({ p_geometry });
|
||||
buffer.NormalData.push_back({ normal });
|
||||
//buffer.TexCoord3Data.push_back(barycentricCoords[i]);
|
||||
buffer.TexCoordData.push_back(triangleUVs[i]);
|
||||
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
VertexDataStruct PlanetObject::generateSphere(int subdivisions) {
|
||||
// 1. Исходный октаэдр
|
||||
std::vector<Triangle> geometry = {
|
||||
Triangle{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f}}, // Top-Front-Right
|
||||
Triangle{{ 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // Top-Right-Back
|
||||
Triangle{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}}, // Top-Back-Left
|
||||
Triangle{{ 0.0f, 1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // Top-Left-Front
|
||||
Triangle{{ 0.0f, -1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // Bottom-Right-Front
|
||||
Triangle{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}}, // Bottom-Front-Left
|
||||
Triangle{{ 0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // Bottom-Left-Back
|
||||
Triangle{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, { 1.0f, 0.0f, 0.0f}} // Bottom-Back-Right
|
||||
};
|
||||
|
||||
// 2. ПРИМЕНЯЕМ ШУМ К ИСХОДНЫМ ВЕРШИНАМ
|
||||
for (auto& t : geometry) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Vector3f dir = t.data[i].normalized();
|
||||
t.data[i] = dir * perlin.getSurfaceHeight(dir);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Разбиваем N раз
|
||||
for (int i = 0; i < subdivisions; i++) {
|
||||
geometry = subdivideTriangles(geometry);
|
||||
}
|
||||
|
||||
// 4. Генерируем вершины И НОРМАЛИ с помощью trianglesToVertices
|
||||
// ЭТО ЗАПОЛНИТ PositionData И NormalData
|
||||
VertexDataStruct buffer = trianglesToVertices(geometry);
|
||||
|
||||
// Теперь нам нужно заполнить ColorData, используя ту же логику, что и раньше.
|
||||
// Сначала резервируем место, так как trianglesToVertices не заполняет ColorData
|
||||
buffer.ColorData.reserve(geometry.size() * 3);
|
||||
|
||||
// Базовый цвет и параметры
|
||||
const Vector3f baseColor = { 0.498f, 0.416f, 0.0f };
|
||||
const float colorFrequency = 5.0f;
|
||||
const float colorAmplitude = 0.2f;
|
||||
const Vector3f offsetR = { 0.1f, 0.2f, 0.3f };
|
||||
const Vector3f offsetG = { 0.5f, 0.4f, 0.6f };
|
||||
const Vector3f offsetB = { 0.9f, 0.8f, 0.7f };
|
||||
|
||||
|
||||
for (const auto& t : geometry) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// ВАЖНО: Мы используем геометрию из t.data[i] для получения направления,
|
||||
// а не PositionData из buffer, поскольку там может не быть нужного порядка.
|
||||
Vector3f p_geometry = t.data[i];
|
||||
Vector3f dir = p_geometry.normalized();
|
||||
|
||||
// Вычисление цветового шума (как вы делали)
|
||||
float noiseR = colorPerlin.noise(
|
||||
(dir.v[0] + offsetR.v[0]) * colorFrequency,
|
||||
(dir.v[1] + offsetR.v[1]) * colorFrequency,
|
||||
(dir.v[2] + offsetR.v[2]) * colorFrequency
|
||||
);
|
||||
float noiseG = colorPerlin.noise(
|
||||
(dir.v[0] + offsetG.v[0]) * colorFrequency,
|
||||
(dir.v[1] + offsetG.v[1]) * colorFrequency,
|
||||
(dir.v[2] + offsetG.v[2]) * colorFrequency
|
||||
);
|
||||
float noiseB = colorPerlin.noise(
|
||||
(dir.v[0] + offsetB.v[0]) * colorFrequency,
|
||||
(dir.v[1] + offsetB.v[1]) * colorFrequency,
|
||||
(dir.v[2] + offsetB.v[2]) * colorFrequency
|
||||
);
|
||||
|
||||
Vector3f colorOffset = {
|
||||
noiseR * colorAmplitude,
|
||||
noiseG * colorAmplitude,
|
||||
noiseB * colorAmplitude
|
||||
};
|
||||
|
||||
Vector3f finalColor = baseColor + colorOffset;
|
||||
|
||||
finalColor.v[0] = max(0.0f, min(1.0f, finalColor.v[0]));
|
||||
finalColor.v[1] = max(0.0f, min(1.0f, finalColor.v[1]));
|
||||
finalColor.v[2] = max(0.0f, min(1.0f, finalColor.v[2]));
|
||||
|
||||
// ДОБАВЛЯЕМ ТОЛЬКО ЦВЕТ, так как PositionData и NormalData уже заполнены!
|
||||
buffer.ColorData.push_back(finalColor);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ZL
|
||||
@ -1,79 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ZLMath.h"
|
||||
#include "Renderer.h"
|
||||
#include "TextureManager.h"
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
|
||||
namespace ZL {
|
||||
|
||||
struct Triangle
|
||||
{
|
||||
std::array<Vector3f, 3> data;
|
||||
|
||||
Triangle(Vector3f p1, Vector3f p2, Vector3f p3)
|
||||
: data{ p1, p2, p3 }
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class PerlinNoise {
|
||||
std::vector<int> p;
|
||||
public:
|
||||
PerlinNoise();
|
||||
PerlinNoise(uint64_t seed);
|
||||
|
||||
float fade(float t);
|
||||
float lerp(float t, float a, float b);
|
||||
float grad(int hash, float x, float y, float z);
|
||||
|
||||
float noise(float x, float y, float z);
|
||||
|
||||
float getSurfaceHeight(Vector3f pos);
|
||||
};
|
||||
|
||||
|
||||
class PlanetObject {
|
||||
private:
|
||||
PerlinNoise perlin;
|
||||
PerlinNoise colorPerlin;
|
||||
void prepareDrawData();
|
||||
VertexDataStruct planetMesh;
|
||||
VertexRenderStruct planetRenderStruct;
|
||||
|
||||
VertexRenderStruct planetAtmosphere;
|
||||
|
||||
|
||||
std::shared_ptr<Texture> sandTexture;
|
||||
|
||||
public:
|
||||
PlanetObject();
|
||||
|
||||
void init();
|
||||
|
||||
void update(float deltaTimeMs);
|
||||
|
||||
void draw(Renderer& renderer);
|
||||
void drawAtmosphere(Renderer& renderer);
|
||||
|
||||
bool planetIsFar();
|
||||
float distanceToPlanetSurface();
|
||||
|
||||
|
||||
private:
|
||||
bool drawDataDirty = true;
|
||||
|
||||
std::vector<Triangle> subdivideTriangles(const std::vector<Triangle>& inputTriangles);
|
||||
Vector3f calculateSurfaceNormal(Vector3f p_sphere);
|
||||
VertexDataStruct trianglesToVertices(const std::vector<Triangle>& triangles);
|
||||
VertexDataStruct generateSphere(int subdivisions);
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
download from https://cmake.org/download/
|
||||
|
||||
|
||||
Windows x64 Installer: cmake-4.2.0-windows-x86_64.msi
|
||||
|
||||
|
||||
|
||||
45
Renderer.cpp
45
Renderer.cpp
@ -294,18 +294,6 @@ namespace ZL {
|
||||
glBufferData(GL_ARRAY_BUFFER, data.TexCoordData.size() * 8, &data.TexCoordData[0], GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
if (data.TexCoord3Data.size() > 0)
|
||||
{
|
||||
if (!texCoord3VBO)
|
||||
{
|
||||
texCoord3VBO = std::make_shared<VBOHolder>();
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, texCoord3VBO->getBuffer());
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, data.TexCoord3Data.size() * 12, &data.TexCoord3Data[0], GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
|
||||
if (data.NormalData.size() > 0)
|
||||
{
|
||||
@ -471,12 +459,6 @@ namespace ZL {
|
||||
return ProjectionModelViewMatrix;
|
||||
}
|
||||
|
||||
Matrix4f Renderer::GetCurrentModelViewMatrix()
|
||||
{
|
||||
return ModelviewMatrixStack.top();
|
||||
}
|
||||
|
||||
|
||||
void Renderer::SetMatrix()
|
||||
{
|
||||
if (ProjectionMatrixStack.size() <= 0)
|
||||
@ -489,16 +471,15 @@ namespace ZL {
|
||||
throw std::runtime_error("Modelview matrix stack out!");
|
||||
}
|
||||
|
||||
Matrix4f& modelViewMatrix = ModelviewMatrixStack.top();
|
||||
ProjectionModelViewMatrix = ProjectionMatrixStack.top() * modelViewMatrix;
|
||||
ProjectionModelViewMatrix = ProjectionMatrixStack.top() * ModelviewMatrixStack.top();
|
||||
|
||||
static const std::string ProjectionModelViewMatrixName = "ProjectionModelViewMatrix";
|
||||
|
||||
//static const std::string ProjectionMatrixName = "ProjectionMatrix";
|
||||
|
||||
RenderUniformMatrix4fv(ProjectionModelViewMatrixName, false, &ProjectionModelViewMatrix.m[0]);
|
||||
|
||||
static const std::string ModelViewMatrixName = "ModelViewMatrix";
|
||||
|
||||
RenderUniformMatrix4fv(ModelViewMatrixName, false, &modelViewMatrix.m[0]);
|
||||
//RenderUniformMatrix4fv(ProjectionMatrixName, false, &ProjectionMatrixStack.top().m[0]);
|
||||
|
||||
}
|
||||
|
||||
@ -727,18 +708,6 @@ namespace ZL {
|
||||
|
||||
}
|
||||
|
||||
void Renderer::RenderUniform1f(const std::string& uniformName, float value)
|
||||
{
|
||||
auto shader = shaderManager.GetCurrentShader();
|
||||
|
||||
auto uniform = shader->uniformList.find(uniformName);
|
||||
|
||||
if (uniform != shader->uniformList.end())
|
||||
{
|
||||
glUniform1fv(uniform->second, 1, &value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Renderer::VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer)
|
||||
@ -764,7 +733,6 @@ namespace ZL {
|
||||
static const std::string vBinormal("vBinormal");
|
||||
static const std::string vColor("vColor");
|
||||
static const std::string vTexCoord("vTexCoord");
|
||||
static const std::string vTexCoord3("vTexCoord3");
|
||||
static const std::string vPosition("vPosition");
|
||||
|
||||
//glBindVertexArray(VertexRenderStruct.vao->getBuffer());
|
||||
@ -795,11 +763,6 @@ namespace ZL {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoordVBO->getBuffer());
|
||||
VertexAttribPointer2fv(vTexCoord, 0, NULL);
|
||||
}
|
||||
if (VertexRenderStruct.data.TexCoord3Data.size() > 0)
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoord3VBO->getBuffer());
|
||||
VertexAttribPointer2fv(vTexCoord3, 0, NULL);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.positionVBO->getBuffer());
|
||||
VertexAttribPointer3fv(vPosition, 0, NULL);
|
||||
|
||||
@ -44,7 +44,6 @@ namespace ZL {
|
||||
{
|
||||
std::vector<Vector3f> PositionData;
|
||||
std::vector<Vector2f> TexCoordData;
|
||||
std::vector<Vector3f> TexCoord3Data;
|
||||
std::vector<Vector3f> NormalData;
|
||||
std::vector<Vector3f> TangentData;
|
||||
std::vector<Vector3f> BinormalData;
|
||||
@ -64,7 +63,6 @@ namespace ZL {
|
||||
std::shared_ptr<VAOHolder> vao;
|
||||
std::shared_ptr<VBOHolder> positionVBO;
|
||||
std::shared_ptr<VBOHolder> texCoordVBO;
|
||||
std::shared_ptr<VBOHolder> texCoord3VBO;
|
||||
std::shared_ptr<VBOHolder> normalVBO;
|
||||
std::shared_ptr<VBOHolder> tangentVBO;
|
||||
std::shared_ptr<VBOHolder> binormalVBO;
|
||||
@ -110,7 +108,6 @@ namespace ZL {
|
||||
|
||||
|
||||
Matrix4f GetProjectionModelViewMatrix();
|
||||
Matrix4f GetCurrentModelViewMatrix();
|
||||
|
||||
void SetMatrix();
|
||||
|
||||
@ -124,7 +121,7 @@ namespace ZL {
|
||||
void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value);
|
||||
void RenderUniform1i(const std::string& uniformName, const int value);
|
||||
void RenderUniform3fv(const std::string& uniformName, const float* value);
|
||||
void RenderUniform1f(const std::string& uniformName, float value);
|
||||
|
||||
|
||||
void VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer);
|
||||
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
#include <random>
|
||||
#include <cmath>
|
||||
#include "OpenGlExtensions.h"
|
||||
#include "Environment.h"
|
||||
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@ -127,7 +125,7 @@ namespace ZL {
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
float aspectRatio = static_cast<float>(screenWidth) / static_cast<float>(screenHeight);
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, aspectRatio, Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, aspectRatio, 1, 1000);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
||||
|
||||
|
||||
26
ZLMath.h
26
ZLMath.h
@ -56,23 +56,6 @@ namespace ZL {
|
||||
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
|
||||
}
|
||||
|
||||
float length() const
|
||||
{
|
||||
return sqrt(squaredNorm());
|
||||
}
|
||||
|
||||
float dot(const Vector3f& other) const {
|
||||
return v[0] * other.v[0] + v[1] * other.v[1] + v[2] * other.v[2];
|
||||
}
|
||||
|
||||
Vector3f cross(const Vector3f& other) const {
|
||||
return Vector3f(
|
||||
v[1] * other.v[2] - v[2] * other.v[1],
|
||||
v[2] * other.v[0] - v[0] * other.v[2],
|
||||
v[0] * other.v[1] - v[1] * other.v[0]
|
||||
);
|
||||
}
|
||||
|
||||
// Îïåðàòîð âû÷èòàíèÿ
|
||||
/*Vector3f operator-(const Vector3f& other) const {
|
||||
return Vector3f(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]);
|
||||
@ -84,15 +67,6 @@ namespace ZL {
|
||||
struct Vector2f
|
||||
{
|
||||
std::array<float, 2> v = {0.f, 0.f};
|
||||
|
||||
Vector2f()
|
||||
{
|
||||
}
|
||||
|
||||
Vector2f(float x, float y)
|
||||
: v{ x,y }
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
Vector2f operator+(const Vector2f& x, const Vector2f& y);
|
||||
|
||||
BIN
resources/button.png
(Stored with Git LFS)
BIN
resources/button.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/musicVolumeBarButton.png
(Stored with Git LFS)
BIN
resources/musicVolumeBarButton.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/musicVolumeBarTexture.png
(Stored with Git LFS)
BIN
resources/musicVolumeBarTexture.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/rock.png
(Stored with Git LFS)
BIN
resources/rock.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/sand.png
(Stored with Git LFS)
BIN
resources/sand.png
(Stored with Git LFS)
Binary file not shown.
@ -1,48 +0,0 @@
|
||||
// Фрагментный шейдер:
|
||||
uniform vec3 uColor;
|
||||
uniform float uDistanceToPlanetSurface; // Расстояние корабля до поверхности
|
||||
|
||||
// Константы затухания, определенные прямо в шейдере
|
||||
const float DIST_FOG_MAX = 2000.0;
|
||||
const float DIST_FOG_MIN = 1000.0;
|
||||
|
||||
varying vec3 vViewNormal;
|
||||
varying vec3 vViewPosition;
|
||||
|
||||
void main()
|
||||
{
|
||||
// --- 1. Расчет плотности по Френелю (краевой эффект) ---
|
||||
vec3 viewVector = normalize(-vViewPosition);
|
||||
float NdotV = dot(vViewNormal, viewVector);
|
||||
float factor = 1.0 - abs(NdotV);
|
||||
float atmosphereDensity = pow(factor, 5.0);
|
||||
|
||||
// --- 2. Расчет коэффициента затухания по дистанции ---
|
||||
|
||||
float distanceFactor = 1.0;
|
||||
|
||||
if (uDistanceToPlanetSurface > DIST_FOG_MAX)
|
||||
{
|
||||
// Дистанция > 2000.0: Полностью видно (Factor = 1.0)
|
||||
distanceFactor = 1.0;
|
||||
}
|
||||
else if (uDistanceToPlanetSurface < DIST_FOG_MIN)
|
||||
{
|
||||
// Дистанция < 1000.0: Полностью не видно (Factor = 0.0)
|
||||
distanceFactor = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Плавный переход (линейная интерполяция)
|
||||
// normalizedDistance: от 0.0 (на DIST_FOG_MIN) до 1.0 (на DIST_FOG_MAX)
|
||||
float normalizedDistance = (uDistanceToPlanetSurface - DIST_FOG_MIN) / (DIST_FOG_MAX - DIST_FOG_MIN);
|
||||
|
||||
distanceFactor = clamp(normalizedDistance, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// --- 3. Финальный цвет и прозрачность ---
|
||||
|
||||
float finalAlpha = atmosphereDensity * distanceFactor;
|
||||
|
||||
gl_FragColor = vec4(uColor, finalAlpha);
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
// Вершинный шейдер:
|
||||
attribute vec3 vPosition;
|
||||
attribute vec3 vNormal; // <-- Новый атрибут
|
||||
|
||||
uniform mat4 ProjectionModelViewMatrix;
|
||||
uniform mat4 ModelViewMatrix;
|
||||
|
||||
// Выходные переменные (передаются во фрагментный шейдер)
|
||||
varying vec3 vViewNormal;
|
||||
varying vec3 vViewPosition;
|
||||
|
||||
void main()
|
||||
{
|
||||
// 1. Позиция в пространстве вида (View Space)
|
||||
vec4 positionView = ModelViewMatrix * vec4(vPosition, 1.0);
|
||||
vViewPosition = positionView.xyz;
|
||||
|
||||
// 2. Нормаль в пространстве вида (View Space)
|
||||
// Преобразуем нормаль, используя ModelViewMatrix. Поскольку нормаль - это вектор,
|
||||
// трансляционная часть (четвертый столбец) матрицы нам не нужна.
|
||||
// Если бы было неединообразное масштабирование, потребовалась бы Inverse Transpose Matrix.
|
||||
// В вашем случае, где есть только униформное масштабирование и вращение,
|
||||
// достаточно просто умножить на ModelViewMatrix:
|
||||
vViewNormal = normalize((ModelViewMatrix * vec4(vNormal, 0.0)).xyz);
|
||||
// W=0.0 для векторов, чтобы игнорировать трансляцию
|
||||
|
||||
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||
}
|
||||
@ -1,23 +1,11 @@
|
||||
attribute vec3 vPosition;
|
||||
attribute vec3 vColor;
|
||||
attribute vec3 vNormal;
|
||||
attribute vec2 vTexCoord; // <-- Обычные UV (если используются)
|
||||
|
||||
varying vec3 color;
|
||||
varying vec3 normal;
|
||||
|
||||
varying vec2 TexCoord; // <-- Передаем UV
|
||||
|
||||
uniform mat4 ProjectionModelViewMatrix;
|
||||
uniform mat4 ModelViewMatrix;
|
||||
uniform vec3 uLightDirection;
|
||||
|
||||
void main()
|
||||
void main()
|
||||
{
|
||||
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||
|
||||
normal = normalize((ModelViewMatrix * vec4(vNormal, 0.0)).xyz);
|
||||
|
||||
color = vColor;
|
||||
TexCoord = vTexCoord;
|
||||
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||
color = vColor;
|
||||
}
|
||||
@ -1,22 +1,9 @@
|
||||
varying vec3 color; // Цвет вершины (с шумом)
|
||||
varying vec3 normal;
|
||||
varying vec3 lightDirection_VS;
|
||||
varying vec2 TexCoord; // UV-координаты
|
||||
//precision mediump float;
|
||||
varying vec3 color;
|
||||
|
||||
uniform sampler2D Texture;
|
||||
uniform vec3 uLightDirection;
|
||||
void main()
|
||||
void main()
|
||||
{
|
||||
// 1. Получаем цвет из текстуры и смешиваем с цветовым шумом
|
||||
vec4 textureColor = texture2D(Texture, TexCoord);
|
||||
vec3 finalColor = textureColor.rgb * color;
|
||||
|
||||
// 3. Расчет освещения
|
||||
float diffuse = max(0.0, dot(normal, uLightDirection));
|
||||
float ambient = 0.2;
|
||||
float lightingFactor = min(1.0, ambient + diffuse);
|
||||
|
||||
|
||||
gl_FragColor = vec4(finalColor * lightingFactor, 1.0);
|
||||
|
||||
//gl_FragColor = vec4(color, 1.0);
|
||||
gl_FragColor = vec4(1.0, 1.0, 0.5, 1.0);
|
||||
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
// Вершинный шейдер (Vertex Shader)
|
||||
|
||||
attribute vec3 vPosition;
|
||||
attribute vec3 vColor;
|
||||
attribute vec3 vNormal;
|
||||
attribute vec2 vTexCoord;
|
||||
|
||||
varying vec3 color;
|
||||
varying vec3 normal;
|
||||
varying vec2 TexCoord;
|
||||
varying float viewZ; // <--- НОВОЕ: Z-координата в пространстве вида (View Space)
|
||||
varying vec3 pos;
|
||||
|
||||
uniform mat4 ProjectionModelViewMatrix;
|
||||
uniform mat4 ModelViewMatrix; // Нужна для преобразования vPosition в View Space
|
||||
uniform vec3 uLightDirection;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Преобразование позиции в пространство вида (View Space)
|
||||
vec4 viewPosition = ModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||
|
||||
// Сохраняем отрицательную Z-координату. В OpenGL Z-координата (глубина)
|
||||
// в пространстве вида обычно отрицательна, но для расчета тумана
|
||||
// удобнее использовать положительное значение.
|
||||
viewZ = -viewPosition.z;
|
||||
|
||||
pos = vPosition.xyz;
|
||||
|
||||
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||
|
||||
normal = normalize((ModelViewMatrix * vec4(vNormal, 0.0)).xyz);
|
||||
color = vColor;
|
||||
TexCoord = vTexCoord;
|
||||
}
|
||||
@ -1,105 +0,0 @@
|
||||
// ---Фрагментный шейдер (Fragment Shader)
|
||||
|
||||
varying vec3 color;
|
||||
varying vec3 normal;
|
||||
varying vec2 TexCoord;
|
||||
varying float viewZ;
|
||||
varying vec3 pos;
|
||||
|
||||
uniform sampler2D Texture;
|
||||
uniform vec3 uLightDirection;
|
||||
uniform float uDistanceToPlanetSurface;
|
||||
uniform float uCurrentZFar;
|
||||
|
||||
// Константы для тумана:
|
||||
const vec4 FOG_COLOR = vec4(0.0, 0.5, 1.0, 1.0); // Синий туман
|
||||
|
||||
// Параметры "Distance Fog"
|
||||
const float DIST_FOG_MAX = 2000.0;
|
||||
const float DIST_FOG_MIN = 1000.0;
|
||||
|
||||
// Параметры "Z-Far Fog"
|
||||
// Насколько близко к Zfar должен начинаться туман (например, 10% от Zfar)
|
||||
const float Z_FOG_START_RATIO = 0.9;
|
||||
// Какую долю от Zfar должен покрывать туман (например, 10% от Zfar)
|
||||
const float Z_FOG_RANGE_RATIO = 0.1;
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
// ... (1. Получаем цвет и 2. Расчет освещения)
|
||||
vec4 textureColor = texture2D(Texture, TexCoord);
|
||||
vec3 finalColor = textureColor.rgb * color;
|
||||
|
||||
float diffuse = max(0.0, dot(normal, uLightDirection));
|
||||
float ambient = 0.2;
|
||||
float lightingFactor = min(1.0, ambient + diffuse);
|
||||
vec3 litColor = finalColor * lightingFactor;
|
||||
|
||||
|
||||
// 3. Расчет коэффициента тумана (fogFactor)
|
||||
float fogFactor = 0.0;
|
||||
|
||||
// --- 3.1. Расчет коэффициента тумана на основе расстояния до поверхности (Distance Fog) ---
|
||||
// Этот туман работает на больших расстояниях и постепенно исчезает,
|
||||
// уступая место Z-Far Fog при приближении к планете.
|
||||
|
||||
if (uDistanceToPlanetSurface >= DIST_FOG_MIN && uDistanceToPlanetSurface <DIST_FOG_MAX) {
|
||||
// Нормализация: 0.0f при DIST_FOG_MAX, 1.0f при DIST_FOG_MIN
|
||||
float distRange = DIST_FOG_MAX - DIST_FOG_MIN;
|
||||
float distNormalized = clamp((uDistanceToPlanetSurface - DIST_FOG_MIN) / distRange, 0.0, 1.0);
|
||||
|
||||
// alpha = 0.0 (Далеко) ... 1.0 (Близко к 1000.f)
|
||||
fogFactor = 1.0 - distNormalized;
|
||||
}
|
||||
if (uDistanceToPlanetSurface < DIST_FOG_MIN)
|
||||
{
|
||||
fogFactor = 1.0;
|
||||
}
|
||||
// Если uDistanceToPlanetSurface < 1000.0f, то fogFactor = 0.0f (пока не пересчитан ниже),
|
||||
// что позволяет Z-Far Fog взять контроль.
|
||||
|
||||
|
||||
// --- 3.2. Расчет коэффициента тумана на основе Z-глубины (Z-Far Fog) ---
|
||||
// Этот туман работает всегда, но его эффект усиливается при уменьшении uCurrentZFar,
|
||||
// гарантируя, что все, что подходит к границе uCurrentZFar, будет скрыто.
|
||||
|
||||
// Точка начала тумана: 90% от uCurrentZFar
|
||||
float farFogStart = 2000.f;//uCurrentZFar * 0.7;
|
||||
// Длина перехода тумана: 10% от uCurrentZFar
|
||||
float depthRange = 2000.f;//uCurrentZFar * 0.25;
|
||||
|
||||
if (abs(uDistanceToPlanetSurface) < 410.f)
|
||||
{
|
||||
farFogStart = 1800.f * abs(uDistanceToPlanetSurface-10.f) * 0.0025 + 200.f;
|
||||
depthRange = farFogStart;
|
||||
}
|
||||
if (abs(uDistanceToPlanetSurface) < 10.f)
|
||||
{
|
||||
farFogStart = 200.f;
|
||||
depthRange = 200.f;
|
||||
}
|
||||
|
||||
float farFogFactor = 0.0;
|
||||
|
||||
if (depthRange > 0.0) {
|
||||
// Нормализация Z-глубины: 0.0f при farFogStart, 1.0f при farFogStart + depthRange
|
||||
farFogFactor = clamp((abs(viewZ) - farFogStart) / depthRange, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// --- 3.3. Объединение ---
|
||||
|
||||
// Когда мы далеко (fogFactor > 0.0), Distance Fog доминирует.
|
||||
// Когда мы близко (fogFactor = 0.0), Z-Far Fog берет управление.
|
||||
// Если оба активны, берем максимум (например, когда фрагмент далек от игрока, но игрок все еще в зоне Distance Fog).
|
||||
//fogFactor = max(fogFactor, farFogFactor);
|
||||
fogFactor = fogFactor * farFogFactor;
|
||||
|
||||
|
||||
// 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(finalColor.rgb, 0.5), 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);
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
attribute vec3 vPosition;
|
||||
|
||||
uniform mat4 ProjectionModelViewMatrix;
|
||||
|
||||
varying vec3 dir;
|
||||
|
||||
void main(){
|
||||
vec4 realVertexPos = vec4(vPosition.xyz, 1.0);
|
||||
gl_Position = ProjectionModelViewMatrix * realVertexPos;
|
||||
|
||||
dir = vPosition;
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
uniform samplerCube Texture;
|
||||
uniform float skyPercent;
|
||||
|
||||
varying vec3 dir;
|
||||
|
||||
void main(){
|
||||
vec4 skyBoxColor = textureCube(Texture, normalize(dir));
|
||||
vec4 skyColor = vec4(0.0, 0.5, 1.0, 1.0);
|
||||
gl_FragColor = skyPercent*skyColor + (1.0 - skyPercent) * skyBoxColor;
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user