Compare commits
4 Commits
854a425d85
...
14b43239b5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14b43239b5 | ||
|
|
7fc46d36a1 | ||
|
|
29834d528a | ||
|
|
e690d0f8e2 |
@ -444,6 +444,10 @@ add_executable(space-game001
|
|||||||
PlanetData.h
|
PlanetData.h
|
||||||
Perlin.cpp
|
Perlin.cpp
|
||||||
Perlin.h
|
Perlin.h
|
||||||
|
StoneObject.cpp
|
||||||
|
StoneObject.h
|
||||||
|
FrameBuffer.cpp
|
||||||
|
FrameBuffer.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Установка проекта по умолчанию для Visual Studio
|
# Установка проекта по умолчанию для Visual Studio
|
||||||
|
|||||||
49
FrameBuffer.cpp
Normal file
49
FrameBuffer.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include "FrameBuffer.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include "Environment.h"
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
FrameBuffer::FrameBuffer(int w, int h) : width(w), height(h) {
|
||||||
|
// 1. Ñîçäàåì FBO
|
||||||
|
glGenFramebuffers(1, &fbo);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
|
||||||
|
// 2. Ñîçäàåì òåêñòóðó, êóäà áóäåì "ôîòîãðàôèðîâàòü"
|
||||||
|
glGenTextures(1, &textureID);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||||
|
|
||||||
|
// Óñòàíàâëèâàåì ïàðàìåòðû òåêñòóðû
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
// 3. Ïðèâÿçûâàåì òåêñòóðó ê FBO
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0);
|
||||||
|
|
||||||
|
// Ïðîâåðêà ãîòîâíîñòè
|
||||||
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
std::cerr << "Error: Framebuffer is not complete!" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameBuffer::~FrameBuffer() {
|
||||||
|
glDeleteFramebuffers(1, &fbo);
|
||||||
|
glDeleteTextures(1, &textureID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameBuffer::Bind() {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
glViewport(0, 0, width, height); // Âàæíî: óñòàíàâëèâàåì âüþïîðò ïîä ðàçìåð òåêñòóðû
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameBuffer::Unbind() {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
// Çäåñü æåëàòåëüíî âîçâðàùàòü âüþïîðò ê ðàçìåðàì ýêðàíà,
|
||||||
|
// íàïðèìåð, ÷åðåç Environment::width/height
|
||||||
|
glViewport(0, 0, Environment::width, Environment::height);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
29
FrameBuffer.h
Normal file
29
FrameBuffer.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "OpenGlExtensions.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
class FrameBuffer {
|
||||||
|
private:
|
||||||
|
GLuint fbo = 0;
|
||||||
|
GLuint textureID = 0;
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FrameBuffer(int w, int h);
|
||||||
|
~FrameBuffer();
|
||||||
|
|
||||||
|
// Çàïðåùàåì êîïèðîâàíèå, êàê â VBOHolder
|
||||||
|
FrameBuffer(const FrameBuffer&) = delete;
|
||||||
|
FrameBuffer& operator=(const FrameBuffer&) = delete;
|
||||||
|
|
||||||
|
void Bind(); // Íà÷àòü ðåíäåð â ýòîò áóôåð
|
||||||
|
void Unbind(); // Âåðíóòüñÿ ê îáû÷íîìó ðåíäåðó â ýêðàí
|
||||||
|
|
||||||
|
GLuint getTextureID() const { return textureID; }
|
||||||
|
int getWidth() const { return width; }
|
||||||
|
int getHeight() const { return height; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
239
Game.cpp
239
Game.cpp
@ -6,6 +6,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "TextureManager.h"
|
#include "TextureManager.h"
|
||||||
#include "TextModel.h"
|
#include "TextModel.h"
|
||||||
|
#include "StoneObject.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
@ -17,180 +18,13 @@ namespace ZL
|
|||||||
const char* CONST_ZIP_FILE = "";
|
const char* CONST_ZIP_FILE = "";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Вспомогательная функция для получения случайного числа в диапазоне [min, max]
|
|
||||||
float getRandomFloat(std::mt19937& gen, float min, float max) {
|
|
||||||
std::uniform_real_distribution<> distrib(min, max);
|
|
||||||
return static_cast<float>(distrib(gen));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Икосаэдр (на основе золотого сечения phi)
|
|
||||||
// Координаты могут быть вычислены заранее для константного икосаэдра.
|
|
||||||
// Здесь только объявление, чтобы показать идею.
|
|
||||||
|
|
||||||
VertexDataStruct CreateConvexPolyhedron(uint64_t seed) {
|
|
||||||
|
|
||||||
// --- КОНСТАНТЫ ПАРАМЕТРОВ (как вы просили) ---
|
|
||||||
const float BASE_SCALE = 3.0f; // Общий размер камня
|
|
||||||
const float MIN_AXIS_SCALE = 0.5f; // Минимальное растяжение/сжатие по оси
|
|
||||||
const float MAX_AXIS_SCALE = 1.5f; // Максимальное растяжение/сжатие по оси
|
|
||||||
const float MIN_PERTURBATION = 0.05f; // Минимальное радиальное возмущение вершины
|
|
||||||
const float MAX_PERTURBATION = 0.25f; // Максимальное радиальное возмущение вершины
|
|
||||||
// const size_t SUBDIVISION_LEVEL = 1; // Уровень подразделения (для более круглого камня, пока опустим)
|
|
||||||
|
|
||||||
std::mt19937 engine(static_cast<unsigned int>(seed));
|
|
||||||
|
|
||||||
// Золотое сечение
|
|
||||||
const float t = (1.0f + std::sqrt(5.0f)) / 2.0f;
|
|
||||||
|
|
||||||
// 12 вершин икосаэдра
|
|
||||||
std::vector<Vector3f> initialVertices = {
|
|
||||||
{ -1, t, 0 }, { 1, t, 0 }, { -1, -t, 0 }, { 1, -t, 0 },
|
|
||||||
{ 0, -1, t }, { 0, 1, t }, { 0, -1, -t }, { 0, 1, -t },
|
|
||||||
{ t, 0, -1 }, { t, 0, 1 }, { -t, 0, -1 }, { -t, 0, 1 }
|
|
||||||
};
|
|
||||||
|
|
||||||
// 20 треугольных граней (индексы вершин)
|
|
||||||
std::vector<std::array<int, 3>> faces = {
|
|
||||||
// 5 треугольников вокруг вершины 0
|
|
||||||
{0, 11, 5}, {0, 5, 1}, {0, 1, 7}, {0, 7, 10}, {0, 10, 11},
|
|
||||||
// 5 смежных полос
|
|
||||||
{1, 5, 9}, {5, 11, 4}, {11, 10, 2}, {10, 7, 6}, {7, 1, 8},
|
|
||||||
// 5 треугольников вокруг вершины 3
|
|
||||||
{3, 9, 4}, {3, 4, 2}, {3, 2, 6}, {3, 6, 8}, {3, 8, 9},
|
|
||||||
// 5 смежных полос
|
|
||||||
{4, 9, 5}, {2, 4, 11}, {6, 2, 10}, {8, 6, 7}, {9, 8, 1}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 1. Нормализация и Возмущение (Perturbation)
|
|
||||||
for (Vector3f& v : initialVertices) {
|
|
||||||
v = v.normalized() * BASE_SCALE; // Нормализация к сфере радиуса BASE_SCALE
|
|
||||||
|
|
||||||
// Радиальное возмущение:
|
|
||||||
float perturbation = getRandomFloat(engine, MIN_PERTURBATION, MAX_PERTURBATION);
|
|
||||||
v = v * (1.0f + perturbation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Трансформация (Масштабирование и Поворот)
|
|
||||||
|
|
||||||
// Случайные масштабы по осям
|
|
||||||
Vector3f scaleFactors = {
|
|
||||||
getRandomFloat(engine, MIN_AXIS_SCALE, MAX_AXIS_SCALE),
|
|
||||||
getRandomFloat(engine, MIN_AXIS_SCALE, MAX_AXIS_SCALE),
|
|
||||||
getRandomFloat(engine, MIN_AXIS_SCALE, MAX_AXIS_SCALE)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Применяем масштабирование
|
|
||||||
for (Vector3f& v : initialVertices) {
|
|
||||||
v.v[0] *= scaleFactors.v[0];
|
|
||||||
v.v[1] *= scaleFactors.v[1];
|
|
||||||
v.v[2] *= scaleFactors.v[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Случайный поворот (например, вокруг трех осей)
|
|
||||||
Vector4f qx = QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f));
|
|
||||||
Vector4f qy = QuatFromRotateAroundY(getRandomFloat(engine, 0.0f, 360.0f));
|
|
||||||
Vector4f qz = QuatFromRotateAroundZ(getRandomFloat(engine, 0.0f, 360.0f));
|
|
||||||
Vector4f qFinal = slerp(qx, qy, 0.5f); // Простой пример комбинирования
|
|
||||||
qFinal = slerp(qFinal, qz, 0.5f).normalized();
|
|
||||||
Matrix3f rotationMatrix = QuatToMatrix(qFinal);
|
|
||||||
|
|
||||||
for (Vector3f& v : initialVertices) {
|
|
||||||
v = MultMatrixVector(rotationMatrix, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Сглаженные Нормали и Формирование Mesh
|
|
||||||
VertexDataStruct result;
|
|
||||||
// Карта для накопления нормалей по уникальным позициям вершин
|
|
||||||
// (Требует определенного оператора < для Vector3f в ZLMath.h, который у вас есть)
|
|
||||||
std::map<Vector3f, Vector3f> smoothNormalsMap;
|
|
||||||
|
|
||||||
// Предварительное заполнение карты нормалями
|
|
||||||
for (const auto& face : faces) {
|
|
||||||
Vector3f p1 = initialVertices[face[0]];
|
|
||||||
Vector3f p2 = initialVertices[face[1]];
|
|
||||||
Vector3f p3 = initialVertices[face[2]];
|
|
||||||
|
|
||||||
// Нормаль грани: (p2 - p1) x (p3 - p1)
|
|
||||||
Vector3f faceNormal = (p2 - p1).cross(p3 - p1).normalized();
|
|
||||||
|
|
||||||
smoothNormalsMap[p1] = smoothNormalsMap[p1] + faceNormal;
|
|
||||||
smoothNormalsMap[p2] = smoothNormalsMap[p2] + faceNormal;
|
|
||||||
smoothNormalsMap[p3] = smoothNormalsMap[p3] + faceNormal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Нормализация накопленных нормалей
|
|
||||||
for (auto& pair : smoothNormalsMap) {
|
|
||||||
pair.second = pair.second.normalized();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 4. Финальное заполнение VertexDataStruct и Текстурные Координаты
|
|
||||||
for (const auto& face : faces) {
|
|
||||||
Vector3f p1 = initialVertices[face[0]];
|
|
||||||
Vector3f p2 = initialVertices[face[1]];
|
|
||||||
Vector3f p3 = initialVertices[face[2]];
|
|
||||||
|
|
||||||
// Позиции
|
|
||||||
result.PositionData.push_back(p1);
|
|
||||||
result.PositionData.push_back(p2);
|
|
||||||
result.PositionData.push_back(p3);
|
|
||||||
|
|
||||||
// Сглаженные Нормали (из карты)
|
|
||||||
result.NormalData.push_back(smoothNormalsMap[p1]);
|
|
||||||
result.NormalData.push_back(smoothNormalsMap[p2]);
|
|
||||||
result.NormalData.push_back(smoothNormalsMap[p3]);
|
|
||||||
|
|
||||||
// Текстурные Координаты (Планарная проекция на плоскость грани)
|
|
||||||
// p1 -> (0, 0), p2 -> (L_12, 0), p3 -> (L_13 * cos(angle), L_13 * sin(angle))
|
|
||||||
// Где L_xy - длина вектора, angle - угол между p2-p1 и p3-p1
|
|
||||||
|
|
||||||
Vector3f uAxis = (p2 - p1).normalized();
|
|
||||||
Vector3f vRaw = p3 - p1;
|
|
||||||
|
|
||||||
// Проекция vRaw на uAxis
|
|
||||||
float uProjLen = vRaw.dot(uAxis);
|
|
||||||
|
|
||||||
// Вектор V перпендикулярный U: vRaw - uProj
|
|
||||||
Vector3f vAxisRaw = vRaw - (uAxis * uProjLen);
|
|
||||||
|
|
||||||
// Длина оси V
|
|
||||||
float vLen = vAxisRaw.length();
|
|
||||||
|
|
||||||
// Нормализованная ось V
|
|
||||||
Vector3f vAxis = vAxisRaw.normalized();
|
|
||||||
|
|
||||||
// Координаты (u, v) для p1, p2, p3 относительно p1
|
|
||||||
Vector2f uv1 = { 0.0f, 0.0f };
|
|
||||||
Vector2f uv2 = { (p2 - p1).length(), 0.0f }; // p2-p1 вдоль оси U
|
|
||||||
Vector2f uv3 = { uProjLen, vLen }; // p3-p1: u-компонента = uProjLen, v-компонента = vLen
|
|
||||||
|
|
||||||
// Находим максимальный размер, чтобы масштабировать в [0, 1]
|
|
||||||
float maxUV = max( uv2.v[0], uv3.v[0], uv3.v[1] );
|
|
||||||
|
|
||||||
if (maxUV > 0.000001f) {
|
|
||||||
// Масштабируем:
|
|
||||||
result.TexCoordData.push_back(uv1);
|
|
||||||
result.TexCoordData.push_back(uv2 * (1.f/ maxUV));
|
|
||||||
result.TexCoordData.push_back(uv3 * (1.f/ maxUV));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Предотвращение деления на ноль для вырожденных граней
|
|
||||||
result.TexCoordData.push_back({ 0.0f, 0.0f });
|
|
||||||
result.TexCoordData.push_back({ 0.0f, 0.0f });
|
|
||||||
result.TexCoordData.push_back({ 0.0f, 0.0f });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector4f generateRandomQuaternion(std::mt19937& gen)
|
Vector4f generateRandomQuaternion(std::mt19937& gen)
|
||||||
{
|
{
|
||||||
// Ðàñïðåäåëåíèå äëÿ ãåíåðàöèè ñëó÷àéíûõ êîîðäèíàò êâàòåðíèîíà
|
|
||||||
std::normal_distribution<> distrib(0.0, 1.0);
|
std::normal_distribution<> distrib(0.0, 1.0);
|
||||||
|
|
||||||
// Ãåíåðèðóåì ÷åòûðå ñëó÷àéíûõ ÷èñëà èç íîðìàëüíîãî ðàñïðåäåëåíèÿ N(0, 1).
|
|
||||||
// Íîðìàëèçàöèÿ ýòîãî âåêòîðà äàåò ðàâíîìåðíîå ðàñïðåäåëåíèå ïî 4D-ñôåðå (ò.å. êâàòåðíèîí åäèíè÷íîé äëèíû).
|
|
||||||
Vector4f randomQuat = {
|
Vector4f randomQuat = {
|
||||||
(float)distrib(gen),
|
(float)distrib(gen),
|
||||||
(float)distrib(gen),
|
(float)distrib(gen),
|
||||||
@ -202,25 +36,18 @@ namespace ZL
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- Îñíîâíàÿ ôóíêöèÿ ãåíåðàöèè ---
|
|
||||||
std::vector<BoxCoords> generateRandomBoxCoords(int N)
|
std::vector<BoxCoords> generateRandomBoxCoords(int N)
|
||||||
{
|
{
|
||||||
// Êîíñòàíòû
|
|
||||||
const float MIN_DISTANCE = 3.0f;
|
const float MIN_DISTANCE = 3.0f;
|
||||||
const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE; // Ðàáîòàåì ñ êâàäðàòîì ðàññòîÿíèÿ
|
const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE;
|
||||||
const float MIN_COORD = -100.0f;
|
const float MIN_COORD = -100.0f;
|
||||||
const float MAX_COORD = 100.0f;
|
const float MAX_COORD = 100.0f;
|
||||||
const int MAX_ATTEMPTS = 1000; // Îãðàíè÷åíèå íà êîëè÷åñòâî ïîïûòîê, ÷òîáû èçáåæàòü áåñêîíå÷íîãî öèêëà
|
const int MAX_ATTEMPTS = 1000;
|
||||||
|
|
||||||
std::vector<BoxCoords> boxCoordsArr;
|
std::vector<BoxCoords> boxCoordsArr;
|
||||||
boxCoordsArr.reserve(N); // Ðåçåðâèðóåì ïàìÿòü
|
|
||||||
|
|
||||||
// 1. Èíèöèàëèçàöèÿ ãåíåðàòîðà ïñåâäîñëó÷àéíûõ ÷èñåë
|
|
||||||
// Èñïîëüçóåì Mersenne Twister (mt19937) êàê âûñîêîêà÷åñòâåííûé ãåíåðàòîð
|
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
std::mt19937 gen(rd());
|
std::mt19937 gen(rd());
|
||||||
|
|
||||||
// 2. Îïðåäåëåíèå ðàâíîìåðíîãî ðàñïðåäåëåíèÿ äëÿ êîîðäèíàò [MIN_COORD, MAX_COORD]
|
|
||||||
std::uniform_real_distribution<> distrib(MIN_COORD, MAX_COORD);
|
std::uniform_real_distribution<> distrib(MIN_COORD, MAX_COORD);
|
||||||
|
|
||||||
int generatedCount = 0;
|
int generatedCount = 0;
|
||||||
@ -230,51 +57,41 @@ namespace ZL
|
|||||||
bool accepted = false;
|
bool accepted = false;
|
||||||
int attempts = 0;
|
int attempts = 0;
|
||||||
|
|
||||||
// Ïîïûòêà íàéòè ïîäõîäÿùèå êîîðäèíàòû
|
|
||||||
while (!accepted && attempts < MAX_ATTEMPTS)
|
while (!accepted && attempts < MAX_ATTEMPTS)
|
||||||
{
|
{
|
||||||
// Ãåíåðèðóåì íîâûå ñëó÷àéíûå êîîðäèíàòû
|
|
||||||
Vector3f newPos(
|
Vector3f newPos(
|
||||||
(float)distrib(gen),
|
(float)distrib(gen),
|
||||||
(float)distrib(gen),
|
(float)distrib(gen),
|
||||||
(float)distrib(gen)
|
(float)distrib(gen)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ïðîâåðêà ðàññòîÿíèÿ äî âñåõ óæå ñóùåñòâóþùèõ îáúåêòîâ
|
accepted = true;
|
||||||
accepted = true; // Ïðåäïîëàãàåì, ÷òî ïîäõîäèò, ïîêà íå äîêàçàíî îáðàòíîå
|
|
||||||
for (const auto& existingBox : boxCoordsArr)
|
for (const auto& existingBox : boxCoordsArr)
|
||||||
{
|
{
|
||||||
// Ðàñ÷åò âåêòîðà ðàçíîñòè
|
|
||||||
Vector3f diff = newPos - existingBox.pos;
|
Vector3f diff = newPos - existingBox.pos;
|
||||||
|
|
||||||
// Ðàñ÷åò êâàäðàòà ðàññòîÿíèÿ
|
|
||||||
float distanceSquared = diff.squaredNorm();
|
float distanceSquared = diff.squaredNorm();
|
||||||
|
|
||||||
// Åñëè êâàäðàò ðàññòîÿíèÿ ìåíüøå êâàäðàòà ìèíèìàëüíîãî ðàññòîÿíèÿ
|
|
||||||
if (distanceSquared < MIN_DISTANCE_SQUARED)
|
if (distanceSquared < MIN_DISTANCE_SQUARED)
|
||||||
{
|
{
|
||||||
accepted = false; // Îòêëîíÿåì, ñëèøêîì áëèçêî
|
accepted = false;
|
||||||
break; // Íåò ñìûñëà ïðîâåðÿòü äàëüøå, åñëè îäíî íàðóøåíèå íàéäåíî
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accepted)
|
if (accepted)
|
||||||
{
|
{
|
||||||
// 2. Ãåíåðèðóåì ñëó÷àéíûé êâàòåðíèîí
|
|
||||||
Vector4f randomQuat = generateRandomQuaternion(gen);
|
Vector4f randomQuat = generateRandomQuaternion(gen);
|
||||||
|
|
||||||
// 3. Ïðåîáðàçóåì åãî â ìàòðèöó âðàùåíèÿ
|
|
||||||
Matrix3f randomMatrix = QuatToMatrix(randomQuat);
|
Matrix3f randomMatrix = QuatToMatrix(randomQuat);
|
||||||
|
|
||||||
// 4. Äîáàâëÿåì îáúåêò ñ íîâîé ñëó÷àéíîé ìàòðèöåé
|
|
||||||
boxCoordsArr.emplace_back(BoxCoords{ newPos, randomMatrix });
|
boxCoordsArr.emplace_back(BoxCoords{ newPos, randomMatrix });
|
||||||
generatedCount++;
|
generatedCount++;
|
||||||
}
|
}
|
||||||
attempts++;
|
attempts++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Åñëè ïðåâûøåíî ìàêñèìàëüíîå êîëè÷åñòâî ïîïûòîê, âûõîäèì èç öèêëà,
|
|
||||||
// ÷òîáû èçáåæàòü çàâèñàíèÿ, åñëè N ñëèøêîì âåëèêî èëè äèàïàçîí ñëèøêîì ìàë.
|
|
||||||
if (!accepted) {
|
if (!accepted) {
|
||||||
std::cerr << "Ïðåäóïðåæäåíèå: Íå óäàëîñü ñãåíåðèðîâàòü " << N << " îáúåêòîâ. Ñãåíåðèðîâàíî: " << generatedCount << std::endl;
|
std::cerr << "Ïðåäóïðåæäåíèå: Íå óäàëîñü ñãåíåðèðîâàòü " << N << " îáúåêòîâ. Ñãåíåðèðîâàíî: " << generatedCount << std::endl;
|
||||||
break;
|
break;
|
||||||
@ -320,6 +137,7 @@ namespace ZL
|
|||||||
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_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("env", "./shaders/env.vertex", "./shaders/env_web.fragment", CONST_ZIP_FILE);
|
||||||
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere.fragment", CONST_ZIP_FILE);
|
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("defaultColorPlanet", "./shaders/defaultColorPlanet.vertex", "./shaders/defaultColorPlanet_web.fragment", CONST_ZIP_FILE);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE);
|
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE);
|
||||||
@ -327,7 +145,8 @@ namespace ZL
|
|||||||
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env_sky.vertex", "./shaders/env_sky_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("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere.fragment", CONST_ZIP_FILE);
|
||||||
renderer.shaderManager.AddShaderFromFiles("defaultColor2", "./shaders/defaultColor_fog2.vertex", "./shaders/defaultColor_fog2_desktop.fragment", CONST_ZIP_FILE);
|
renderer.shaderManager.AddShaderFromFiles("defaultColor2", "./shaders/defaultColor_fog2.vertex", "./shaders/defaultColor_fog2_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("defaultColorStones", "./shaders/defaultColor_fog_stones.vertex", "./shaders/defaultColor_fog_stones_desktop.fragment", CONST_ZIP_FILE);
|
||||||
|
renderer.shaderManager.AddShaderFromFiles("defaultColorBake", "./shaders/defaultColor_bake.vertex", "./shaders/defaultColor_bake_desktop.fragment", CONST_ZIP_FILE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cubemapTexture = std::make_shared<Texture>(
|
cubemapTexture = std::make_shared<Texture>(
|
||||||
@ -345,15 +164,16 @@ namespace ZL
|
|||||||
cubemap.RefreshVBO();
|
cubemap.RefreshVBO();
|
||||||
|
|
||||||
//Load texture
|
//Load texture
|
||||||
spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/DefaultMaterial_BaseColor.png", CONST_ZIP_FILE));
|
spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/DefaultMaterial_BaseColor_shine.png", CONST_ZIP_FILE));
|
||||||
spaceshipBase = LoadFromTextFile02("./resources/spaceship005.txt", CONST_ZIP_FILE);
|
spaceshipBase = LoadFromTextFile02("./resources/spaceship006.txt", CONST_ZIP_FILE);
|
||||||
spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0)));
|
spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0)));
|
||||||
//spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 });
|
//spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 });
|
||||||
spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 });
|
//spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 });
|
||||||
|
|
||||||
spaceship.AssignFrom(spaceshipBase);
|
spaceship.AssignFrom(spaceshipBase);
|
||||||
spaceship.RefreshVBO();
|
spaceship.RefreshVBO();
|
||||||
|
|
||||||
|
|
||||||
//Boxes
|
//Boxes
|
||||||
boxTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/box/box.png", CONST_ZIP_FILE));
|
boxTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/box/box.png", CONST_ZIP_FILE));
|
||||||
boxBase = LoadFromTextFile02("./resources/box/box.txt", CONST_ZIP_FILE);
|
boxBase = LoadFromTextFile02("./resources/box/box.txt", CONST_ZIP_FILE);
|
||||||
@ -364,8 +184,8 @@ namespace ZL
|
|||||||
|
|
||||||
for (int i = 0; i < boxCoordsArr.size(); i++)
|
for (int i = 0; i < boxCoordsArr.size(); i++)
|
||||||
{
|
{
|
||||||
//boxRenderArr[i].AssignFrom(boxBase);
|
boxRenderArr[i].AssignFrom(boxBase);
|
||||||
boxRenderArr[i].data = CreateConvexPolyhedron(1999);
|
//boxRenderArr[i].data = CreateBaseConvexPolyhedron(1999);
|
||||||
boxRenderArr[i].RefreshVBO();
|
boxRenderArr[i].RefreshVBO();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,8 +360,8 @@ namespace ZL
|
|||||||
renderer.TranslateMatrix(boxCoordsArr[i].pos);
|
renderer.TranslateMatrix(boxCoordsArr[i].pos);
|
||||||
renderer.RotateMatrix(boxCoordsArr[i].m);
|
renderer.RotateMatrix(boxCoordsArr[i].m);
|
||||||
|
|
||||||
//glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID());
|
glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID());
|
||||||
glBindTexture(GL_TEXTURE_2D, rockTexture->getTexID());
|
//glBindTexture(GL_TEXTURE_2D, rockTexture->getTexID());
|
||||||
renderer.DrawVertexRenderStruct(boxRenderArr[i]);
|
renderer.DrawVertexRenderStruct(boxRenderArr[i]);
|
||||||
|
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
@ -654,6 +474,7 @@ namespace ZL
|
|||||||
skyPercent = (1900.f - distance) / 900.f;
|
skyPercent = (1900.f - distance) / 900.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
drawCubemap(skyPercent);
|
drawCubemap(skyPercent);
|
||||||
planetObject.draw(renderer);
|
planetObject.draw(renderer);
|
||||||
if (planetObject.distanceToPlanetSurface(Environment::shipPosition) > 100.f)
|
if (planetObject.distanceToPlanetSurface(Environment::shipPosition) > 100.f)
|
||||||
@ -807,6 +628,26 @@ namespace ZL
|
|||||||
}
|
}
|
||||||
else if (event.type == SDL_KEYUP)
|
else if (event.type == SDL_KEYUP)
|
||||||
{
|
{
|
||||||
|
if (event.key.keysym.sym == SDLK_a)
|
||||||
|
{
|
||||||
|
planetObject.x += 1;
|
||||||
|
}
|
||||||
|
if (event.key.keysym.sym == SDLK_s)
|
||||||
|
{
|
||||||
|
planetObject.x -= 1;
|
||||||
|
}
|
||||||
|
if (event.key.keysym.sym == SDLK_q)
|
||||||
|
{
|
||||||
|
|
||||||
|
Environment::shipPosition = { 0, 0, 25000 };
|
||||||
|
//Environment::shipPosition = { 50000, 50000, 50000 };
|
||||||
|
|
||||||
|
//planetObject.y += 1;
|
||||||
|
}
|
||||||
|
if (event.key.keysym.sym == SDLK_w)
|
||||||
|
{
|
||||||
|
planetObject.y -= 1;
|
||||||
|
}
|
||||||
if (event.key.keysym.sym == SDLK_i)
|
if (event.key.keysym.sym == SDLK_i)
|
||||||
{
|
{
|
||||||
Environment::shipVelocity += 500.f;
|
Environment::shipVelocity += 500.f;
|
||||||
|
|||||||
@ -19,8 +19,8 @@ namespace ZL {
|
|||||||
static constexpr float NEAR_Z_NEAR = 100.0f;
|
static constexpr float NEAR_Z_NEAR = 100.0f;
|
||||||
static constexpr float NEAR_Z_FAR = 20000.0f;
|
static constexpr float NEAR_Z_FAR = 20000.0f;
|
||||||
static constexpr float TRANSITION_NEAR_END = 100.f;
|
static constexpr float TRANSITION_NEAR_END = 100.f;
|
||||||
static constexpr float SUPER_NEAR_Z_NEAR = 30.0f;
|
static constexpr float SUPER_NEAR_Z_NEAR = 5.0f;
|
||||||
static constexpr float SUPER_NEAR_Z_FAR = 6000.0f;
|
static constexpr float SUPER_NEAR_Z_FAR = 5000.0f;
|
||||||
static constexpr float TRANSITION_SUPER_NEAR_END = 30.f;
|
static constexpr float TRANSITION_SUPER_NEAR_END = 30.f;
|
||||||
|
|
||||||
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2) {
|
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2) {
|
||||||
@ -56,14 +56,14 @@ namespace ZL {
|
|||||||
|
|
||||||
void PlanetData::init() {
|
void PlanetData::init() {
|
||||||
for (int i = 0; i < planetMeshLods.size(); i++) {
|
for (int i = 0; i < planetMeshLods.size(); i++) {
|
||||||
planetMeshLods[i] = generateSphere(i, 0.02f);
|
planetMeshLods[i] = generateSphere(i, 0);
|
||||||
planetMeshLods[i].vertexData.Scale(PLANET_RADIUS);
|
planetMeshLods[i].Scale(PLANET_RADIUS);
|
||||||
planetMeshLods[i].vertexData.Move(PLANET_CENTER_OFFSET);
|
planetMeshLods[i].Move(PLANET_CENTER_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
planetAtmosphereLod = generateSphere(5, 0);
|
planetAtmosphereLod = generateSphere(5, 0);
|
||||||
planetAtmosphereLod.vertexData.Scale(PLANET_RADIUS * 1.03);
|
planetAtmosphereLod.Scale(PLANET_RADIUS * 1.03);
|
||||||
planetAtmosphereLod.vertexData.Move(PLANET_CENTER_OFFSET);
|
planetAtmosphereLod.Move(PLANET_CENTER_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
const LodLevel& PlanetData::getLodLevel(int level) const {
|
const LodLevel& PlanetData::getLodLevel(int level) const {
|
||||||
@ -165,7 +165,7 @@ namespace ZL {
|
|||||||
|
|
||||||
// --- Ðåàëèçàöèÿ getTrianglesUnderCamera (áûâøàÿ triangleUnderCamera) ---
|
// --- Ðåàëèçàöèÿ getTrianglesUnderCamera (áûâøàÿ triangleUnderCamera) ---
|
||||||
// Âñïîìîãàòåëüíàÿ ðåêóðñèâíàÿ ôóíêöèÿ, ñêðûòàÿ îò ïóáëè÷íîãî API
|
// Âñïîìîãàòåëüíàÿ ðåêóðñèâíàÿ ôóíêöèÿ, ñêðûòàÿ îò ïóáëè÷íîãî API
|
||||||
static std::vector<int> recursiveTriangleSearch(int lod, const Vector3f& pos, const std::array<LodLevel, 6>& meshes) {
|
static std::vector<int> recursiveTriangleSearch(int lod, const Vector3f& pos, const std::array<LodLevel, MAX_LOD_LEVELS>& meshes) {
|
||||||
std::vector<int> r;
|
std::vector<int> r;
|
||||||
// Ëîãèêà óðîâíÿ 0 (áàçîâûé îêòàýäð)
|
// Ëîãèêà óðîâíÿ 0 (áàçîâûé îêòàýäð)
|
||||||
if (lod == 0) {
|
if (lod == 0) {
|
||||||
@ -199,6 +199,7 @@ namespace ZL {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<int> PlanetData::getTrianglesUnderCamera(const Vector3f& viewerPosition) {
|
std::vector<int> PlanetData::getTrianglesUnderCamera(const Vector3f& viewerPosition) {
|
||||||
// Âûçûâàåì ðåêóðñèþ ñ òåêóùèì LOD
|
// Âûçûâàåì ðåêóðñèþ ñ òåêóùèì LOD
|
||||||
return recursiveTriangleSearch(currentLod, viewerPosition, planetMeshLods);
|
return recursiveTriangleSearch(currentLod, viewerPosition, planetMeshLods);
|
||||||
@ -316,31 +317,51 @@ namespace ZL {
|
|||||||
|
|
||||||
LodLevel PlanetData::trianglesToVertices(const std::vector<Triangle>& geometry) {
|
LodLevel PlanetData::trianglesToVertices(const std::vector<Triangle>& geometry) {
|
||||||
LodLevel result;
|
LodLevel result;
|
||||||
|
result.triangles = geometry;
|
||||||
|
|
||||||
result.vertexData.PositionData.reserve(geometry.size() * 3);
|
size_t vertexCount = geometry.size() * 3;
|
||||||
result.vertexData.NormalData.reserve(geometry.size() * 3);
|
result.vertexData.PositionData.reserve(vertexCount);
|
||||||
result.vertexData.TexCoordData.reserve(geometry.size() * 3); // <-- ÐÅÇÅÐÂÈÐÓÅÌ
|
result.vertexData.NormalData.reserve(vertexCount);
|
||||||
//buffer.TexCoord3Data.reserve(triangles.size() * 3); // <-- ÐÅÇÅÐÂÈÐÓÅÌ
|
result.vertexData.TexCoordData.reserve(vertexCount);
|
||||||
|
result.vertexData.TangentData.reserve(vertexCount); // Äîáàâëÿåì ðåçåðâ
|
||||||
|
result.vertexData.BinormalData.reserve(vertexCount);
|
||||||
|
result.VertexIDs.reserve(vertexCount);
|
||||||
|
|
||||||
// Ñòàíäàðòíûå UV-êîîðäèíàòû äëÿ ïîêðûòèÿ îäíîãî òðåóãîëüíèêà
|
|
||||||
// Ïîêðûâàåò òåêñòóðîé âñþ ãðàíü.
|
|
||||||
const std::array<Vector2f, 3> triangleUVs = {
|
const std::array<Vector2f, 3> triangleUVs = {
|
||||||
|
Vector2f(0.5f, 1.0f),
|
||||||
Vector2f(0.0f, 0.0f),
|
Vector2f(0.0f, 0.0f),
|
||||||
Vector2f(1.0f, 0.0f),
|
Vector2f(1.0f, 0.0f)
|
||||||
Vector2f(0.0f, 1.0f)
|
|
||||||
};
|
};
|
||||||
result.VertexIDs.reserve(geometry.size() * 3); // Çàïîëíÿåì ID çäåñü
|
|
||||||
|
|
||||||
for (const auto& t : geometry) {
|
for (const auto& t : geometry) {
|
||||||
for (int i = 0; i < 3; ++i) {
|
// --- Âû÷èñëÿåì ëîêàëüíûé áàçèñ òðåóãîëüíèêà (êàê â GetRotationForTriangle) ---
|
||||||
// Çàïîëíÿåì PositionData
|
Vector3f vA = t.data[0];
|
||||||
result.vertexData.PositionData.push_back(t.data[i]);
|
Vector3f vB = t.data[1];
|
||||||
|
Vector3f vC = t.data[2];
|
||||||
|
|
||||||
// Çàïîëíÿåì NormalData (íîðìàëü = íîðìàëèçîâàííàÿ ïîçèöèÿ íà ñôåðå)
|
Vector3f x_axis = (vC - vB).normalized(); // Íàïðàâëåíèå U
|
||||||
result.vertexData.NormalData.push_back(t.data[i].normalized());
|
|
||||||
|
Vector3f edge1 = vB - vA;
|
||||||
|
Vector3f edge2 = vC - vA;
|
||||||
|
Vector3f z_axis = edge1.cross(edge2).normalized(); // Íîðìàëü ïëîñêîñòè
|
||||||
|
|
||||||
|
// Ïðîâåðêà íàïðàâëåíèÿ íîðìàëè íàðóæó (îò öåíòðà ïëàíåòû)
|
||||||
|
Vector3f centerToTri = (vA + vB + vC).normalized();
|
||||||
|
if (z_axis.dot(centerToTri) < 0) {
|
||||||
|
z_axis = z_axis * -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3f y_axis = z_axis.cross(x_axis).normalized(); // Íàïðàâëåíèå V
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
result.vertexData.PositionData.push_back(t.data[i]);
|
||||||
|
result.vertexData.NormalData.push_back(z_axis); // Ïëîñêàÿ íîðìàëü ãðàíè äëÿ Parallax
|
||||||
result.vertexData.TexCoordData.push_back(triangleUVs[i]);
|
result.vertexData.TexCoordData.push_back(triangleUVs[i]);
|
||||||
|
|
||||||
// Çàïîëíÿåì VertexIDs
|
// Çàïèñûâàåì âû÷èñëåííûé áàçèñ â êàæäóþ âåðøèíó òðåóãîëüíèêà
|
||||||
|
result.vertexData.TangentData.push_back(x_axis);
|
||||||
|
result.vertexData.BinormalData.push_back(y_axis);
|
||||||
|
|
||||||
result.VertexIDs.push_back(t.ids[i]);
|
result.VertexIDs.push_back(t.ids[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -351,14 +372,16 @@ namespace ZL {
|
|||||||
LodLevel PlanetData::generateSphere(int subdivisions, float noiseCoeff) {
|
LodLevel PlanetData::generateSphere(int subdivisions, float noiseCoeff) {
|
||||||
// 1. Èñõîäíûé îêòàýäð è ïðèñâîåíèå ID
|
// 1. Èñõîäíûé îêòàýäð è ïðèñâîåíèå ID
|
||||||
std::vector<Triangle> geometry = {
|
std::vector<Triangle> geometry = {
|
||||||
{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f}}, // 0
|
// Âåðõíÿÿ ïîëóñôåðà (Y > 0)
|
||||||
{{ 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // 1
|
{{ 0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // 0
|
||||||
{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}}, // 2
|
{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, { 1.0f, 0.0f, 0.0f}}, // 1
|
||||||
{{ 0.0f, 1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // 3
|
{{ 0.0f, 1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // 2
|
||||||
{{ 0.0f, -1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}}, // 4
|
{{ 0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}}, // 3
|
||||||
{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}}, // 5
|
// Íèæíÿÿ ïîëóñôåðà (Y < 0)
|
||||||
{{ 0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // 6
|
{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f, 0.0f}}, // 4
|
||||||
{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, { 1.0f, 0.0f, 0.0f}} // 7
|
{{ 0.0f, -1.0f, 0.0f}, { 1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}}, // 5
|
||||||
|
{{ 0.0f, -1.0f, 0.0f}, { 0.0f, 0.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}}, // 6
|
||||||
|
{{ 0.0f, -1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f, 1.0f}} // 7
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ïðèñâîåíèå ID èñõîäíûì âåðøèíàì
|
// Ïðèñâîåíèå ID èñõîäíûì âåðøèíàì
|
||||||
@ -410,7 +433,7 @@ namespace ZL {
|
|||||||
Vector3f dir = lodLevel.vertexData.PositionData[i].normalized();
|
Vector3f dir = lodLevel.vertexData.PositionData[i].normalized();
|
||||||
lodLevel.vertexData.PositionData[i] = dir * perlin.getSurfaceHeight(dir, noiseCoeff);
|
lodLevel.vertexData.PositionData[i] = dir * perlin.getSurfaceHeight(dir, noiseCoeff);
|
||||||
// Îáðàòèòå âíèìàíèå: NormalData îñòàåòñÿ (dir), êàê â âàøåì êîäå
|
// Îáðàòèòå âíèìàíèå: NormalData îñòàåòñÿ (dir), êàê â âàøåì êîäå
|
||||||
lodLevel.vertexData.NormalData[i] = dir;
|
//lodLevel.vertexData.NormalData[i] = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
25
PlanetData.h
25
PlanetData.h
@ -16,6 +16,9 @@ namespace ZL {
|
|||||||
|
|
||||||
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2);
|
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2);
|
||||||
|
|
||||||
|
//constexpr static int MAX_LOD_LEVELS = 6;
|
||||||
|
constexpr static int MAX_LOD_LEVELS = 1;
|
||||||
|
|
||||||
struct Triangle
|
struct Triangle
|
||||||
{
|
{
|
||||||
std::array<Vector3f, 3> data;
|
std::array<Vector3f, 3> data;
|
||||||
@ -35,9 +38,29 @@ namespace ZL {
|
|||||||
|
|
||||||
struct LodLevel
|
struct LodLevel
|
||||||
{
|
{
|
||||||
|
std::vector<Triangle> triangles;
|
||||||
VertexDataStruct vertexData;
|
VertexDataStruct vertexData;
|
||||||
std::vector<VertexID> VertexIDs;
|
std::vector<VertexID> VertexIDs;
|
||||||
V2TMap v2tMap;
|
V2TMap v2tMap;
|
||||||
|
|
||||||
|
void Scale(float s)
|
||||||
|
{
|
||||||
|
vertexData.Scale(s);
|
||||||
|
for (auto& t : triangles) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
t.data[i] = t.data[i] * s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Move(Vector3f pos)
|
||||||
|
{
|
||||||
|
vertexData.Move(pos);
|
||||||
|
for (auto& t : triangles) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
t.data[i] = t.data[i] + pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlanetData {
|
class PlanetData {
|
||||||
@ -49,7 +72,7 @@ namespace ZL {
|
|||||||
PerlinNoise perlin;
|
PerlinNoise perlin;
|
||||||
PerlinNoise colorPerlin;
|
PerlinNoise colorPerlin;
|
||||||
|
|
||||||
std::array<LodLevel, 6> planetMeshLods;
|
std::array<LodLevel, MAX_LOD_LEVELS> planetMeshLods;
|
||||||
LodLevel planetAtmosphereLod;
|
LodLevel planetAtmosphereLod;
|
||||||
|
|
||||||
int currentLod; // Ëîãè÷åñêèé òåêóùèé óðîâåíü äåòàëèçàöèè
|
int currentLod; // Ëîãè÷åñêèé òåêóùèé óðîâåíü äåòàëèçàöèè
|
||||||
|
|||||||
414
PlanetObject.cpp
414
PlanetObject.cpp
@ -3,10 +3,63 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "OpenGlExtensions.h"
|
#include "OpenGlExtensions.h"
|
||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
|
#include "StoneObject.h"
|
||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
|
|
||||||
|
Matrix3f GetRotationForTriangle(const Triangle& tri) {
|
||||||
|
// Для треугольника №0:
|
||||||
|
// tri.data[0] = {0, 20000, 0} (A)
|
||||||
|
// tri.data[1] = {0, 0, 20000} (B)
|
||||||
|
// tri.data[2] = {20000, 0, 0} (C)
|
||||||
|
|
||||||
|
Vector3f vA = tri.data[0];
|
||||||
|
Vector3f vB = tri.data[1];
|
||||||
|
Vector3f vC = tri.data[2];
|
||||||
|
|
||||||
|
// 1. Вычисляем ось X (горизонталь).
|
||||||
|
// Нам нужна грань BC: от (0, 0, 20000) до (20000, 0, 0)
|
||||||
|
Vector3f x_axis = (vC - vB).normalized();
|
||||||
|
|
||||||
|
|
||||||
|
// 2. Вычисляем нормаль (ось Z).
|
||||||
|
// Порядок cross product (AB x AC) определит "лицевую" сторону.
|
||||||
|
Vector3f edge1 = vB - vA;
|
||||||
|
Vector3f edge2 = vC - vA;
|
||||||
|
Vector3f z_axis = edge1.cross(edge2).normalized();
|
||||||
|
|
||||||
|
// 3. Вычисляем ось Y (вертикаль).
|
||||||
|
// В ортонормированном базисе Y всегда перпендикулярна Z и X.
|
||||||
|
Vector3f y_axis = z_axis.cross(x_axis).normalized();
|
||||||
|
|
||||||
|
// 4. Формируем прямую матрицу поворота (Rotation/World Matrix).
|
||||||
|
// Векторы базиса записываются в СТОЛБЦЫ.
|
||||||
|
// В памяти Matrix3f m (std::array<float, 9>):
|
||||||
|
// m[0]=X.x, m[1]=Y.x, m[2]=Z.x
|
||||||
|
// m[3]=X.y, m[4]=Y.y, m[5]=Z.y
|
||||||
|
// m[6]=X.z, m[7]=Y.z, m[8]=Z.z
|
||||||
|
|
||||||
|
Matrix3f rot;
|
||||||
|
|
||||||
|
// Столбец 0: Ось X
|
||||||
|
rot.m[0] = x_axis.v[0];
|
||||||
|
rot.m[3] = x_axis.v[1];
|
||||||
|
rot.m[6] = x_axis.v[2];
|
||||||
|
|
||||||
|
// Столбец 1: Ось Y
|
||||||
|
rot.m[1] = y_axis.v[0];
|
||||||
|
rot.m[4] = y_axis.v[1];
|
||||||
|
rot.m[7] = y_axis.v[2];
|
||||||
|
|
||||||
|
// Столбец 2: Ось Z
|
||||||
|
rot.m[2] = z_axis.v[0];
|
||||||
|
rot.m[5] = z_axis.v[1];
|
||||||
|
rot.m[8] = z_axis.v[2];
|
||||||
|
|
||||||
|
return rot;
|
||||||
|
}
|
||||||
|
|
||||||
PlanetObject::PlanetObject()
|
PlanetObject::PlanetObject()
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -20,13 +73,36 @@ namespace ZL {
|
|||||||
// Берем максимальный LOD для начальной отрисовки
|
// Берем максимальный LOD для начальной отрисовки
|
||||||
int lodIndex = planetData.getMaxLodIndex();
|
int lodIndex = planetData.getMaxLodIndex();
|
||||||
planetRenderStruct.data = planetData.getLodLevel(lodIndex).vertexData;
|
planetRenderStruct.data = planetData.getLodLevel(lodIndex).vertexData;
|
||||||
|
/*planetRenderStruct.data.PositionData[0] = planetRenderStruct.data.PositionData[6 * 3];
|
||||||
|
planetRenderStruct.data.PositionData[0+1] = planetRenderStruct.data.PositionData[6 * 3+1];
|
||||||
|
planetRenderStruct.data.PositionData[0+2] = planetRenderStruct.data.PositionData[6 * 3+2];
|
||||||
|
*/
|
||||||
|
planetRenderStruct.data.PositionData.resize(3);
|
||||||
|
/*planetRenderStruct.data.NormalData[0] = Vector3f{1.0,1.0,1.0}.normalized();
|
||||||
|
planetRenderStruct.data.NormalData[1] = Vector3f{ 1.0,1.0,1.0 }.normalized();
|
||||||
|
planetRenderStruct.data.NormalData[2] = Vector3f{ 1.0,1.0,1.0 }.normalized();*/
|
||||||
planetRenderStruct.RefreshVBO();
|
planetRenderStruct.RefreshVBO();
|
||||||
|
|
||||||
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand.png", ""));
|
planetRenderStructCut.data = planetData.getLodLevel(lodIndex).vertexData;
|
||||||
|
|
||||||
|
planetRenderStructCut.data.PositionData.resize(3);
|
||||||
|
|
||||||
|
planetRenderStructCut.RefreshVBO();
|
||||||
|
//sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand2.png", ""));
|
||||||
|
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand2.png", ""));
|
||||||
|
stoneTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", ""));
|
||||||
|
|
||||||
// Атмосфера
|
// Атмосфера
|
||||||
planetAtmosphereRenderStruct.data = planetData.getAtmosphereLod().vertexData;
|
planetAtmosphereRenderStruct.data = planetData.getAtmosphereLod().vertexData;
|
||||||
planetAtmosphereRenderStruct.RefreshVBO();
|
planetAtmosphereRenderStruct.RefreshVBO();
|
||||||
|
|
||||||
|
|
||||||
|
planetStones = CreateStoneGroupData(777, planetData.getLodLevel(lodIndex));
|
||||||
|
planetStones.inflate({ 0/*,1,2,3,4,5,6,7*/ });
|
||||||
|
planetStonesToBakeRenderStruct.AssignFrom(planetStones.mesh);
|
||||||
|
planetStonesToBakeRenderStruct.RefreshVBO();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlanetObject::prepareDrawData() {
|
void PlanetObject::prepareDrawData() {
|
||||||
@ -34,68 +110,304 @@ namespace ZL {
|
|||||||
drawDataDirty = false;
|
drawDataDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PlanetObject::update(float deltaTimeMs) {
|
void PlanetObject::update(float deltaTimeMs) {
|
||||||
// Получаем видимые треугольники, передавая позицию корабля
|
// 1. Получаем базовые треугольники под камерой
|
||||||
auto lr = planetData.getTrianglesUnderCamera(Environment::shipPosition);
|
auto lr = planetData.getTrianglesUnderCamera(Environment::shipPosition);
|
||||||
int currentLod = planetData.getCurrentLodIndex();
|
int currentLod = planetData.getCurrentLodIndex();
|
||||||
|
|
||||||
|
// Временный вектор для сбора новых индексов
|
||||||
|
std::vector<int> newIndices;
|
||||||
|
std::set<int> used;
|
||||||
|
|
||||||
|
// Рекурсивно (или итеративно, как у тебя) собираем индексы видимых зон
|
||||||
|
for (int i : lr) {
|
||||||
|
if (used.insert(i).second) newIndices.push_back(i);
|
||||||
|
|
||||||
|
auto neighbors = planetData.findNeighbors(i, currentLod);
|
||||||
|
for (int n : neighbors) {
|
||||||
|
if (used.insert(n).second) newIndices.push_back(n);
|
||||||
|
|
||||||
|
auto neighbors2 = planetData.findNeighbors(n, currentLod);
|
||||||
|
for (int n2 : neighbors2) {
|
||||||
|
if (used.insert(n2).second) newIndices.push_back(n2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Сортируем новый список, чтобы порядок не влиял на сравнение
|
||||||
|
std::sort(newIndices.begin(), newIndices.end());
|
||||||
|
|
||||||
|
// 3. Сравниваем с тем, что было нарисовано в прошлый раз
|
||||||
|
if (newIndices != triangleIndicesToDraw) {
|
||||||
|
// Обновляем список индексов (используем move для эффективности)
|
||||||
|
triangleIndicesToDraw = std::move(newIndices);
|
||||||
|
|
||||||
|
// --- ОБНОВЛЯЕМ ЖЕЛТУЮ ЗОНУ (только когда изменился состав треугольников) ---
|
||||||
const auto& fullMesh = planetData.getLodLevel(currentLod).vertexData;
|
const auto& fullMesh = planetData.getLodLevel(currentLod).vertexData;
|
||||||
|
|
||||||
planetRenderRedStruct.data.PositionData.clear();
|
|
||||||
planetRenderRedStruct.data.TexCoordData.clear();
|
|
||||||
// ... очистка остальных буферов ...
|
|
||||||
|
|
||||||
planetRenderYellowStruct.data.PositionData.clear();
|
planetRenderYellowStruct.data.PositionData.clear();
|
||||||
planetRenderYellowStruct.data.TexCoordData.clear();
|
planetRenderYellowStruct.data.TexCoordData.clear();
|
||||||
|
|
||||||
std::set<int> usedYellow;
|
for (int i : triangleIndicesToDraw) {
|
||||||
|
// Копируем геометрию для подсветки
|
||||||
// Заполняем красный (текущий треугольник под камерой)
|
for (int j = 0; j < 3; ++j) {
|
||||||
for (int i : lr) {
|
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3 + j]);
|
||||||
planetRenderRedStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3]);
|
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3 + j]);
|
||||||
planetRenderRedStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3 + 1]);
|
|
||||||
planetRenderRedStruct.data.PositionData.push_back(fullMesh.PositionData[i * 3 + 2]);
|
|
||||||
planetRenderRedStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3]);
|
|
||||||
planetRenderRedStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3 + 1]);
|
|
||||||
planetRenderRedStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[i * 3 + 2]);
|
|
||||||
usedYellow.insert(i);
|
|
||||||
}
|
|
||||||
planetRenderRedStruct.RefreshVBO();
|
|
||||||
|
|
||||||
// Заполняем желтый (соседи)
|
|
||||||
for (int i : lr) {
|
|
||||||
auto neighbors = planetData.findNeighbors(i, currentLod);
|
|
||||||
for (int n : neighbors) {
|
|
||||||
if (usedYellow.count(n) == 0) {
|
|
||||||
usedYellow.insert(n);
|
|
||||||
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n * 3]);
|
|
||||||
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n * 3 + 1]);
|
|
||||||
planetRenderYellowStruct.data.PositionData.push_back(fullMesh.PositionData[n * 3 + 2]);
|
|
||||||
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n * 3]);
|
|
||||||
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n * 3 + 1]);
|
|
||||||
planetRenderYellowStruct.data.TexCoordData.push_back(fullMesh.TexCoordData[n * 3 + 2]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
planetRenderYellowStruct.RefreshVBO();
|
planetRenderYellowStruct.RefreshVBO();
|
||||||
|
|
||||||
|
// --- ОБНОВЛЯЕМ КАМНИ (через новую структуру StoneGroup) ---
|
||||||
|
if (triangleIndicesToDraw.size() > 0)
|
||||||
|
{
|
||||||
|
planetStones.inflate(triangleIndicesToDraw);
|
||||||
|
// Используем AssignFrom, он внутри сам вызывает RefreshVBO
|
||||||
|
planetStonesRenderStruct.AssignFrom(planetStones.mesh);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void PlanetObject::bakeStoneTexture(Renderer& renderer) {
|
||||||
|
glViewport(0, 0, 512, 512);
|
||||||
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
|
||||||
|
static const std::string defaultShaderName2 = "defaultColorBake";
|
||||||
|
static const std::string vPositionName = "vPosition";
|
||||||
|
static const std::string vTexCoordName = "vTexCoord";
|
||||||
|
static const std::string textureUniformName = "Texture";
|
||||||
|
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(defaultShaderName2);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
renderer.EnableVertexAttribArray(vPositionName);
|
||||||
|
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||||
|
|
||||||
|
float dist = planetData.distanceToPlanetSurface(Environment::shipPosition);
|
||||||
|
auto zRange = planetData.calculateZRange(dist);
|
||||||
|
const float currentZNear = zRange.first;
|
||||||
|
const float currentZFar = zRange.second;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Triangle tr = planetData.getLodLevel(planetData.getCurrentLodIndex()).triangles[0];
|
||||||
|
|
||||||
|
// 1. Получаем матрицу вращения (оси в столбцах)
|
||||||
|
Matrix3f mr = GetRotationForTriangle(tr);
|
||||||
|
|
||||||
|
// 2. Трансформируем вершины в локальное пространство экрана, чтобы найти габариты
|
||||||
|
// Используем MultMatrixVector(Matrix, Vector).
|
||||||
|
// Если ваша функция считает V * M, то передайте Inverse(mr).
|
||||||
|
Vector3f rA = MultMatrixVector(mr, tr.data[0]);
|
||||||
|
Vector3f rB = MultMatrixVector(mr, tr.data[1]);
|
||||||
|
Vector3f rC = MultMatrixVector(mr, tr.data[2]);
|
||||||
|
|
||||||
|
// 3. Вычисляем реальные границы треугольника после поворота
|
||||||
|
float minX = min(rA.v[0], min(rB.v[0], rC.v[0]));
|
||||||
|
float maxX = max(rA.v[0], max(rB.v[0], rC.v[0]));
|
||||||
|
float minY = min(rA.v[1], min(rB.v[1], rC.v[1]));
|
||||||
|
float maxY = max(rA.v[1], max(rB.v[1], rC.v[1]));
|
||||||
|
|
||||||
|
// Находим центр и размеры
|
||||||
|
float width = maxX - minX;
|
||||||
|
float height = maxY - minY;
|
||||||
|
float centerX = (minX + maxX) * 0.5f;
|
||||||
|
float centerY = (minY + maxY) * 0.5f;
|
||||||
|
|
||||||
|
//float size = max(width, height);
|
||||||
|
//float hSize = size * 0.5f;
|
||||||
|
|
||||||
|
renderer.PushProjectionMatrix(
|
||||||
|
centerX - width*0.5, centerX + width * 0.5,
|
||||||
|
centerY - height * 0.5, centerY + height * 0.5,
|
||||||
|
//currentZNear, currentZFar);
|
||||||
|
150, 200000);
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.LoadIdentity();
|
||||||
|
|
||||||
|
|
||||||
|
// Сдвигаем камеру по Z
|
||||||
|
renderer.TranslateMatrix(Vector3f{ 0, 0, -45000 });
|
||||||
|
|
||||||
|
// Применяем вращение
|
||||||
|
renderer.RotateMatrix(mr);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Извлекаем нормаль треугольника (это 3-й столбец нашей матрицы вращения)
|
||||||
|
Vector3f planeNormal = { mr.m[2], mr.m[5], mr.m[8] };
|
||||||
|
//Vector3f planeNormal = { 0,0,1 };
|
||||||
|
|
||||||
|
renderer.RenderUniform3fv("uPlanePoint", &tr.data[0].v[0]);
|
||||||
|
renderer.RenderUniform3fv("uPlaneNormal", &planeNormal.v[0]);
|
||||||
|
renderer.RenderUniform1f("uMaxHeight", 8000.f); // Соответствует BASE_SCALE + perturbation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID());
|
||||||
|
|
||||||
|
renderer.DrawVertexRenderStruct(planetRenderStructCut);
|
||||||
|
|
||||||
|
//glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glCullFace(GL_BACK); // Отсекаем задние грани
|
||||||
|
if (planetStonesToBakeRenderStruct.data.PositionData.size() > 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID());
|
||||||
|
renderer.DrawVertexRenderStruct(planetStonesToBakeRenderStruct);
|
||||||
|
CheckGlError();
|
||||||
|
}
|
||||||
|
glDisable(GL_CULL_FACE); // Не забываем выключить, чтобы не сломать остальной рендер
|
||||||
|
renderer.PopMatrix();
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||||
|
renderer.DisableVertexAttribArray(vPositionName);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
CheckGlError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PlanetObject::draw(Renderer& renderer) {
|
void PlanetObject::draw(Renderer& renderer) {
|
||||||
|
|
||||||
prepareDrawData();
|
prepareDrawData();
|
||||||
|
|
||||||
|
{
|
||||||
|
if (stoneMapFB == nullptr)
|
||||||
|
{
|
||||||
|
stoneMapFB = std::make_unique<FrameBuffer>(512, 512);
|
||||||
|
}
|
||||||
|
stoneMapFB->Bind();
|
||||||
|
|
||||||
|
bakeStoneTexture(renderer);
|
||||||
|
|
||||||
|
stoneMapFB->Unbind();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//bakeStoneTexture(renderer);
|
||||||
|
|
||||||
|
glViewport(0, 0, Environment::width, Environment::height);
|
||||||
//--------------------------
|
//--------------------------
|
||||||
|
|
||||||
drawPlanet(renderer);
|
|
||||||
drawYellowZone(renderer);
|
|
||||||
|
|
||||||
drawAtmosphere(renderer);
|
drawPlanet(renderer);
|
||||||
|
//drawYellowZone(renderer);
|
||||||
|
//drawStones(renderer);
|
||||||
|
|
||||||
|
//drawAtmosphere(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlanetObject::drawPlanet(Renderer& renderer)
|
void PlanetObject::drawPlanet(Renderer& renderer)
|
||||||
{
|
{
|
||||||
static const std::string defaultShaderName = "defaultColor";
|
static const std::string defaultShaderName = "defaultColorStones";
|
||||||
|
|
||||||
|
static const std::string vPositionName = "vPosition";
|
||||||
|
static const std::string vColorName = "vColor";
|
||||||
|
static const std::string vNormalName = "vNormal";
|
||||||
|
static const std::string vTexCoordName = "vTexCoord";
|
||||||
|
static const std::string vTexCoord2Name = "vTexCoord2";
|
||||||
|
//static const std::string vTexCoord3Name = "vTexCoord3";
|
||||||
|
static const std::string textureUniformName = "Texture";
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(defaultShaderName);
|
||||||
|
|
||||||
|
renderer.EnableVertexAttribArray(vPositionName);
|
||||||
|
renderer.EnableVertexAttribArray(vColorName);
|
||||||
|
renderer.EnableVertexAttribArray(vNormalName);
|
||||||
|
renderer.EnableVertexAttribArray("vTangent");
|
||||||
|
renderer.EnableVertexAttribArray("vBinormal");
|
||||||
|
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||||
|
//renderer.EnableVertexAttribArray(vTexCoord3Name);
|
||||||
|
|
||||||
|
float dist = planetData.distanceToPlanetSurface(Environment::shipPosition);
|
||||||
|
auto zRange = planetData.calculateZRange(dist);
|
||||||
|
const float currentZNear = zRange.first;
|
||||||
|
const float currentZFar = zRange.second;
|
||||||
|
|
||||||
|
// 2. Применяем динамическую матрицу проекции
|
||||||
|
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||||
|
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||||
|
currentZNear, currentZFar);
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.LoadIdentity();
|
||||||
|
//renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||||
|
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||||
|
|
||||||
|
//renderer.RotateMatrix(QuatToMatrix(QuatFromRotateAroundX(M_PI / 4.0)));
|
||||||
|
//renderer.RotateMatrix(QuatToMatrix(QuatFromRotateAroundY(-M_PI / 4.0)));
|
||||||
|
|
||||||
|
renderer.TranslateMatrix(-Environment::shipPosition);
|
||||||
|
|
||||||
|
const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix();
|
||||||
|
/*
|
||||||
|
Vector3f lightDir_World = Vector3f(1.0f, 0.0f, -1.0f).normalized();
|
||||||
|
// В OpenGL/шейдерах удобнее работать с вектором, указывающим ОТ источника к поверхности.
|
||||||
|
Vector3f lightDirection_World = -lightDir_World; // Вектор, направленный от источника
|
||||||
|
Vector3f lightDirection_View;
|
||||||
|
|
||||||
|
lightDirection_View.v[0] = viewMatrix.m[0] * lightDirection_World.v[0] + viewMatrix.m[4] * lightDirection_World.v[1] + viewMatrix.m[8] * lightDirection_World.v[2];
|
||||||
|
lightDirection_View.v[1] = viewMatrix.m[1] * lightDirection_World.v[0] + viewMatrix.m[5] * lightDirection_World.v[1] + viewMatrix.m[9] * lightDirection_World.v[2];
|
||||||
|
lightDirection_View.v[2] = viewMatrix.m[2] * lightDirection_World.v[0] + viewMatrix.m[6] * lightDirection_World.v[1] + viewMatrix.m[10] * lightDirection_World.v[2];
|
||||||
|
lightDirection_View = lightDirection_View.normalized(); // Нормализуем на всякий случай
|
||||||
|
|
||||||
|
// Установка uniform-переменной
|
||||||
|
// Предполагается, что RenderUniform3fv определена в Renderer.h
|
||||||
|
renderer.RenderUniform3fv("uLightDirection", &lightDirection_View.v[0]);
|
||||||
|
renderer.RenderUniformMatrix4fv("ModelViewMatrix", false, &viewMatrix.m[0]);
|
||||||
|
|
||||||
|
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
||||||
|
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
||||||
|
*/
|
||||||
|
renderer.RenderUniform1i("Texture", 0);
|
||||||
|
|
||||||
|
Triangle tr = planetData.getLodLevel(planetData.getCurrentLodIndex()).triangles[0]; // Берем базовый треугольник
|
||||||
|
Matrix3f mr = GetRotationForTriangle(tr); // Та же матрица, что и при запекании
|
||||||
|
|
||||||
|
// Позиция камеры (корабля) в мире
|
||||||
|
renderer.RenderUniform3fv("uViewPos", &Environment::shipPosition.v[0]);
|
||||||
|
|
||||||
|
// Передаем матрицу вращения треугольника для перехода в Tangent Space
|
||||||
|
renderer.RenderUniformMatrix3fv("uTangentMatrix", false, &mr.m[0]);
|
||||||
|
|
||||||
|
// Не забудьте масштаб эффекта (глубина камней)
|
||||||
|
//renderer.RenderUniform1f("uHeightScale", 0.08f);
|
||||||
|
//renderer.RenderUniform1f("uHeightScale", -0.01f);
|
||||||
|
renderer.RenderUniform1f("uHeightScale", 0.0f + x / 1000.f);
|
||||||
|
//renderer.RenderUniform1f("uHeightScale", 0.0f);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, stoneMapFB->getTextureID());
|
||||||
|
|
||||||
|
renderer.DrawVertexRenderStruct(planetRenderStruct);
|
||||||
|
CheckGlError();
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
renderer.PopProjectionMatrix();
|
||||||
|
//renderer.DisableVertexAttribArray(vTexCoord3Name);
|
||||||
|
renderer.DisableVertexAttribArray(vTexCoord2Name);
|
||||||
|
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||||
|
renderer.DisableVertexAttribArray(vNormalName);
|
||||||
|
renderer.DisableVertexAttribArray("vTangent");
|
||||||
|
renderer.DisableVertexAttribArray("vBinormal");
|
||||||
|
renderer.DisableVertexAttribArray(vColorName);
|
||||||
|
renderer.DisableVertexAttribArray(vPositionName);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
CheckGlError();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanetObject::drawStones(Renderer& renderer)
|
||||||
|
{
|
||||||
|
//static const std::string defaultShaderName = "defaultColor";
|
||||||
static const std::string defaultShaderName2 = "defaultColor2";
|
static const std::string defaultShaderName2 = "defaultColor2";
|
||||||
static const std::string vPositionName = "vPosition";
|
static const std::string vPositionName = "vPosition";
|
||||||
static const std::string vColorName = "vColor";
|
static const std::string vColorName = "vColor";
|
||||||
@ -104,7 +416,7 @@ namespace ZL {
|
|||||||
//static const std::string vTexCoord3Name = "vTexCoord3";
|
//static const std::string vTexCoord3Name = "vTexCoord3";
|
||||||
static const std::string textureUniformName = "Texture";
|
static const std::string textureUniformName = "Texture";
|
||||||
|
|
||||||
renderer.shaderManager.PushShader(defaultShaderName);
|
renderer.shaderManager.PushShader(defaultShaderName2);
|
||||||
renderer.RenderUniform1i(textureUniformName, 0);
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
renderer.EnableVertexAttribArray(vPositionName);
|
renderer.EnableVertexAttribArray(vPositionName);
|
||||||
renderer.EnableVertexAttribArray(vColorName);
|
renderer.EnableVertexAttribArray(vColorName);
|
||||||
@ -130,7 +442,6 @@ namespace ZL {
|
|||||||
|
|
||||||
const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix();
|
const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix();
|
||||||
|
|
||||||
|
|
||||||
Vector3f lightDir_World = Vector3f(1.0f, 0.0f, -1.0f).normalized();
|
Vector3f lightDir_World = Vector3f(1.0f, 0.0f, -1.0f).normalized();
|
||||||
// В OpenGL/шейдерах удобнее работать с вектором, указывающим ОТ источника к поверхности.
|
// В OpenGL/шейдерах удобнее работать с вектором, указывающим ОТ источника к поверхности.
|
||||||
Vector3f lightDirection_World = -lightDir_World; // Вектор, направленный от источника
|
Vector3f lightDirection_World = -lightDir_World; // Вектор, направленный от источника
|
||||||
@ -148,13 +459,16 @@ namespace ZL {
|
|||||||
|
|
||||||
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
||||||
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
||||||
//glEnable(GL_BLEND);
|
Vector3f color2 = { 1.0, 1.0, 1.0 };
|
||||||
//glBlendFunc(GL_SRC_ALPHA, GL_ONE);// Аддитивное смешивание для эффекта свечения
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID());
|
renderer.RenderUniform3fv("uColor", &color2.v[0]);
|
||||||
renderer.DrawVertexRenderStruct(planetRenderStruct);
|
|
||||||
//glDisable(GL_BLEND);
|
if (planetStonesRenderStruct.data.PositionData.size() > 0)
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID());
|
||||||
|
renderer.DrawVertexRenderStruct(planetStonesRenderStruct);
|
||||||
CheckGlError();
|
CheckGlError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
@ -172,6 +486,7 @@ namespace ZL {
|
|||||||
|
|
||||||
void PlanetObject::drawYellowZone(Renderer& renderer)
|
void PlanetObject::drawYellowZone(Renderer& renderer)
|
||||||
{
|
{
|
||||||
|
|
||||||
static const std::string defaultShaderName = "defaultColor";
|
static const std::string defaultShaderName = "defaultColor";
|
||||||
static const std::string defaultShaderName2 = "defaultColor2";
|
static const std::string defaultShaderName2 = "defaultColor2";
|
||||||
static const std::string vPositionName = "vPosition";
|
static const std::string vPositionName = "vPosition";
|
||||||
@ -186,7 +501,9 @@ namespace ZL {
|
|||||||
const float currentZNear = zRange.first;
|
const float currentZNear = zRange.first;
|
||||||
const float currentZFar = zRange.second;
|
const float currentZFar = zRange.second;
|
||||||
|
|
||||||
if (planetRenderRedStruct.data.PositionData.size() > 0)
|
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
if (planetRenderYellowStruct.data.PositionData.size() > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
renderer.shaderManager.PushShader(defaultShaderName2);
|
renderer.shaderManager.PushShader(defaultShaderName2);
|
||||||
@ -212,12 +529,7 @@ namespace ZL {
|
|||||||
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
||||||
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID());
|
|
||||||
|
|
||||||
Vector3f color1 = { 1.0, 0.0, 0.0 };
|
|
||||||
Vector3f color2 = { 1.0, 1.0, 0.0 };
|
Vector3f color2 = { 1.0, 1.0, 0.0 };
|
||||||
renderer.RenderUniform3fv("uColor", &color1.v[0]);
|
|
||||||
renderer.DrawVertexRenderStruct(planetRenderRedStruct);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID());
|
glBindTexture(GL_TEXTURE_2D, sandTexture->getTexID());
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,8 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include "Perlin.h"
|
#include "Perlin.h"
|
||||||
#include "PlanetData.h"
|
#include "PlanetData.h"
|
||||||
|
#include "StoneObject.h"
|
||||||
|
#include "FrameBuffer.h"
|
||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
@ -25,25 +27,39 @@ namespace ZL {
|
|||||||
|
|
||||||
// Данные только для рендеринга (OpenGL specific)
|
// Данные только для рендеринга (OpenGL specific)
|
||||||
VertexRenderStruct planetRenderStruct;
|
VertexRenderStruct planetRenderStruct;
|
||||||
VertexRenderStruct planetRenderRedStruct;
|
VertexRenderStruct planetRenderStructCut;
|
||||||
VertexRenderStruct planetRenderYellowStruct;
|
VertexRenderStruct planetRenderYellowStruct;
|
||||||
VertexRenderStruct planetAtmosphereRenderStruct;
|
VertexRenderStruct planetAtmosphereRenderStruct;
|
||||||
|
VertexRenderStruct planetStonesRenderStruct;
|
||||||
|
VertexRenderStruct planetStonesToBakeRenderStruct;
|
||||||
|
StoneGroup planetStones;
|
||||||
|
|
||||||
|
std::vector<int> triangleIndicesToDraw;
|
||||||
|
|
||||||
std::shared_ptr<Texture> sandTexture;
|
std::shared_ptr<Texture> sandTexture;
|
||||||
|
std::shared_ptr<Texture> stoneTexture;
|
||||||
|
|
||||||
bool drawDataDirty = true;
|
bool drawDataDirty = true;
|
||||||
void prepareDrawData();
|
void prepareDrawData();
|
||||||
|
|
||||||
|
std::unique_ptr<FrameBuffer> stoneMapFB;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PlanetObject();
|
PlanetObject();
|
||||||
|
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void update(float deltaTimeMs);
|
void update(float deltaTimeMs);
|
||||||
|
void bakeStoneTexture(Renderer& renderer);
|
||||||
void draw(Renderer& renderer);
|
void draw(Renderer& renderer);
|
||||||
|
void drawStones(Renderer& renderer);
|
||||||
void drawPlanet(Renderer& renderer);
|
void drawPlanet(Renderer& renderer);
|
||||||
void drawYellowZone(Renderer& renderer);
|
void drawYellowZone(Renderer& renderer);
|
||||||
void drawAtmosphere(Renderer& renderer);
|
void drawAtmosphere(Renderer& renderer);
|
||||||
|
|
||||||
|
|
||||||
float distanceToPlanetSurface(const Vector3f& viewerPosition);
|
float distanceToPlanetSurface(const Vector3f& viewerPosition);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
39
Renderer.cpp
39
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.TexCoord2Data.size() > 0)
|
||||||
|
{
|
||||||
|
if (!texCoord2VBO)
|
||||||
|
{
|
||||||
|
texCoord2VBO = std::make_shared<VBOHolder>();
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, texCoord2VBO->getBuffer());
|
||||||
|
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, data.TexCoord2Data.size() * 8, &data.TexCoord2Data[0], GL_STATIC_DRAW);
|
||||||
|
}*/
|
||||||
|
|
||||||
if (data.TexCoord3Data.size() > 0)
|
if (data.TexCoord3Data.size() > 0)
|
||||||
{
|
{
|
||||||
if (!texCoord3VBO)
|
if (!texCoord3VBO)
|
||||||
@ -443,6 +455,18 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::PushProjectionMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar)
|
||||||
|
{
|
||||||
|
Matrix4f m = MakeOrthoMatrix(xmin, xmax, ymin, ymax, zNear, zFar);
|
||||||
|
ProjectionMatrixStack.push(m);
|
||||||
|
SetMatrix();
|
||||||
|
|
||||||
|
if (ProjectionMatrixStack.size() > CONST_MATRIX_STACK_SIZE)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Projection matrix stack overflow!!!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar)
|
void Renderer::PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar)
|
||||||
{
|
{
|
||||||
Matrix4f m = MakePerspectiveMatrix(fovY, aspectRatio, zNear, zFar);
|
Matrix4f m = MakePerspectiveMatrix(fovY, aspectRatio, zNear, zFar);
|
||||||
@ -689,6 +713,18 @@ namespace ZL {
|
|||||||
glDisableVertexAttribArray(shader->attribList[attribName]);
|
glDisableVertexAttribArray(shader->attribList[attribName]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value)
|
||||||
|
{
|
||||||
|
auto shader = shaderManager.GetCurrentShader();
|
||||||
|
|
||||||
|
auto uniform = shader->uniformList.find(uniformName);
|
||||||
|
|
||||||
|
if (uniform != shader->uniformList.end())
|
||||||
|
{
|
||||||
|
glUniformMatrix3fv(uniform->second, 1, transpose, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Renderer::RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value)
|
void Renderer::RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value)
|
||||||
{
|
{
|
||||||
@ -764,6 +800,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 vTexCoord2("vTexCoord2");
|
||||||
static const std::string vTexCoord3("vTexCoord3");
|
static const std::string vTexCoord3("vTexCoord3");
|
||||||
static const std::string vPosition("vPosition");
|
static const std::string vPosition("vPosition");
|
||||||
|
|
||||||
@ -798,7 +835,7 @@ namespace ZL {
|
|||||||
if (VertexRenderStruct.data.TexCoord3Data.size() > 0)
|
if (VertexRenderStruct.data.TexCoord3Data.size() > 0)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoord3VBO->getBuffer());
|
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoord3VBO->getBuffer());
|
||||||
VertexAttribPointer2fv(vTexCoord3, 0, NULL);
|
VertexAttribPointer3fv(vTexCoord3, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.positionVBO->getBuffer());
|
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.positionVBO->getBuffer());
|
||||||
|
|||||||
@ -44,6 +44,7 @@ namespace ZL {
|
|||||||
{
|
{
|
||||||
std::vector<Vector3f> PositionData;
|
std::vector<Vector3f> PositionData;
|
||||||
std::vector<Vector2f> TexCoordData;
|
std::vector<Vector2f> TexCoordData;
|
||||||
|
//std::vector<Vector2f> TexCoord2Data;
|
||||||
std::vector<Vector3f> TexCoord3Data;
|
std::vector<Vector3f> TexCoord3Data;
|
||||||
std::vector<Vector3f> NormalData;
|
std::vector<Vector3f> NormalData;
|
||||||
std::vector<Vector3f> TangentData;
|
std::vector<Vector3f> TangentData;
|
||||||
@ -64,6 +65,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> texCoord2VBO;
|
||||||
std::shared_ptr<VBOHolder> texCoord3VBO;
|
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;
|
||||||
@ -95,6 +97,7 @@ namespace ZL {
|
|||||||
void InitOpenGL();
|
void InitOpenGL();
|
||||||
|
|
||||||
void PushProjectionMatrix(float width, float height, float zNear = 0.f, float zFar = 1.f);
|
void PushProjectionMatrix(float width, float height, float zNear = 0.f, float zFar = 1.f);
|
||||||
|
void PushProjectionMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar);
|
||||||
void PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar);
|
void PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar);
|
||||||
void PopProjectionMatrix();
|
void PopProjectionMatrix();
|
||||||
|
|
||||||
@ -121,6 +124,7 @@ namespace ZL {
|
|||||||
void DisableVertexAttribArray(const std::string& attribName);
|
void DisableVertexAttribArray(const std::string& attribName);
|
||||||
|
|
||||||
|
|
||||||
|
void RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value);
|
||||||
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);
|
||||||
|
|||||||
@ -39,6 +39,7 @@ namespace ZL {
|
|||||||
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled);
|
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled);
|
||||||
glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog);
|
glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog);
|
||||||
|
|
||||||
|
|
||||||
if (!vertexShaderCompiled)
|
if (!vertexShaderCompiled)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to compile vertex shader code!");
|
throw std::runtime_error("Failed to compile vertex shader code!");
|
||||||
|
|||||||
275
StoneObject.cpp
Normal file
275
StoneObject.cpp
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
#include "StoneObject.h"
|
||||||
|
|
||||||
|
#include "Utils.h"
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <random>
|
||||||
|
#include <cmath>
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include "PlanetData.h"
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
// Âñïîìîãàòåëüíàÿ ôóíêöèÿ äëÿ ïîëó÷åíèÿ ñëó÷àéíîãî ÷èñëà â äèàïàçîíå [min, max]
|
||||||
|
float getRandomFloat(std::mt19937& gen, float min, float max) {
|
||||||
|
std::uniform_real_distribution<> distrib(min, max);
|
||||||
|
return static_cast<float>(distrib(gen));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Âñïîìîãàòåëüíàÿ ôóíêöèÿ äëÿ ãåíåðàöèè ñëó÷àéíîé òî÷êè íà òðåóãîëüíèêå
|
||||||
|
// Èñïîëüçóåò áàðèöåíòðè÷åñêèå êîîðäèíàòû
|
||||||
|
Vector3f GetRandomPointOnTriangle(const Triangle& t, std::mt19937& engine) {
|
||||||
|
std::uniform_real_distribution<> distrib(0.0f, 1.0f);
|
||||||
|
|
||||||
|
float r1 = getRandomFloat(engine, 0.0f, 1.0f);
|
||||||
|
float r2 = getRandomFloat(engine, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
// Ïðåîáðàçîâàíèå r1, r2 äëÿ ïîëó÷åíèÿ ðàâíîìåðíîãî ðàñïðåäåëåíèÿ
|
||||||
|
float a = 1.0f - std::sqrt(r1);
|
||||||
|
float b = std::sqrt(r1) * r2;
|
||||||
|
float c = 1.0f - a - b; // c = sqrt(r1) * (1 - r2)
|
||||||
|
|
||||||
|
// Áàðèöåíòðè÷åñêèå êîîðäèíàòû
|
||||||
|
// P = a*p1 + b*p2 + c*p3
|
||||||
|
Vector3f p1_term = t.data[0] * a;
|
||||||
|
Vector3f p2_term = t.data[1] * b;
|
||||||
|
Vector3f p3_term = t.data[2] * c;
|
||||||
|
|
||||||
|
return p1_term + p2_term + p3_term;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Èêîñàýäð (íà îñíîâå çîëîòîãî ñå÷åíèÿ phi)
|
||||||
|
// Êîîðäèíàòû ìîãóò áûòü âû÷èñëåíû çàðàíåå äëÿ êîíñòàíòíîãî èêîñàýäðà.
|
||||||
|
// Çäåñü òîëüêî îáúÿâëåíèå, ÷òîáû ïîêàçàòü èäåþ.
|
||||||
|
|
||||||
|
VertexDataStruct CreateBaseConvexPolyhedron(uint64_t seed) {
|
||||||
|
|
||||||
|
// --- ÊÎÍÑÒÀÍÒÛ ÏÀÐÀÌÅÒÐÎÂ (êàê âû ïðîñèëè) ---
|
||||||
|
//const float BASE_SCALE = 15.0f; // Îáùèé ðàçìåð êàìíÿ
|
||||||
|
const float BASE_SCALE = 5000.0f; // Îáùèé ðàçìåð êàìíÿ
|
||||||
|
const float MIN_AXIS_SCALE = 1.0f; // Ìèíèìàëüíîå ðàñòÿæåíèå/ñæàòèå ïî îñè
|
||||||
|
const float MAX_AXIS_SCALE = 1.0f; // Ìàêñèìàëüíîå ðàñòÿæåíèå/ñæàòèå ïî îñè
|
||||||
|
const float MIN_PERTURBATION = 0.0f; // Ìèíèìàëüíîå ðàäèàëüíîå âîçìóùåíèå âåðøèíû
|
||||||
|
const float MAX_PERTURBATION = 0.0f; // Ìàêñèìàëüíîå ðàäèàëüíîå âîçìóùåíèå âåðøèíû
|
||||||
|
/*const float MIN_AXIS_SCALE = 0.5f; // Ìèíèìàëüíîå ðàñòÿæåíèå/ñæàòèå ïî îñè
|
||||||
|
const float MAX_AXIS_SCALE = 1.5f; // Ìàêñèìàëüíîå ðàñòÿæåíèå/ñæàòèå ïî îñè
|
||||||
|
const float MIN_PERTURBATION = 0.05f; // Ìèíèìàëüíîå ðàäèàëüíîå âîçìóùåíèå âåðøèíû
|
||||||
|
const float MAX_PERTURBATION = 0.25f; // Ìàêñèìàëüíîå ðàäèàëüíîå âîçìóùåíèå âåðøèíû
|
||||||
|
*/
|
||||||
|
// const size_t SUBDIVISION_LEVEL = 1; // Óðîâåíü ïîäðàçäåëåíèÿ (äëÿ áîëåå êðóãëîãî êàìíÿ, ïîêà îïóñòèì)
|
||||||
|
|
||||||
|
std::mt19937 engine(static_cast<unsigned int>(seed));
|
||||||
|
|
||||||
|
// Çîëîòîå ñå÷åíèå
|
||||||
|
const float t = (1.0f + std::sqrt(5.0f)) / 2.0f;
|
||||||
|
|
||||||
|
// 12 âåðøèí èêîñàýäðà
|
||||||
|
std::vector<Vector3f> initialVertices = {
|
||||||
|
{ -1, t, 0 }, { 1, t, 0 }, { -1, -t, 0 }, { 1, -t, 0 },
|
||||||
|
{ 0, -1, t }, { 0, 1, t }, { 0, -1, -t }, { 0, 1, -t },
|
||||||
|
{ t, 0, -1 }, { t, 0, 1 }, { -t, 0, -1 }, { -t, 0, 1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 20 òðåóãîëüíûõ ãðàíåé (èíäåêñû âåðøèí)
|
||||||
|
std::vector<std::array<int, 3>> faces = {
|
||||||
|
// 5 òðåóãîëüíèêîâ âîêðóã âåðøèíû 0
|
||||||
|
{0, 11, 5}, {0, 5, 1}, {0, 1, 7}, {0, 7, 10}, {0, 10, 11},
|
||||||
|
// 5 ñìåæíûõ ïîëîñ
|
||||||
|
{1, 5, 9}, {5, 11, 4}, {11, 10, 2}, {10, 7, 6}, {7, 1, 8},
|
||||||
|
// 5 òðåóãîëüíèêîâ âîêðóã âåðøèíû 3
|
||||||
|
{3, 9, 4}, {3, 4, 2}, {3, 2, 6}, {3, 6, 8}, {3, 8, 9},
|
||||||
|
// 5 ñìåæíûõ ïîëîñ
|
||||||
|
{4, 9, 5}, {2, 4, 11}, {6, 2, 10}, {8, 6, 7}, {9, 8, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1. Íîðìàëèçàöèÿ è Âîçìóùåíèå (Perturbation)
|
||||||
|
for (Vector3f& v : initialVertices) {
|
||||||
|
v = v.normalized() * BASE_SCALE; // Íîðìàëèçàöèÿ ê ñôåðå ðàäèóñà BASE_SCALE
|
||||||
|
|
||||||
|
// Ðàäèàëüíîå âîçìóùåíèå:
|
||||||
|
float perturbation = getRandomFloat(engine, MIN_PERTURBATION, MAX_PERTURBATION);
|
||||||
|
v = v * (1.0f + perturbation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Òðàíñôîðìàöèÿ (Ìàñøòàáèðîâàíèå è Ïîâîðîò)
|
||||||
|
|
||||||
|
// Ñëó÷àéíûå ìàñøòàáû ïî îñÿì
|
||||||
|
Vector3f scaleFactors = {
|
||||||
|
getRandomFloat(engine, MIN_AXIS_SCALE, MAX_AXIS_SCALE),
|
||||||
|
getRandomFloat(engine, MIN_AXIS_SCALE, MAX_AXIS_SCALE),
|
||||||
|
getRandomFloat(engine, MIN_AXIS_SCALE, MAX_AXIS_SCALE)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ïðèìåíÿåì ìàñøòàáèðîâàíèå
|
||||||
|
for (Vector3f& v : initialVertices) {
|
||||||
|
v.v[0] *= scaleFactors.v[0];
|
||||||
|
v.v[1] *= scaleFactors.v[1];
|
||||||
|
v.v[2] *= scaleFactors.v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ñëó÷àéíûé ïîâîðîò (íàïðèìåð, âîêðóã òðåõ îñåé)
|
||||||
|
Vector4f qx = QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
|
Vector4f qy = QuatFromRotateAroundY(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
|
Vector4f qz = QuatFromRotateAroundZ(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
|
Vector4f qFinal = slerp(qx, qy, 0.5f); // Ïðîñòîé ïðèìåð êîìáèíèðîâàíèÿ
|
||||||
|
qFinal = slerp(qFinal, qz, 0.5f).normalized();
|
||||||
|
Matrix3f rotationMatrix = QuatToMatrix(qFinal);
|
||||||
|
|
||||||
|
for (Vector3f& v : initialVertices) {
|
||||||
|
v = MultMatrixVector(rotationMatrix, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Ñãëàæåííûå Íîðìàëè è Ôîðìèðîâàíèå Mesh
|
||||||
|
VertexDataStruct result;
|
||||||
|
// Êàðòà äëÿ íàêîïëåíèÿ íîðìàëåé ïî óíèêàëüíûì ïîçèöèÿì âåðøèí
|
||||||
|
// (Òðåáóåò îïðåäåëåííîãî îïåðàòîðà < äëÿ Vector3f â ZLMath.h, êîòîðûé ó âàñ åñòü)
|
||||||
|
std::map<Vector3f, Vector3f> smoothNormalsMap;
|
||||||
|
|
||||||
|
// Ïðåäâàðèòåëüíîå çàïîëíåíèå êàðòû íîðìàëÿìè
|
||||||
|
for (const auto& face : faces) {
|
||||||
|
Vector3f p1 = initialVertices[face[0]];
|
||||||
|
Vector3f p2 = initialVertices[face[1]];
|
||||||
|
Vector3f p3 = initialVertices[face[2]];
|
||||||
|
|
||||||
|
// Íîðìàëü ãðàíè: (p2 - p1) x (p3 - p1)
|
||||||
|
Vector3f faceNormal = (p2 - p1).cross(p3 - p1).normalized();
|
||||||
|
|
||||||
|
smoothNormalsMap[p1] = smoothNormalsMap[p1] + faceNormal;
|
||||||
|
smoothNormalsMap[p2] = smoothNormalsMap[p2] + faceNormal;
|
||||||
|
smoothNormalsMap[p3] = smoothNormalsMap[p3] + faceNormal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Íîðìàëèçàöèÿ íàêîïëåííûõ íîðìàëåé
|
||||||
|
for (auto& pair : smoothNormalsMap) {
|
||||||
|
pair.second = pair.second.normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 4. Ôèíàëüíîå çàïîëíåíèå VertexDataStruct è Òåêñòóðíûå Êîîðäèíàòû
|
||||||
|
for (const auto& face : faces) {
|
||||||
|
Vector3f p1 = initialVertices[face[0]];
|
||||||
|
Vector3f p2 = initialVertices[face[1]];
|
||||||
|
Vector3f p3 = initialVertices[face[2]];
|
||||||
|
|
||||||
|
// Ïîçèöèè
|
||||||
|
result.PositionData.push_back(p1);
|
||||||
|
result.PositionData.push_back(p2);
|
||||||
|
result.PositionData.push_back(p3);
|
||||||
|
|
||||||
|
// Ñãëàæåííûå Íîðìàëè (èç êàðòû)
|
||||||
|
result.NormalData.push_back(smoothNormalsMap[p1]);
|
||||||
|
result.NormalData.push_back(smoothNormalsMap[p2]);
|
||||||
|
result.NormalData.push_back(smoothNormalsMap[p3]);
|
||||||
|
|
||||||
|
// Òåêñòóðíûå Êîîðäèíàòû (Ïëàíàðíàÿ ïðîåêöèÿ íà ïëîñêîñòü ãðàíè)
|
||||||
|
// p1 -> (0, 0), p2 -> (L_12, 0), p3 -> (L_13 * cos(angle), L_13 * sin(angle))
|
||||||
|
// Ãäå L_xy - äëèíà âåêòîðà, angle - óãîë ìåæäó p2-p1 è p3-p1
|
||||||
|
|
||||||
|
Vector3f uAxis = (p2 - p1).normalized();
|
||||||
|
Vector3f vRaw = p3 - p1;
|
||||||
|
|
||||||
|
// Ïðîåêöèÿ vRaw íà uAxis
|
||||||
|
float uProjLen = vRaw.dot(uAxis);
|
||||||
|
|
||||||
|
// Âåêòîð V ïåðïåíäèêóëÿðíûé U: vRaw - uProj
|
||||||
|
Vector3f vAxisRaw = vRaw - (uAxis * uProjLen);
|
||||||
|
|
||||||
|
// Äëèíà îñè V
|
||||||
|
float vLen = vAxisRaw.length();
|
||||||
|
|
||||||
|
// Íîðìàëèçîâàííàÿ îñü V
|
||||||
|
Vector3f vAxis = vAxisRaw.normalized();
|
||||||
|
|
||||||
|
// Êîîðäèíàòû (u, v) äëÿ p1, p2, p3 îòíîñèòåëüíî p1
|
||||||
|
Vector2f uv1 = { 0.0f, 0.0f };
|
||||||
|
Vector2f uv2 = { (p2 - p1).length(), 0.0f }; // p2-p1 âäîëü îñè U
|
||||||
|
Vector2f uv3 = { uProjLen, vLen }; // p3-p1: u-êîìïîíåíòà = uProjLen, v-êîìïîíåíòà = vLen
|
||||||
|
|
||||||
|
// Íàõîäèì ìàêñèìàëüíûé ðàçìåð, ÷òîáû ìàñøòàáèðîâàòü â [0, 1]
|
||||||
|
float maxUV = max(uv2.v[0], max(uv3.v[0], uv3.v[1]));
|
||||||
|
|
||||||
|
if (maxUV > 0.000001f) {
|
||||||
|
// Ìàñøòàáèðóåì:
|
||||||
|
result.TexCoordData.push_back(uv1);
|
||||||
|
result.TexCoordData.push_back(uv2 * (1.f / maxUV));
|
||||||
|
result.TexCoordData.push_back(uv3 * (1.f / maxUV));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Ïðåäîòâðàùåíèå äåëåíèÿ íà íîëü äëÿ âûðîæäåííûõ ãðàíåé
|
||||||
|
result.TexCoordData.push_back({ 0.0f, 0.0f });
|
||||||
|
result.TexCoordData.push_back({ 0.0f, 0.0f });
|
||||||
|
result.TexCoordData.push_back({ 0.0f, 0.0f });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoneGroup CreateStoneGroupData(uint64_t globalSeed, const LodLevel& planetLodLevel) {
|
||||||
|
StoneGroup group;
|
||||||
|
const int STONES_PER_TRIANGLE = 1;
|
||||||
|
|
||||||
|
// Ðåçåðâèðóåì ìåñòî ïîä âñå òðåóãîëüíèêè òåêóùåãî LOD
|
||||||
|
group.allInstances.resize(planetLodLevel.triangles.size());
|
||||||
|
|
||||||
|
for (size_t tIdx = 0; tIdx < planetLodLevel.triangles.size(); ++tIdx) {
|
||||||
|
const Triangle& tri = planetLodLevel.triangles[tIdx];
|
||||||
|
std::mt19937 engine(static_cast<unsigned int>(globalSeed));
|
||||||
|
|
||||||
|
for (int i = 0; i < STONES_PER_TRIANGLE; ++i) {
|
||||||
|
StoneInstance instance;
|
||||||
|
instance.seed = globalSeed;// + tIdx * 1000 + i; // Óíèêàëüíûé ñèä äëÿ êàæäîãî êàìíÿ
|
||||||
|
|
||||||
|
//instance.position = GetRandomPointOnTriangle(tri, engine);
|
||||||
|
|
||||||
|
instance.position = Vector3f(5000.0f, 5000.0f, 5000.0f);
|
||||||
|
// Ãåíåðèðóåì ñëó÷àéíûå ïàðàìåòðû îäèí ðàç
|
||||||
|
instance.scale = {
|
||||||
|
getRandomFloat(engine, 0.5f, 1.5f),
|
||||||
|
getRandomFloat(engine, 0.5f, 1.5f),
|
||||||
|
getRandomFloat(engine, 0.5f, 1.5f)
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector4f qx = QuatFromRotateAroundX(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
|
Vector4f qy = QuatFromRotateAroundY(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
|
Vector4f qz = QuatFromRotateAroundZ(getRandomFloat(engine, 0.0f, 360.0f));
|
||||||
|
instance.rotation = slerp(slerp(qx, qy, 0.5f), qz, 0.5f).normalized();
|
||||||
|
|
||||||
|
group.allInstances[tIdx].push_back(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StoneGroup::inflate(const std::vector<int>& triangleIndices) {
|
||||||
|
// 1. Î÷èùàåì òåêóùèé ìåø ïåðåä çàïîëíåíèåì
|
||||||
|
mesh.PositionData.clear();
|
||||||
|
mesh.NormalData.clear();
|
||||||
|
mesh.TexCoordData.clear();
|
||||||
|
|
||||||
|
static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337);
|
||||||
|
|
||||||
|
// 2. Íàïîëíÿåì ìåø òîëüêî äëÿ âèäèìûõ òðåóãîëüíèêîâ
|
||||||
|
for (int tIdx : triangleIndices) {
|
||||||
|
if (tIdx >= allInstances.size()) continue;
|
||||||
|
|
||||||
|
for (const auto& inst : allInstances[tIdx]) {
|
||||||
|
Matrix3f rotMat = QuatToMatrix(inst.rotation);
|
||||||
|
|
||||||
|
for (size_t j = 0; j < baseStone.PositionData.size(); ++j) {
|
||||||
|
Vector3f p = baseStone.PositionData[j];
|
||||||
|
Vector3f n = baseStone.NormalData[j];
|
||||||
|
|
||||||
|
// Ìàñøòàá -> Ïîâîðîò -> Ñìåùåíèå
|
||||||
|
p.v[0] *= inst.scale.v[0];
|
||||||
|
p.v[1] *= inst.scale.v[1];
|
||||||
|
p.v[2] *= inst.scale.v[2];
|
||||||
|
|
||||||
|
mesh.PositionData.push_back(MultMatrixVector(rotMat, p) + inst.position);
|
||||||
|
mesh.NormalData.push_back(MultMatrixVector(rotMat, n));
|
||||||
|
mesh.TexCoordData.push_back(baseStone.TexCoordData[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace ZL
|
||||||
30
StoneObject.h
Normal file
30
StoneObject.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ZLMath.h"
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include "PlanetData.h"
|
||||||
|
|
||||||
|
namespace ZL {
|
||||||
|
|
||||||
|
struct StoneInstance {
|
||||||
|
uint64_t seed;
|
||||||
|
Vector3f position;
|
||||||
|
Vector3f scale;
|
||||||
|
Vector4f rotation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StoneGroup {
|
||||||
|
// mesh.PositionData è ïðî÷èå áóäóò çàïîëíÿòüñÿ â inflate()
|
||||||
|
VertexDataStruct mesh;
|
||||||
|
|
||||||
|
// Âíåøíèé âåêòîð — èíäåêñ òðåóãîëüíèêà ïëàíåòû,
|
||||||
|
// âíóòðåííèé — ñïèñîê êàìíåé íà ýòîì òðåóãîëüíèêå
|
||||||
|
std::vector<std::vector<StoneInstance>> allInstances;
|
||||||
|
|
||||||
|
// Î÷èùàåò ñòàðóþ ãåîìåòðèþ è ãåíåðèðóåò íîâóþ äëÿ óêàçàííûõ èíäåêñîâ
|
||||||
|
void inflate(const std::vector<int>& triangleIndices);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Òåïåðü âîçâðàùàåò çàãîòîâêó ñî âñåìè ïàðàìåòðàìè, íî áåç òÿæåëîãî ìåøà
|
||||||
|
StoneGroup CreateStoneGroupData(uint64_t globalSeed, const LodLevel& planetLodLevel);
|
||||||
|
|
||||||
|
} // namespace ZL
|
||||||
32
ZLMath.cpp
32
ZLMath.cpp
@ -189,6 +189,38 @@ namespace ZL {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Matrix4f MakeOrthoMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar)
|
||||||
|
{
|
||||||
|
float width = xmax - xmin;
|
||||||
|
float height = ymax - ymin;
|
||||||
|
float depthRange = zFar - zNear;
|
||||||
|
|
||||||
|
if (width <= 0 || height <= 0 || depthRange <= 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid dimensions for orthogonal matrix");
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix4f r;
|
||||||
|
|
||||||
|
// Масштабирование
|
||||||
|
r.m[0] = 2.f / width;
|
||||||
|
r.m[5] = 2.f / height;
|
||||||
|
r.m[10] = -1.f / depthRange;
|
||||||
|
|
||||||
|
// Обнуление неиспользуемых компонентов
|
||||||
|
r.m[1] = r.m[2] = r.m[3] = 0;
|
||||||
|
r.m[4] = r.m[6] = r.m[7] = 0;
|
||||||
|
r.m[8] = r.m[9] = r.m[11] = 0;
|
||||||
|
|
||||||
|
// Трансляция (смещение)
|
||||||
|
r.m[12] = -(xmax + xmin) / width;
|
||||||
|
r.m[13] = -(ymax + ymin) / height;
|
||||||
|
r.m[14] = zNear / depthRange;
|
||||||
|
r.m[15] = 1.f;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar)
|
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar)
|
||||||
{
|
{
|
||||||
float tanHalfFovy = tan(fovY / 2.f);
|
float tanHalfFovy = tan(fovY / 2.f);
|
||||||
|
|||||||
6
ZLMath.h
6
ZLMath.h
@ -79,11 +79,6 @@ namespace ZL {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Îïåðàòîð âû÷èòàíèÿ
|
|
||||||
/*Vector3f operator-(const Vector3f& other) const {
|
|
||||||
return Vector3f(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
bool operator<(const Vector3f& other) const {
|
bool operator<(const Vector3f& other) const {
|
||||||
if (v[0] != other.v[0]) return v[0] < other.v[0];
|
if (v[0] != other.v[0]) return v[0] < other.v[0];
|
||||||
if (v[1] != other.v[1]) return v[1] < other.v[1];
|
if (v[1] != other.v[1]) return v[1] < other.v[1];
|
||||||
@ -153,6 +148,7 @@ namespace ZL {
|
|||||||
Matrix4f operator*(const Matrix4f& m1, const Matrix4f& m2);
|
Matrix4f operator*(const Matrix4f& m1, const Matrix4f& m2);
|
||||||
|
|
||||||
Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar);
|
Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar);
|
||||||
|
Matrix4f MakeOrthoMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar);
|
||||||
|
|
||||||
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar);
|
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar);
|
||||||
|
|
||||||
|
|||||||
BIN
resources/DefaultMaterial_BaseColor.png
(Stored with Git LFS)
BIN
resources/DefaultMaterial_BaseColor.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/DefaultMaterial_BaseColor_shine.png
(Stored with Git LFS)
Normal file
BIN
resources/DefaultMaterial_BaseColor_shine.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/rockx.png
(Stored with Git LFS)
Normal file
BIN
resources/rockx.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/sand2.png
(Stored with Git LFS)
Normal file
BIN
resources/sand2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/sandx.png
(Stored with Git LFS)
Normal file
BIN
resources/sandx.png
(Stored with Git LFS)
Normal file
Binary file not shown.
11574
resources/spaceship006.txt
Normal file
11574
resources/spaceship006.txt
Normal file
File diff suppressed because it is too large
Load Diff
34
shaders/defaultColor_bake.vertex
Normal file
34
shaders/defaultColor_bake.vertex
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Vertex Shader (Bake Stage)
|
||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec2 vTexCoord;
|
||||||
|
attribute vec3 vNormal; // Нормаль самого камня (для освещения при запекании)
|
||||||
|
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying float vHeight;
|
||||||
|
varying vec3 vWorldNormal;
|
||||||
|
|
||||||
|
// Данные о плоскости треугольника планеты
|
||||||
|
uniform vec3 uPlanePoint; // Любая вершина треугольника (например, tri.data[0])
|
||||||
|
uniform vec3 uPlaneNormal; // Нормаль треугольника планеты (ось Z из GetRotationForTriangle)
|
||||||
|
uniform float uMaxHeight; // Максимальный размер камня (BASE_SCALE)
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// 1. Вычисляем вектор от плоскости до текущей вершины камня
|
||||||
|
vec3 vecToVertex = vPosition - uPlanePoint;
|
||||||
|
|
||||||
|
// 2. Проецируем этот вектор на нормаль плоскости (скалярное произведение)
|
||||||
|
// Это и есть кратчайшее расстояние от точки до плоскости
|
||||||
|
float distance = dot(vecToVertex, uPlaneNormal);
|
||||||
|
|
||||||
|
// 3. Нормализуем высоту для записи в текстуру (0.0 - уровень земли, 1.0 - пик)
|
||||||
|
// Clamp гарантирует, что значения не выйдут за пределы, если камень "утоплен"
|
||||||
|
vHeight = clamp(distance / uMaxHeight, 0.0, 1.0);
|
||||||
|
|
||||||
|
TexCoord = vTexCoord;
|
||||||
|
vWorldNormal = vNormal;
|
||||||
|
|
||||||
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition, 1.0);
|
||||||
|
}
|
||||||
21
shaders/defaultColor_bake_desktop.fragment
Normal file
21
shaders/defaultColor_bake_desktop.fragment
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Fragment Shader (Bake Stage)
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying float vHeight;
|
||||||
|
varying vec3 vWorldNormal;
|
||||||
|
|
||||||
|
uniform sampler2D Texture; // Текстура камня (rock.png)
|
||||||
|
uniform vec3 uLightDir; // Направление света для базового затенения камней при запекании
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 stoneColor = texture2D(Texture, TexCoord);
|
||||||
|
|
||||||
|
// Простое Lambert-освещение, чтобы камни не были "плоскими" в текстуре
|
||||||
|
//float diff = max(dot(normalize(vWorldNormal), normalize(uLightDir)), 0.3);
|
||||||
|
float diff = 1.0;
|
||||||
|
|
||||||
|
// RGB - цвет камня с учетом света, A - нормализованная высота
|
||||||
|
//gl_FragColor = vec4(stoneColor.rgb * diff, vHeight);
|
||||||
|
gl_FragColor = vec4(vHeight, vHeight, vHeight, vHeight);
|
||||||
|
//gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
|
||||||
|
}
|
||||||
@ -90,8 +90,8 @@ void main()
|
|||||||
// 4. Смешивание цвета с туманом
|
// 4. Смешивание цвета с туманом
|
||||||
|
|
||||||
//vec3 mountainColor = vec3((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.5,0.0);
|
//vec3 mountainColor = vec3((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.5,0.0);
|
||||||
gl_FragColor = mix(vec4(uColor* finalColor.rgb, 1.0), FOG_COLOR, fogFactor);
|
//gl_FragColor = mix(vec4(uColor* finalColor.rgb, 1.0), FOG_COLOR, fogFactor);
|
||||||
//gl_FragColor = vec4((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.0,0.0, 1.0);
|
//gl_FragColor = vec4((length(pos+vec3(0.0,0.0,45000.0))-20000.0)/100.0, 0.0,0.0, 1.0);
|
||||||
//gl_FragColor = vec4(fogFactor, 0.5,0.5, 1.0);
|
//gl_FragColor = vec4(fogFactor, 0.5,0.5, 1.0);
|
||||||
//gl_FragColor = vec4(uColor*textureColor.rgb, 1.0);
|
gl_FragColor = vec4(textureColor.rgb, 1.0);
|
||||||
}
|
}
|
||||||
@ -30,7 +30,8 @@ void main()
|
|||||||
{
|
{
|
||||||
// ... (1. Получаем цвет и 2. Расчет освещения)
|
// ... (1. Получаем цвет и 2. Расчет освещения)
|
||||||
vec4 textureColor = texture2D(Texture, TexCoord);
|
vec4 textureColor = texture2D(Texture, TexCoord);
|
||||||
vec3 finalColor = textureColor.rgb * color;
|
//vec3 finalColor = textureColor.rgb * color;
|
||||||
|
vec3 finalColor = textureColor.rgb;
|
||||||
|
|
||||||
float diffuse = max(0.0, dot(normal, uLightDirection));
|
float diffuse = max(0.0, dot(normal, uLightDirection));
|
||||||
float ambient = 0.2;
|
float ambient = 0.2;
|
||||||
|
|||||||
26
shaders/defaultColor_fog_stones.vertex
Normal file
26
shaders/defaultColor_fog_stones.vertex
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
attribute vec3 vPosition;
|
||||||
|
attribute vec2 vTexCoord;
|
||||||
|
attribute vec3 vNormal;
|
||||||
|
attribute vec3 vTangent; // Новые атрибуты
|
||||||
|
attribute vec3 vBinormal;
|
||||||
|
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying vec3 vViewDirTangent;
|
||||||
|
|
||||||
|
uniform mat4 ProjectionModelViewMatrix;
|
||||||
|
uniform vec3 uViewPos;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = ProjectionModelViewMatrix * vec4(vPosition, 1.0);
|
||||||
|
TexCoord = vTexCoord;
|
||||||
|
|
||||||
|
vec3 viewDirWorld = normalize(uViewPos - vPosition);
|
||||||
|
|
||||||
|
// Строим матрицу перехода из атрибутов
|
||||||
|
// Так как базис ортонормирован, TBN^-1 == TBN_transpose
|
||||||
|
vViewDirTangent = vec3(
|
||||||
|
dot(viewDirWorld, vTangent),
|
||||||
|
dot(viewDirWorld, vBinormal),
|
||||||
|
dot(viewDirWorld, vNormal)
|
||||||
|
);
|
||||||
|
}
|
||||||
67
shaders/defaultColor_fog_stones_desktop.fragment
Normal file
67
shaders/defaultColor_fog_stones_desktop.fragment
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
varying vec2 TexCoord;
|
||||||
|
varying vec3 vViewDirTangent;
|
||||||
|
|
||||||
|
uniform sampler2D Texture; // Нам нужен только Alpha канал (высота)
|
||||||
|
uniform float uHeightScale;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 viewDir = normalize(vViewDirTangent);
|
||||||
|
float height = texture2D(Texture, TexCoord).a;
|
||||||
|
|
||||||
|
// Рассчитываем вектор смещения P
|
||||||
|
//vec2 p = viewDir.xy * (height * uHeightScale) / viewDir.z;
|
||||||
|
//vec2 p = vec2(viewDir.y, -viewDir.x) * (height * uHeightScale);
|
||||||
|
//vec2 p = viewDir.xy * (height * uHeightScale);
|
||||||
|
vec2 p = vec2(viewDir.x, -viewDir.y) * (height * uHeightScale);
|
||||||
|
vec2 finalTexCoord = TexCoord + p;
|
||||||
|
|
||||||
|
// 1. Визуализация сетки по смещенным координатам
|
||||||
|
// Если сетка кривая или ломается на стыках — значит T, B, N векторы не сошлись
|
||||||
|
vec2 grid = fract(finalTexCoord * 20.0); // 20 ячеек сетки
|
||||||
|
float line = (step(0.9, grid.x) + step(0.9, grid.y));
|
||||||
|
|
||||||
|
// 2. Визуализация вектора смещения через цвет
|
||||||
|
// Красный = смещение по U, Зеленый = смещение по V
|
||||||
|
vec3 offsetColor = vec3(p * 10.0 + 0.5, 0.0); // Умножаем на 10 для видимости
|
||||||
|
|
||||||
|
vec3 finalColor = mix(offsetColor, vec3(1.0), line); // Накладываем сетку поверх цвета
|
||||||
|
|
||||||
|
// 3. Подмешиваем карту высот, чтобы видеть "объемы"
|
||||||
|
gl_FragColor = vec4(finalColor * height, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying vec3 vViewDirTangent;
|
||||||
|
|
||||||
|
uniform sampler2D Texture;
|
||||||
|
uniform float uHeightScale;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 viewDir = normalize(vViewDirTangent);
|
||||||
|
|
||||||
|
// Получаем высоту из альфа-канала запеченной текстуры
|
||||||
|
float height = texture2D(Texture, TexCoord).a;
|
||||||
|
|
||||||
|
// Смещение. Знак минус используется, если мы хотим "вдавить" камни
|
||||||
|
// Деление на viewDir.z помогает избежать сильных искажений под углом
|
||||||
|
vec2 p = viewDir.xy * (height * uHeightScale) / viewDir.z;
|
||||||
|
vec2 finalTexCoord = TexCoord + p;
|
||||||
|
|
||||||
|
gl_FragColor = texture2D(Texture, finalTexCoord);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
varying vec2 TexCoord;
|
||||||
|
varying vec3 vViewDirTangent; // Тот самый вектор из VS
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// 1. Нормализуем входящий вектор
|
||||||
|
vec3 v = normalize(vViewDirTangent);
|
||||||
|
|
||||||
|
// 2. Преобразуем компоненты из [-1, 1] в [0, 1] для визуализации
|
||||||
|
// X -> Red, Y -> Green, Z -> Blue
|
||||||
|
vec3 debugColor = v * 0.5 + 0.5;
|
||||||
|
|
||||||
|
gl_FragColor = vec4(debugColor, 1.0);
|
||||||
|
}*/
|
||||||
Loading…
Reference in New Issue
Block a user