Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a1961b5d1 | ||
|
|
af550f56a7 | ||
|
|
27fb7a448c | ||
|
|
2b6af91992 | ||
|
|
4afb9d6f4f | ||
|
|
fe361885c0 | ||
|
|
3887208b8d | ||
|
|
4c837eff0a | ||
|
|
8f9a18d960 | ||
|
|
bc49540a95 | ||
|
|
d2605d9108 | ||
|
|
115cbbb7fa | ||
| ae1ca71a20 | |||
| c02273d29d | |||
| fec7e08c2b | |||
| 0f937e2e02 | |||
|
|
b855cff0e6 | ||
|
|
b768b27d49 |
@ -436,6 +436,10 @@ add_executable(space-game001
|
|||||||
OpenGlExtensions.h
|
OpenGlExtensions.h
|
||||||
Utils.cpp
|
Utils.cpp
|
||||||
Utils.h
|
Utils.h
|
||||||
|
SparkEmitter.cpp
|
||||||
|
SparkEmitter.h
|
||||||
|
PlanetObject.cpp
|
||||||
|
PlanetObject.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Установка проекта по умолчанию для Visual Studio
|
# Установка проекта по умолчанию для Visual Studio
|
||||||
|
|||||||
@ -8,7 +8,7 @@ namespace ZL {
|
|||||||
int Environment::windowHeaderHeight = 0;
|
int Environment::windowHeaderHeight = 0;
|
||||||
int Environment::width = 0;
|
int Environment::width = 0;
|
||||||
int Environment::height = 0;
|
int Environment::height = 0;
|
||||||
float Environment::zoom = 6.f;
|
float Environment::zoom = 18.f;
|
||||||
|
|
||||||
bool Environment::leftPressed = false;
|
bool Environment::leftPressed = false;
|
||||||
bool Environment::rightPressed = false;
|
bool Environment::rightPressed = false;
|
||||||
@ -31,9 +31,13 @@ bool Environment::tapDownHold = false;
|
|||||||
Vector2f Environment::tapDownStartPos = { 0, 0 };
|
Vector2f Environment::tapDownStartPos = { 0, 0 };
|
||||||
Vector2f Environment::tapDownCurrentPos = { 0, 0 };
|
Vector2f Environment::tapDownCurrentPos = { 0, 0 };
|
||||||
|
|
||||||
Vector3f Environment::shipPosition = {0,0,0};
|
Vector3f Environment::shipPosition = {0,0,45000.f};
|
||||||
|
|
||||||
float Environment::shipVelocity = 0.f;
|
float Environment::shipVelocity = 0.f;
|
||||||
|
|
||||||
|
|
||||||
|
const float Environment::CONST_Z_NEAR = 5.f;
|
||||||
|
const float Environment::CONST_Z_FAR = 5000.f;
|
||||||
|
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
|
|||||||
@ -37,6 +37,10 @@ public:
|
|||||||
static Vector3f shipPosition;
|
static Vector3f shipPosition;
|
||||||
static float shipVelocity;
|
static float shipVelocity;
|
||||||
|
|
||||||
|
static const float CONST_Z_NEAR;
|
||||||
|
static const float CONST_Z_FAR;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
105
Game.h
105
Game.h
@ -1,61 +1,92 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "OpenGlExtensions.h"
|
#include "OpenGlExtensions.h"
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
#include "TextureManager.h"
|
#include "TextureManager.h"
|
||||||
|
#include "SparkEmitter.h"
|
||||||
|
#include "PlanetObject.h"
|
||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
|
|
||||||
struct BoxCoords
|
struct BoxCoords
|
||||||
{
|
{
|
||||||
Vector3f pos;
|
Vector3f pos;
|
||||||
Matrix3f m;
|
Matrix3f m;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Game {
|
class Game {
|
||||||
public:
|
public:
|
||||||
Game();
|
Game();
|
||||||
~Game();
|
~Game();
|
||||||
|
|
||||||
void setup();
|
void setup();
|
||||||
void update();
|
void update();
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
bool shouldExit() const { return Environment::exitGameLoop; }
|
|
||||||
|
|
||||||
private:
|
bool shouldExit() const { return Environment::exitGameLoop; }
|
||||||
void processTickCount();
|
|
||||||
void drawScene();
|
|
||||||
void drawCubemap();
|
|
||||||
void drawShip();
|
|
||||||
void drawBoxes();
|
|
||||||
|
|
||||||
SDL_Window* window;
|
private:
|
||||||
SDL_GLContext glContext;
|
void processTickCount();
|
||||||
Renderer renderer;
|
void drawScene();
|
||||||
|
void drawCubemap(float skyPercent);
|
||||||
|
void drawShip();
|
||||||
|
void drawBoxes();
|
||||||
|
void drawUI();
|
||||||
|
|
||||||
size_t newTickCount;
|
SDL_Window* window;
|
||||||
size_t lastTickCount;
|
SDL_GLContext glContext;
|
||||||
|
Renderer renderer;
|
||||||
|
|
||||||
static const size_t CONST_TIMER_INTERVAL = 10;
|
size_t newTickCount;
|
||||||
static const size_t CONST_MAX_TIME_INTERVAL = 1000;
|
size_t lastTickCount;
|
||||||
|
|
||||||
std::shared_ptr<Texture> spaceshipTexture;
|
|
||||||
std::shared_ptr<Texture> cubemapTexture;
|
|
||||||
VertexDataStruct spaceshipBase;
|
|
||||||
VertexRenderStruct spaceship;
|
|
||||||
|
|
||||||
VertexRenderStruct cubemap;
|
std::vector<BoxCoords> boxCoordsArr;
|
||||||
|
std::vector<VertexRenderStruct> boxRenderArr;
|
||||||
|
|
||||||
std::shared_ptr<Texture> boxTexture;
|
|
||||||
VertexDataStruct boxBase;
|
|
||||||
|
|
||||||
std::vector<BoxCoords> boxCoordsArr;
|
std::shared_ptr<Texture> buttonTexture;
|
||||||
std::vector<VertexRenderStruct> boxRenderArr;
|
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;
|
||||||
|
|
||||||
|
std::shared_ptr<Texture> sparkTexture;
|
||||||
|
std::shared_ptr<Texture> spaceshipTexture;
|
||||||
|
std::shared_ptr<Texture> cubemapTexture;
|
||||||
|
VertexDataStruct spaceshipBase;
|
||||||
|
VertexRenderStruct spaceship;
|
||||||
|
|
||||||
|
VertexRenderStruct cubemap;
|
||||||
|
|
||||||
|
std::shared_ptr<Texture> boxTexture;
|
||||||
|
VertexDataStruct boxBase;
|
||||||
|
|
||||||
|
SparkEmitter sparkEmitter;
|
||||||
|
PlanetObject planetObject;
|
||||||
|
};
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
582
PlanetObject.cpp
Normal file
582
PlanetObject.cpp
Normal file
@ -0,0 +1,582 @@
|
|||||||
|
#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
|
||||||
79
PlanetObject.h
Normal file
79
PlanetObject.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#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,6 +2,7 @@
|
|||||||
|
|
||||||
download from https://cmake.org/download/
|
download from https://cmake.org/download/
|
||||||
|
|
||||||
|
|
||||||
Windows x64 Installer: cmake-4.2.0-windows-x86_64.msi
|
Windows x64 Installer: cmake-4.2.0-windows-x86_64.msi
|
||||||
|
|
||||||
|
|
||||||
@ -148,7 +149,7 @@ embuilder build sdl2 sdl2_ttf sdl2_image sdl2_image_jpg sdl2_image_png
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
emcc main.cpp Game.cpp Environment.cpp BoneAnimatedModel.cpp Math.cpp Renderer.cpp TextModel.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp OpenGlExtensions.cpp -O2 -std=c++14 -pthread -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sTOTAL_MEMORY=4294967296 -sINITIAL_MEMORY=3221225472 -sMAXIMUM_MEMORY=4294967296 -sALLOW_MEMORY_GROWTH=1 -I./thirdparty/libzip-1.11.3/build-emcmake/install/include -L./thirdparty/libzip-1.11.3/build-emcmake/install/lib -lzip -lz -sUSE_SDL_IMAGE=2 -sUSE_SDL=2 -sUSE_LIBPNG=1 --preload-file space-game001.zip -o space-game001.html
|
emcc main.cpp Game.cpp Environment.cpp BoneAnimatedModel.cpp ZLMath.cpp Renderer.cpp TextModel.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp OpenGlExtensions.cpp -O2 -std=c++14 -pthread -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sTOTAL_MEMORY=4294967296 -sINITIAL_MEMORY=3221225472 -sMAXIMUM_MEMORY=4294967296 -sALLOW_MEMORY_GROWTH=1 -I./thirdparty/libzip-1.11.3/build-emcmake/install/include -L./thirdparty/libzip-1.11.3/build-emcmake/install/lib -lzip -lz -sUSE_SDL_IMAGE=2 -sUSE_SDL=2 -sUSE_LIBPNG=1 --preload-file space-game001.zip -o space-game001.html
|
||||||
|
|
||||||
emrun --no_browser --port 8080 .
|
emrun --no_browser --port 8080 .
|
||||||
```
|
```
|
||||||
|
|||||||
45
Renderer.cpp
45
Renderer.cpp
@ -294,6 +294,18 @@ namespace ZL {
|
|||||||
glBufferData(GL_ARRAY_BUFFER, data.TexCoordData.size() * 8, &data.TexCoordData[0], GL_STATIC_DRAW);
|
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)
|
if (data.NormalData.size() > 0)
|
||||||
{
|
{
|
||||||
@ -459,6 +471,12 @@ namespace ZL {
|
|||||||
return ProjectionModelViewMatrix;
|
return ProjectionModelViewMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Matrix4f Renderer::GetCurrentModelViewMatrix()
|
||||||
|
{
|
||||||
|
return ModelviewMatrixStack.top();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Renderer::SetMatrix()
|
void Renderer::SetMatrix()
|
||||||
{
|
{
|
||||||
if (ProjectionMatrixStack.size() <= 0)
|
if (ProjectionMatrixStack.size() <= 0)
|
||||||
@ -471,15 +489,16 @@ namespace ZL {
|
|||||||
throw std::runtime_error("Modelview matrix stack out!");
|
throw std::runtime_error("Modelview matrix stack out!");
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectionModelViewMatrix = ProjectionMatrixStack.top() * ModelviewMatrixStack.top();
|
Matrix4f& modelViewMatrix = ModelviewMatrixStack.top();
|
||||||
|
ProjectionModelViewMatrix = ProjectionMatrixStack.top() * modelViewMatrix;
|
||||||
|
|
||||||
static const std::string ProjectionModelViewMatrixName = "ProjectionModelViewMatrix";
|
static const std::string ProjectionModelViewMatrixName = "ProjectionModelViewMatrix";
|
||||||
|
|
||||||
//static const std::string ProjectionMatrixName = "ProjectionMatrix";
|
|
||||||
|
|
||||||
RenderUniformMatrix4fv(ProjectionModelViewMatrixName, false, &ProjectionModelViewMatrix.m[0]);
|
RenderUniformMatrix4fv(ProjectionModelViewMatrixName, false, &ProjectionModelViewMatrix.m[0]);
|
||||||
|
|
||||||
//RenderUniformMatrix4fv(ProjectionMatrixName, false, &ProjectionMatrixStack.top().m[0]);
|
static const std::string ModelViewMatrixName = "ModelViewMatrix";
|
||||||
|
|
||||||
|
RenderUniformMatrix4fv(ModelViewMatrixName, false, &modelViewMatrix.m[0]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,6 +727,18 @@ 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)
|
void Renderer::VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer)
|
||||||
@ -733,6 +764,7 @@ namespace ZL {
|
|||||||
static const std::string vBinormal("vBinormal");
|
static const std::string vBinormal("vBinormal");
|
||||||
static const std::string vColor("vColor");
|
static const std::string vColor("vColor");
|
||||||
static const std::string vTexCoord("vTexCoord");
|
static const std::string vTexCoord("vTexCoord");
|
||||||
|
static const std::string vTexCoord3("vTexCoord3");
|
||||||
static const std::string vPosition("vPosition");
|
static const std::string vPosition("vPosition");
|
||||||
|
|
||||||
//glBindVertexArray(VertexRenderStruct.vao->getBuffer());
|
//glBindVertexArray(VertexRenderStruct.vao->getBuffer());
|
||||||
@ -763,6 +795,11 @@ namespace ZL {
|
|||||||
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoordVBO->getBuffer());
|
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoordVBO->getBuffer());
|
||||||
VertexAttribPointer2fv(vTexCoord, 0, NULL);
|
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());
|
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.positionVBO->getBuffer());
|
||||||
VertexAttribPointer3fv(vPosition, 0, NULL);
|
VertexAttribPointer3fv(vPosition, 0, NULL);
|
||||||
|
|||||||
@ -44,6 +44,7 @@ namespace ZL {
|
|||||||
{
|
{
|
||||||
std::vector<Vector3f> PositionData;
|
std::vector<Vector3f> PositionData;
|
||||||
std::vector<Vector2f> TexCoordData;
|
std::vector<Vector2f> TexCoordData;
|
||||||
|
std::vector<Vector3f> TexCoord3Data;
|
||||||
std::vector<Vector3f> NormalData;
|
std::vector<Vector3f> NormalData;
|
||||||
std::vector<Vector3f> TangentData;
|
std::vector<Vector3f> TangentData;
|
||||||
std::vector<Vector3f> BinormalData;
|
std::vector<Vector3f> BinormalData;
|
||||||
@ -63,6 +64,7 @@ namespace ZL {
|
|||||||
std::shared_ptr<VAOHolder> vao;
|
std::shared_ptr<VAOHolder> vao;
|
||||||
std::shared_ptr<VBOHolder> positionVBO;
|
std::shared_ptr<VBOHolder> positionVBO;
|
||||||
std::shared_ptr<VBOHolder> texCoordVBO;
|
std::shared_ptr<VBOHolder> texCoordVBO;
|
||||||
|
std::shared_ptr<VBOHolder> texCoord3VBO;
|
||||||
std::shared_ptr<VBOHolder> normalVBO;
|
std::shared_ptr<VBOHolder> normalVBO;
|
||||||
std::shared_ptr<VBOHolder> tangentVBO;
|
std::shared_ptr<VBOHolder> tangentVBO;
|
||||||
std::shared_ptr<VBOHolder> binormalVBO;
|
std::shared_ptr<VBOHolder> binormalVBO;
|
||||||
@ -108,6 +110,7 @@ namespace ZL {
|
|||||||
|
|
||||||
|
|
||||||
Matrix4f GetProjectionModelViewMatrix();
|
Matrix4f GetProjectionModelViewMatrix();
|
||||||
|
Matrix4f GetCurrentModelViewMatrix();
|
||||||
|
|
||||||
void SetMatrix();
|
void SetMatrix();
|
||||||
|
|
||||||
@ -121,7 +124,7 @@ namespace ZL {
|
|||||||
void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value);
|
void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value);
|
||||||
void RenderUniform1i(const std::string& uniformName, const int value);
|
void RenderUniform1i(const std::string& uniformName, const int value);
|
||||||
void RenderUniform3fv(const std::string& uniformName, const float* 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);
|
void VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer);
|
||||||
|
|
||||||
|
|||||||
299
SparkEmitter.cpp
Normal file
299
SparkEmitter.cpp
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
#include "SparkEmitter.h"
|
||||||
|
#include <random>
|
||||||
|
#include <cmath>
|
||||||
|
#include "OpenGlExtensions.h"
|
||||||
|
#include "Environment.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
SparkEmitter::SparkEmitter()
|
||||||
|
: emissionRate(100.0f), isActive(true), drawDataDirty(true), maxParticles(200) {
|
||||||
|
particles.resize(maxParticles);
|
||||||
|
drawPositions.reserve(maxParticles * 6);
|
||||||
|
drawTexCoords.reserve(maxParticles * 6);
|
||||||
|
lastEmissionTime = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
sparkQuad.data = VertexDataStruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions, float rate)
|
||||||
|
: emissionPoints(positions), emissionRate(rate), isActive(true),
|
||||||
|
drawDataDirty(true), maxParticles(positions.size() * 100) {
|
||||||
|
particles.resize(maxParticles);
|
||||||
|
drawPositions.reserve(maxParticles * 6);
|
||||||
|
drawTexCoords.reserve(maxParticles * 6);
|
||||||
|
lastEmissionTime = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
sparkQuad.data = VertexDataStruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions,
|
||||||
|
std::shared_ptr<Texture> tex,
|
||||||
|
float rate)
|
||||||
|
: emissionPoints(positions), texture(tex), emissionRate(rate),
|
||||||
|
isActive(true), drawDataDirty(true), maxParticles(positions.size() * 100) {
|
||||||
|
particles.resize(maxParticles);
|
||||||
|
drawPositions.reserve(maxParticles * 6);
|
||||||
|
drawTexCoords.reserve(maxParticles * 6);
|
||||||
|
lastEmissionTime = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
sparkQuad.data = VertexDataStruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SparkEmitter::setTexture(std::shared_ptr<Texture> tex) {
|
||||||
|
texture = tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SparkEmitter::prepareDrawData() {
|
||||||
|
if (!drawDataDirty) return;
|
||||||
|
|
||||||
|
drawPositions.clear();
|
||||||
|
drawTexCoords.clear();
|
||||||
|
|
||||||
|
if (getActiveParticleCount() == 0) {
|
||||||
|
drawDataDirty = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<const SparkParticle*, float>> sortedParticles;
|
||||||
|
sortedParticles.reserve(getActiveParticleCount());
|
||||||
|
|
||||||
|
for (const auto& particle : particles) {
|
||||||
|
if (particle.active) {
|
||||||
|
sortedParticles.push_back({ &particle, particle.position.v[2] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(sortedParticles.begin(), sortedParticles.end(),
|
||||||
|
[](const auto& a, const auto& b) {
|
||||||
|
return a.second > b.second;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const auto& [particlePtr, depth] : sortedParticles) {
|
||||||
|
const auto& particle = *particlePtr;
|
||||||
|
Vector3f pos = particle.position;
|
||||||
|
float size = 0.04f * particle.scale;
|
||||||
|
|
||||||
|
drawPositions.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
|
||||||
|
drawTexCoords.push_back({ 0.0f, 0.0f });
|
||||||
|
|
||||||
|
drawPositions.push_back({ pos.v[0] - size, pos.v[1] + size, pos.v[2] });
|
||||||
|
drawTexCoords.push_back({ 0.0f, 1.0f });
|
||||||
|
|
||||||
|
drawPositions.push_back({ pos.v[0] + size, pos.v[1] + size, pos.v[2] });
|
||||||
|
drawTexCoords.push_back({ 1.0f, 1.0f });
|
||||||
|
|
||||||
|
drawPositions.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
|
||||||
|
drawTexCoords.push_back({ 0.0f, 0.0f });
|
||||||
|
|
||||||
|
drawPositions.push_back({ pos.v[0] + size, pos.v[1] + size, pos.v[2] });
|
||||||
|
drawTexCoords.push_back({ 1.0f, 1.0f });
|
||||||
|
|
||||||
|
drawPositions.push_back({ pos.v[0] + size, pos.v[1] - size, pos.v[2] });
|
||||||
|
drawTexCoords.push_back({ 1.0f, 0.0f });
|
||||||
|
}
|
||||||
|
|
||||||
|
drawDataDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SparkEmitter::draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight) {
|
||||||
|
if (getActiveParticleCount() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!texture) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareDrawData();
|
||||||
|
|
||||||
|
if (drawPositions.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sparkQuad.data.PositionData = drawPositions;
|
||||||
|
sparkQuad.data.TexCoordData = drawTexCoords;
|
||||||
|
sparkQuad.RefreshVBO();
|
||||||
|
|
||||||
|
static const std::string defaultShaderName = "default";
|
||||||
|
static const std::string vPositionName = "vPosition";
|
||||||
|
static const std::string vTexCoordName = "vTexCoord";
|
||||||
|
static const std::string textureUniformName = "Texture";
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(defaultShaderName);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
renderer.EnableVertexAttribArray(vPositionName);
|
||||||
|
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);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.LoadIdentity();
|
||||||
|
renderer.TranslateMatrix({ 0, 0, -1.0f * zoom });
|
||||||
|
|
||||||
|
renderer.DrawVertexRenderStruct(sparkQuad);
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
|
renderer.DisableVertexAttribArray(vPositionName);
|
||||||
|
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SparkEmitter::update(float deltaTimeMs) {
|
||||||
|
auto currentTime = std::chrono::steady_clock::now();
|
||||||
|
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
currentTime - lastEmissionTime).count();
|
||||||
|
|
||||||
|
if (isActive && elapsed >= emissionRate) {
|
||||||
|
emit();
|
||||||
|
lastEmissionTime = currentTime;
|
||||||
|
drawDataDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool anyChanged = false;
|
||||||
|
for (auto& particle : particles) {
|
||||||
|
if (particle.active) {
|
||||||
|
Vector3f oldPosition = particle.position;
|
||||||
|
float oldScale = particle.scale;
|
||||||
|
|
||||||
|
particle.position.v[0] += particle.velocity.v[0] * deltaTimeMs / 1000.0f;
|
||||||
|
particle.position.v[1] += particle.velocity.v[1] * deltaTimeMs / 1000.0f;
|
||||||
|
particle.position.v[2] += particle.velocity.v[2] * deltaTimeMs / 1000.0f;
|
||||||
|
|
||||||
|
particle.lifeTime += deltaTimeMs;
|
||||||
|
|
||||||
|
if (particle.lifeTime >= particle.maxLifeTime) {
|
||||||
|
particle.active = false;
|
||||||
|
anyChanged = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
float lifeRatio = particle.lifeTime / particle.maxLifeTime;
|
||||||
|
particle.scale = 1.0f - lifeRatio * 0.8f;
|
||||||
|
|
||||||
|
if (oldPosition.v[0] != particle.position.v[0] ||
|
||||||
|
oldPosition.v[1] != particle.position.v[1] ||
|
||||||
|
oldPosition.v[2] != particle.position.v[2] ||
|
||||||
|
oldScale != particle.scale) {
|
||||||
|
anyChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anyChanged) {
|
||||||
|
drawDataDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SparkEmitter::emit() {
|
||||||
|
if (emissionPoints.empty()) return;
|
||||||
|
bool emitted = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < emissionPoints.size(); ++i) {
|
||||||
|
bool particleFound = false;
|
||||||
|
|
||||||
|
for (auto& particle : particles) {
|
||||||
|
if (!particle.active) {
|
||||||
|
initParticle(particle, i);
|
||||||
|
particle.active = true;
|
||||||
|
particle.lifeTime = 0;
|
||||||
|
particle.position = emissionPoints[i];
|
||||||
|
particle.emitterIndex = i;
|
||||||
|
particleFound = true;
|
||||||
|
emitted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!particleFound && !particles.empty()) {
|
||||||
|
size_t oldestIndex = 0;
|
||||||
|
float maxLifeTime = 0;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < particles.size(); ++j) {
|
||||||
|
if (particles[j].lifeTime > maxLifeTime) {
|
||||||
|
maxLifeTime = particles[j].lifeTime;
|
||||||
|
oldestIndex = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initParticle(particles[oldestIndex], i);
|
||||||
|
particles[oldestIndex].active = true;
|
||||||
|
particles[oldestIndex].lifeTime = 0;
|
||||||
|
particles[oldestIndex].position = emissionPoints[i];
|
||||||
|
particles[oldestIndex].emitterIndex = i;
|
||||||
|
emitted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emitted) {
|
||||||
|
drawDataDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SparkEmitter::setEmissionPoints(const std::vector<Vector3f>& positions) {
|
||||||
|
emissionPoints = positions;
|
||||||
|
maxParticles = positions.size() * 100;
|
||||||
|
particles.resize(maxParticles);
|
||||||
|
drawDataDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SparkEmitter::initParticle(SparkParticle& particle, int emitterIndex) {
|
||||||
|
particle.velocity = getRandomVelocity(emitterIndex);
|
||||||
|
particle.scale = 1.0f;
|
||||||
|
particle.maxLifeTime = 800.0f + (rand() % 400);
|
||||||
|
particle.emitterIndex = emitterIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3f SparkEmitter::getRandomVelocity(int emitterIndex) {
|
||||||
|
static std::random_device rd;
|
||||||
|
static std::mt19937 gen(rd());
|
||||||
|
static std::uniform_real_distribution<> angleDist(0, 2 * M_PI);
|
||||||
|
static std::uniform_real_distribution<> speedDist(0.5f, 2.0f);
|
||||||
|
static std::uniform_real_distribution<> zSpeedDist(1.0f, 3.0f);
|
||||||
|
|
||||||
|
float angle = angleDist(gen);
|
||||||
|
float speed = speedDist(gen);
|
||||||
|
float zSpeed = zSpeedDist(gen);
|
||||||
|
|
||||||
|
if (emitterIndex == 0) {
|
||||||
|
return Vector3f{
|
||||||
|
cosf(angle) * speed - 0.3f,
|
||||||
|
sinf(angle) * speed,
|
||||||
|
zSpeed
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Vector3f{
|
||||||
|
cosf(angle) * speed + 0.3f,
|
||||||
|
sinf(angle) * speed,
|
||||||
|
zSpeed
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<SparkParticle>& SparkEmitter::getParticles() const {
|
||||||
|
return particles;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SparkEmitter::getActiveParticleCount() const {
|
||||||
|
size_t count = 0;
|
||||||
|
for (const auto& particle : particles) {
|
||||||
|
if (particle.active) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
66
SparkEmitter.h
Normal file
66
SparkEmitter.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ZLMath.h"
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include "TextureManager.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
struct SparkParticle {
|
||||||
|
Vector3f position;
|
||||||
|
Vector3f velocity;
|
||||||
|
float scale;
|
||||||
|
float lifeTime;
|
||||||
|
float maxLifeTime;
|
||||||
|
bool active;
|
||||||
|
int emitterIndex;
|
||||||
|
|
||||||
|
SparkParticle() : position({ 0,0,0 }), velocity({ 0,0,0 }), scale(1.0f),
|
||||||
|
lifeTime(0), maxLifeTime(1000.0f), active(false), emitterIndex(0) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SparkEmitter {
|
||||||
|
private:
|
||||||
|
std::vector<SparkParticle> particles;
|
||||||
|
std::vector<Vector3f> emissionPoints;
|
||||||
|
std::chrono::steady_clock::time_point lastEmissionTime;
|
||||||
|
float emissionRate;
|
||||||
|
bool isActive;
|
||||||
|
|
||||||
|
std::vector<Vector3f> drawPositions;
|
||||||
|
std::vector<Vector2f> drawTexCoords;
|
||||||
|
bool drawDataDirty;
|
||||||
|
VertexRenderStruct sparkQuad;
|
||||||
|
std::shared_ptr<Texture> texture;
|
||||||
|
|
||||||
|
int maxParticles;
|
||||||
|
|
||||||
|
void prepareDrawData();
|
||||||
|
|
||||||
|
public:
|
||||||
|
SparkEmitter();
|
||||||
|
SparkEmitter(const std::vector<Vector3f>& positions, float rate = 100.0f);
|
||||||
|
SparkEmitter(const std::vector<Vector3f>& positions,
|
||||||
|
std::shared_ptr<Texture> tex,
|
||||||
|
float rate = 100.0f);
|
||||||
|
|
||||||
|
void setEmissionPoints(const std::vector<Vector3f>& positions);
|
||||||
|
void setTexture(std::shared_ptr<Texture> tex);
|
||||||
|
|
||||||
|
void update(float deltaTimeMs);
|
||||||
|
void emit();
|
||||||
|
|
||||||
|
void draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight);
|
||||||
|
|
||||||
|
const std::vector<SparkParticle>& getParticles() const;
|
||||||
|
size_t getActiveParticleCount() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initParticle(SparkParticle& particle, int emitterIndex);
|
||||||
|
Vector3f getRandomVelocity(int emitterIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
26
ZLMath.h
26
ZLMath.h
@ -56,6 +56,23 @@ namespace ZL {
|
|||||||
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
|
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 {
|
/*Vector3f operator-(const Vector3f& other) const {
|
||||||
return Vector3f(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]);
|
return Vector3f(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]);
|
||||||
@ -67,6 +84,15 @@ namespace ZL {
|
|||||||
struct Vector2f
|
struct Vector2f
|
||||||
{
|
{
|
||||||
std::array<float, 2> v = {0.f, 0.f};
|
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);
|
Vector2f operator+(const Vector2f& x, const Vector2f& y);
|
||||||
|
|||||||
BIN
resources/button.png
(Stored with Git LFS)
Normal file
BIN
resources/button.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/musicVolumeBarButton.png
(Stored with Git LFS)
Normal file
BIN
resources/musicVolumeBarButton.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/musicVolumeBarTexture.png
(Stored with Git LFS)
Normal file
BIN
resources/musicVolumeBarTexture.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/rock.png
(Stored with Git LFS)
Normal file
BIN
resources/rock.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/sand.png
(Stored with Git LFS)
Normal file
BIN
resources/sand.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/spark.png
(Stored with Git LFS)
Normal file
BIN
resources/spark.png
(Stored with Git LFS)
Normal file
Binary file not shown.
48
shaders/defaultAtmosphere.fragment
Normal file
48
shaders/defaultAtmosphere.fragment
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Фрагментный шейдер:
|
||||||
|
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);
|
||||||
|
}
|
||||||
28
shaders/defaultAtmosphere.vertex
Normal file
28
shaders/defaultAtmosphere.vertex
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Вершинный шейдер:
|
||||||
|
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,11 +1,23 @@
|
|||||||
attribute vec3 vPosition;
|
attribute vec3 vPosition;
|
||||||
attribute vec3 vColor;
|
attribute vec3 vColor;
|
||||||
|
attribute vec3 vNormal;
|
||||||
|
attribute vec2 vTexCoord; // <-- Обычные UV (если используются)
|
||||||
|
|
||||||
varying vec3 color;
|
varying vec3 color;
|
||||||
|
varying vec3 normal;
|
||||||
|
|
||||||
|
varying vec2 TexCoord; // <-- Передаем UV
|
||||||
|
|
||||||
uniform mat4 ProjectionModelViewMatrix;
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform mat4 ModelViewMatrix;
|
||||||
|
uniform vec3 uLightDirection;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
|
||||||
color = vColor;
|
|
||||||
|
normal = normalize((ModelViewMatrix * vec4(vNormal, 0.0)).xyz);
|
||||||
|
|
||||||
|
color = vColor;
|
||||||
|
TexCoord = vTexCoord;
|
||||||
}
|
}
|
||||||
@ -1,9 +1,22 @@
|
|||||||
//precision mediump float;
|
varying vec3 color; // Цвет вершины (с шумом)
|
||||||
varying vec3 color;
|
varying vec3 normal;
|
||||||
|
varying vec3 lightDirection_VS;
|
||||||
|
varying vec2 TexCoord; // UV-координаты
|
||||||
|
|
||||||
|
uniform sampler2D Texture;
|
||||||
|
uniform vec3 uLightDirection;
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
//gl_FragColor = vec4(color, 1.0);
|
// 1. Получаем цвет из текстуры и смешиваем с цветовым шумом
|
||||||
gl_FragColor = vec4(1.0, 1.0, 0.5, 1.0);
|
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);
|
||||||
|
|
||||||
}
|
}
|
||||||
35
shaders/defaultColor_fog.vertex
Normal file
35
shaders/defaultColor_fog.vertex
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Вершинный шейдер (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;
|
||||||
|
}
|
||||||
105
shaders/defaultColor_fog_desktop.fragment
Normal file
105
shaders/defaultColor_fog_desktop.fragment
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// ---Фрагментный шейдер (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);
|
||||||
|
}
|
||||||
@ -5,8 +5,8 @@ varying vec2 texCoord;
|
|||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec4 color = texture2D(Texture,texCoord).rgba;
|
vec4 color = texture2D(Texture,texCoord).rgba;
|
||||||
gl_FragColor = vec4(color.rgb*0.9 + vec3(0.1, 0.1, 0.1), 1.0);
|
//gl_FragColor = vec4(color.rgb*0.9 + vec3(0.1, 0.1, 0.1), 1.0);
|
||||||
|
|
||||||
//gl_FragColor = color;
|
gl_FragColor = color;
|
||||||
|
|
||||||
}
|
}
|
||||||
12
shaders/env_sky.vertex
Normal file
12
shaders/env_sky.vertex
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
attribute vec3 vPosition;
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
|
||||||
|
varying vec3 dir;
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec4 realVertexPos = vec4(vPosition.xyz, 1.0);
|
||||||
|
gl_Position = ProjectionModelViewMatrix * realVertexPos;
|
||||||
|
|
||||||
|
dir = vPosition;
|
||||||
|
}
|
||||||
11
shaders/env_sky_desktop.fragment
Normal file
11
shaders/env_sky_desktop.fragment
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
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