This commit is contained in:
Vladislav Khorev 2026-05-01 20:26:50 +03:00
parent 519d780b3c
commit e04fcbb9bd
11 changed files with 91 additions and 1463 deletions

View File

@ -32,8 +32,6 @@ add_executable(witcher001
../src/TextModel.h
../src/AudioPlayerAsync.cpp
../src/AudioPlayerAsync.h
../src/BoneAnimatedModel.cpp
../src/BoneAnimatedModel.h
../src/BoneAnimatedModelNew.cpp
../src/BoneAnimatedModelNew.h
../src/render/OpenGlExtensions.cpp
@ -42,8 +40,6 @@ add_executable(witcher001
../src/utils/Utils.h
../src/SparkEmitter.cpp
../src/SparkEmitter.h
../src/utils/Perlin.cpp
../src/utils/Perlin.h
../src/utils/TaskManager.cpp
../src/utils/TaskManager.h
../src/render/FrameBuffer.cpp

File diff suppressed because it is too large Load Diff

View File

@ -1,103 +0,0 @@
#pragma once
#include "render/Renderer.h"
#include <unordered_map>
namespace ZL
{
constexpr int MAX_BONE_COUNT = 6;
constexpr int MAX_GPU_BONES = 64;
struct Bone
{
Vector3f boneStartWorld;
float boneLength;
Matrix4f boneMatrixWorld;
int parent;
std::vector<int> children;
};
struct BoneWeight
{
int boneIndex = -1;
float weight = 0;
};
struct AnimationKeyFrame
{
int frame;
std::vector<Bone> bones;
};
struct Animation
{
std::vector<AnimationKeyFrame> keyFrames;
};
struct GpuBoneData {
std::vector<Vector4f> boneIndices0; // bone indices 0-3 per vertex (as float)
std::vector<Vector2f> boneIndices1; // bone indices 4-5 per vertex
std::vector<Vector4f> boneWeights0; // bone weights 0-3 per vertex
std::vector<Vector2f> boneWeights1; // bone weights 4-5 per vertex
bool prepared = false;
void PrepareGpuSkinningData(const std::vector<std::array<BoneWeight, MAX_BONE_COUNT>>& verticesBoneWeight);
};
struct BoneSystem
{
VertexDataStruct mesh;
VertexDataStruct startMesh;
std::vector<std::array<BoneWeight, MAX_BONE_COUNT>> verticesBoneWeight;
Matrix4f armatureMatrix;
std::vector<Bone> startBones;
std::vector<Bone> currentBones;
std::vector<std::string> boneNames;
std::vector<Animation> animations;
int startingFrame = 0;
void LoadFromFile(const std::string& fileName, const std::string& ZIPFileName = "");
void LoadFromBinaryFile(const std::string& fileName, const std::string& ZIPFileName = "");
void Interpolate(int frame);
int findBoneIndex(const std::string& name) const;
// GPU skinning: compute skinning matrices without modifying the mesh
//void ComputeSkinningMatrices(int frame, std::vector<Matrix4f>& outMatrices) const;
};
struct GpuSkinningShaderData {
GpuBoneData gpuBoneData;
// GPU skinning data (lazily initialized)
VertexRenderStruct bindPoseMutable;
std::shared_ptr<VBOHolder> boneIndices0VBO;
std::shared_ptr<VBOHolder> boneIndices1VBO;
std::shared_ptr<VBOHolder> boneWeights0VBO;
std::shared_ptr<VBOHolder> boneWeights1VBO;
bool gpuSkinningPrepared = false;
std::vector<Eigen::Matrix4f> skinningMatrices;
void prepareGpuSkinningVBOs(BoneSystem& model);
void RenderVBO(Renderer& renderer);
void ComputeSkinningMatrices(const std::vector<Bone>& startBones, const std::vector<AnimationKeyFrame>& keyFrames, int frame);
};
struct BoneAnimationData {
BoneSystem model;
float currentFrame = 0.f;
int lastFrame = -1;
int totalFrames = 1;
GpuSkinningShaderData gpuSkinningShaderData;
};
};

View File

@ -13,7 +13,21 @@ namespace ZL
using std::max;
#endif
extern int getIndexByValue(const std::string& name, const std::vector<std::string>& words);
int getIndexByValue(const std::string& name, const std::vector<std::string>& words)
{
for (int i = 0; i < words.size(); i++)
{
if (words[i] == name)
{
return i;
}
}
std::cout << "Bone name not found: " << name << std::endl;
throw std::runtime_error("Bone name not found: " + name);
return -1;
}
static std::string trimRight(const std::string& s)
{
@ -23,6 +37,42 @@ namespace ZL
return s.substr(0, end);
}
void GpuBoneData::PrepareGpuSkinningData(const std::vector<std::array<BoneWeight, MAX_BONE_COUNT>>& verticesBoneWeight)
{
size_t vertexCount = verticesBoneWeight.size();
boneIndices0.resize(vertexCount);
boneIndices1.resize(vertexCount);
boneWeights0.resize(vertexCount);
boneWeights1.resize(vertexCount);
for (size_t i = 0; i < vertexCount; i++)
{
boneIndices0[i] = Vector4f(
static_cast<float>(max(0, verticesBoneWeight[i][0].boneIndex)),
static_cast<float>(max(0, verticesBoneWeight[i][1].boneIndex)),
static_cast<float>(max(0, verticesBoneWeight[i][2].boneIndex)),
static_cast<float>(max(0, verticesBoneWeight[i][3].boneIndex))
);
boneIndices1[i] = Vector2f(
static_cast<float>(max(0, verticesBoneWeight[i][4].boneIndex)),
static_cast<float>(max(0, verticesBoneWeight[i][5].boneIndex))
);
boneWeights0[i] = Vector4f(
verticesBoneWeight[i][0].weight,
verticesBoneWeight[i][1].weight,
verticesBoneWeight[i][2].weight,
verticesBoneWeight[i][3].weight
);
boneWeights1[i] = Vector2f(
verticesBoneWeight[i][4].weight,
verticesBoneWeight[i][5].weight
);
}
prepared = true;
}
void BoneSystemNew::LoadFromFile(const std::string& fileName, const std::string& ZIPFileName)
{
std::ifstream filestream;

View File

@ -1,9 +1,48 @@
#pragma once
#include "BoneAnimatedModel.h"
#include "render/Renderer.h"
#include <unordered_map>
namespace ZL
{
constexpr int MAX_BONE_COUNT = 6;
constexpr int MAX_GPU_BONES = 64;
struct Bone
{
Eigen::Vector3f boneStartWorld;
float boneLength;
Eigen::Matrix4f boneMatrixWorld;
int parent;
std::vector<int> children;
};
struct BoneWeight
{
int boneIndex = -1;
float weight = 0;
};
struct AnimationKeyFrame
{
int frame;
std::vector<Bone> bones;
};
struct Animation
{
std::vector<AnimationKeyFrame> keyFrames;
};
struct GpuBoneData {
std::vector<Vector4f> boneIndices0; // bone indices 0-3 per vertex (as float)
std::vector<Vector2f> boneIndices1; // bone indices 4-5 per vertex
std::vector<Vector4f> boneWeights0; // bone weights 0-3 per vertex
std::vector<Vector2f> boneWeights1; // bone weights 4-5 per vertex
bool prepared = false;
void PrepareGpuSkinningData(const std::vector<std::array<BoneWeight, MAX_BONE_COUNT>>& verticesBoneWeight);
};
struct MeshBoneData
{
VertexDataStruct mesh;

View File

@ -1,6 +1,5 @@
#include "Game.h"
#include "AnimatedModel.h"
#include "BoneAnimatedModel.h"
#include "utils/Utils.h"
#include "render/OpenGlExtensions.h"
#include <iostream>

View File

@ -1,6 +1,5 @@
#pragma once
#include "Character.h"
#include "BoneAnimatedModel.h"
#include "render/Renderer.h"
#include "Environment.h"
#include "render/TextureManager.h"

View File

@ -10,219 +10,6 @@
namespace ZL
{
VertexDataStruct LoadFromTextFile(const std::string& fileName, const std::string& ZIPFileName)
{
VertexDataStruct result;
std::ifstream filestream;
std::istringstream zipStream;
if (!ZIPFileName.empty())
{
std::vector<char> fileData = readFileFromZIP(fileName, ZIPFileName);
std::string fileContents(fileData.begin(), fileData.end());
zipStream.str(fileContents);
}
else
{
filestream.open(fileName);
}
// Создаем ссылку f на нужный поток после этого код ниже остается без изменений
std::istream& f = (!ZIPFileName.empty()) ? static_cast<std::istream&>(zipStream) : static_cast<std::istream&>(filestream);
//Skip first 5 lines
std::string tempLine;
std::getline(f, tempLine);
static const std::regex pattern_count(R"(\d+)");
static const std::regex pattern_float(R"([-]?\d+\.\d+)");
static const std::regex pattern_int(R"([-]?\d+)");
std::smatch match;
int numberVertices;
if (std::regex_search(tempLine, match, pattern_count)) {
std::string number_str = match.str();
numberVertices = std::stoi(number_str);
}
else {
std::cout << "No number found in the input string: " << tempLine << std::endl;
throw std::runtime_error("No number found in the input string.");
}
std::vector<Vector3f> vertices;
vertices.resize(numberVertices);
for (int i = 0; i < numberVertices; i++)
{
std::getline(f, tempLine);
std::vector<float> floatValues;
auto b = tempLine.cbegin();
auto e = tempLine.cend();
while (std::regex_search(b, e, match, pattern_float)) {
floatValues.push_back(std::stof(match.str()));
b = match.suffix().first;
}
vertices[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
}
std::cout << "UV Coordinates" << std::endl;
std::getline(f, tempLine); //===UV Coordinates:
std::getline(f, tempLine); //triangle count
int numberTriangles;
if (std::regex_search(tempLine, match, pattern_count)) {
std::string number_str = match.str();
numberTriangles = std::stoi(number_str);
}
else {
std::cout << "-No number found in the input string: " << tempLine << std::endl;
throw std::runtime_error("-No number found in the input string.");
}
// Now process UVs
std::vector<std::array<Vector2f, 3>> uvCoords;
uvCoords.resize(numberTriangles);
for (int i = 0; i < numberTriangles; i++)
{
std::getline(f, tempLine); //Face 0
int uvCount;
std::getline(f, tempLine);
if (std::regex_search(tempLine, match, pattern_count)) {
std::string number_str = match.str();
uvCount = std::stoi(number_str);
}
else {
std::cout << "2 No number found in the input string: " << tempLine << std::endl;
throw std::runtime_error("2 No number found in the input string.");
}
if (uvCount != 3)
{
std::cout << "UV count is not 3 for triangle " << i << ": " << uvCount << std::endl;
throw std::runtime_error("more than 3 uvs");
}
std::vector<float> floatValues;
for (int j = 0; j < 3; j++)
{
std::getline(f, tempLine); //UV <Vector (-0.3661, -1.1665)>
auto b = tempLine.cbegin();
auto e = tempLine.cend();
floatValues.clear();
while (std::regex_search(b, e, match, pattern_float)) {
floatValues.push_back(std::stof(match.str()));
b = match.suffix().first;
}
if (floatValues.size() != 2)
{
std::cout << "UV count is not 2: " << j << " " << floatValues.size() << std::endl;
throw std::runtime_error("more than 2 uvs---");
}
uvCoords[i][j] = Vector2f{ floatValues[0],floatValues[1] };
}
}
//std::cout << "Normals go" << std::endl;
std::getline(f, tempLine); //===Normals:
std::vector<Vector3f> normals;
normals.resize(numberVertices);
for (int i = 0; i < numberVertices; i++)
{
std::getline(f, tempLine);
std::vector<float> floatValues;
auto b = tempLine.cbegin();
auto e = tempLine.cend();
while (std::regex_search(b, e, match, pattern_float)) {
floatValues.push_back(std::stof(match.str()));
b = match.suffix().first;
}
normals[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
}
//std::cout << "Triangles go:" << std::endl;
std::getline(f, tempLine); //===Triangles: 3974
std::vector<std::array<int, 3>> triangles;
triangles.resize(numberTriangles);
for (int i = 0; i < numberTriangles; i++)
{
std::getline(f, tempLine);
std::vector<int> intValues;
auto b = tempLine.cbegin();
auto e = tempLine.cend();
while (std::regex_search(b, e, match, pattern_int)) {
intValues.push_back(std::stoi(match.str()));
b = match.suffix().first;
}
triangles[i] = { intValues[0], intValues[1], intValues[2] };
}
std::cout << "Process vertices" << std::endl;
// Now let's process vertices
for (int i = 0; i < numberTriangles; i++)
{
result.PositionData.push_back(vertices[triangles[i][0]]);
result.PositionData.push_back(vertices[triangles[i][1]]);
result.PositionData.push_back(vertices[triangles[i][2]]);
result.TexCoordData.push_back(uvCoords[i][0]);
result.TexCoordData.push_back(uvCoords[i][1]);
result.TexCoordData.push_back(uvCoords[i][2]);
}
//Swap from Blender format to OpenGL format
for (int i = 0; i < result.PositionData.size(); i++)
{
Vector3f tempVec = result.PositionData[i];
result.PositionData[i](0) = tempVec(1);
result.PositionData[i](1) = tempVec(2);
result.PositionData[i](2) = tempVec(0);
}
return result;
}
VertexDataStruct LoadFromTextFile02(const std::string& fileName, const std::string& ZIPFileName)
{
VertexDataStruct result;

View File

@ -6,6 +6,5 @@
namespace ZL
{
VertexDataStruct LoadFromTextFile(const std::string& fileName, const std::string& ZIPFileName = "");
VertexDataStruct LoadFromTextFile02(const std::string& fileName, const std::string& ZIPFileName = "");
}

View File

@ -1,73 +0,0 @@
#include "Perlin.h"
#include <cmath>
#include <numeric>
#include <random>
#include <algorithm>
namespace ZL {
PerlinNoise::PerlinNoise() {
p.resize(256);
std::iota(p.begin(), p.end(), 0);
// Перемешиваем для случайности (можно задать seed)
std::default_random_engine engine(77777);
std::shuffle(p.begin(), p.end(), engine);
p.insert(p.end(), p.begin(), p.end()); // Дублируем для переполнения
}
PerlinNoise::PerlinNoise(uint64_t seed) {
p.resize(256);
std::iota(p.begin(), p.end(), 0);
// Перемешиваем для случайности (используем переданный seed)
std::default_random_engine engine(static_cast<unsigned int>(seed));
std::shuffle(p.begin(), p.end(), engine);
p.insert(p.end(), p.begin(), p.end()); // Дублируем для переполнения
}
float PerlinNoise::fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); }
float PerlinNoise::lerp(float t, float a, float b) { return a + t * (b - a); }
float PerlinNoise::grad(int hash, float x, float y, float z) {
int h = hash & 15;
float u = h < 8 ? x : y;
float v = h < 4 ? y : (h == 12 || h == 14 ? x : z);
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
float PerlinNoise::noise(float x, float y, float z) {
int X = (int)floor(x) & 255;
int Y = (int)floor(y) & 255;
int Z = (int)floor(z) & 255;
x -= floor(x);
y -= floor(y);
z -= floor(z);
float u = fade(x);
float v = fade(y);
float w = fade(z);
int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z;
int B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;
return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), grad(p[BA], x - 1, y, z)),
lerp(u, grad(p[AB], x, y - 1, z), grad(p[BB], x - 1, y - 1, z))),
lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), grad(p[BA + 1], x - 1, y, z - 1)),
lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1))));
}
float PerlinNoise::getSurfaceHeight(Eigen::Vector3f pos, float noiseCoeff) {
// Частота шума (чем больше, тем больше "холмов")
float frequency = 7.0f;
// Получаем значение шума (обычно от -1 до 1)
float noiseValue = noise(pos(0) * frequency, pos(1) * frequency, pos(2) * frequency);
// Масштабируем: хотим отклонение от 1.0 до 1.1 (примерно)
float height = 1.0f + (noiseValue * noiseCoeff);
return height;
}
} // namespace ZL

View File

@ -1,24 +0,0 @@
#pragma once
#include <vector>
#include <cstdint>
#include <Eigen/Dense>
namespace ZL {
class PerlinNoise {
std::vector<int> p;
public:
PerlinNoise();
PerlinNoise(uint64_t seed);
float fade(float t);
float lerp(float t, float a, float b);
float grad(int hash, float x, float y, float z);
float noise(float x, float y, float z);
float getSurfaceHeight(Eigen::Vector3f pos, float noiseCoeff);
};
} // namespace ZL