复原大唐3d项目测试版
这是一个可以完美复原大唐风土人情的VR项目!!!!!
这里只是最初的测试版本,需要下载多个库,以后会有更多方法
:
// TangDynastyVR_Complete.h
#pragma once
#include <openvr.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <vector>
#include <memory>
#include <string>
#include <map>
#include <random>
// 情感状态枚举
enum class EmotionalState {
NEUTRAL, JOYFUL, ANGRY, SAD, POETIC, NOSTALGIC, PROUD
};
// 对话消息结构
struct DialogueMessage {
std::string speakerName;
std::string content;
float displayTime;
glm::vec3 speakerPosition;
bool isHistoricalFigure;
};
// 基础场景对象
class SceneObject {
public:
virtual ~SceneObject() = default;
virtual void render(const glm::mat4& view, const glm::mat4& projection) = 0;
virtual void update(float deltaTime) = 0;
};
// 唐朝人物基类
class TangCharacter : public SceneObject {
protected:
glm::vec3 position;
glm::mat4 modelMatrix;
GLuint VAO, VBO;
float animationTime = 0.0f;
public:
TangCharacter(const glm::vec3& pos) : position(pos) {}
virtual ~TangCharacter() = default;
void update(float deltaTime) override {
animationTime += deltaTime;
// 基础动画逻辑
}
void render(const glm::mat4& view, const glm::mat4& projection) override {
// 基础渲染逻辑
}
};
// 人物性格系统
class HistoricalPersonality {
private:
std::map<EmotionalState, std::vector<std::string>> dialogues;
EmotionalState currentState = EmotionalState::NEUTRAL;
public:
void setDialogues(EmotionalState state, const std::vector<std::string>& lines) {
dialogues[state] = lines;
}
std::string speak(EmotionalState state) {
currentState = state;
auto& stateDialogues = dialogues[state];
if (stateDialogues.empty()) return "";
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, stateDialogues.size() - 1);
return stateDialogues[dis(gen)];
}
EmotionalState getCurrentState() const { return currentState; }
};
// 增强的唐朝人物类
class EnhancedTangCharacter : public TangCharacter {
private:
std::string characterName;
std::string characterType;
HistoricalPersonality personality;
EmotionalState currentEmotion;
float emotionChangeTimer = 0;
float speakCooldown = 0;
bool canSpeak = true;
public:
EnhancedTangCharacter(const std::string& name, const std::string& type, const glm::vec3& pos)
: TangCharacter(pos), characterName(name), characterType(type),
currentEmotion(EmotionalState::NEUTRAL) {
initializePersonality();
}
void initializePersonality() {
if (characterType == "libai") {
personality.setDialogues(EmotionalState::POETIC, {
"李白:(举杯邀月)人生得意须尽欢,莫使金樽空对月!这月色如此美好,当浮一大白!",
"李白:我本楚狂人,凤歌笑孔丘。手持绿玉杖,朝别黄鹤楼。哈哈哈!痛快!"
});
personality.setDialogues(EmotionalState::JOYFUL, {
"李白:今日得见知己,当痛饮三百杯!店家,再上酒来!",
"李白:这长安繁华,盛唐气象,能生于此世,实乃我辈之幸!"
});
personality.setDialogues(EmotionalState::SAD, {
"李白:(叹息)大道如青天,我独不得出...这满腹才华,何时才能得遇明主?",
"李白:花间一壶酒,独酌无相亲。举杯邀明月,对影成三人...寂寞啊寂寞。"
});
} else if (characterType == "dufu") {
personality.setDialogues(EmotionalState::SAD, {
"杜甫:(忧心忡忡)朱门酒肉臭,路有冻死骨...这世道,百姓苦啊!",
"杜甫:国破山河在,城春草木深。感时花溅泪,恨别鸟惊心...大唐何时才能重振?"
});
personality.setDialogues(EmotionalState::ANGRY, {
"杜甫:(愤慨)官军收洛阳,家住洛阳里。夫婿与兄弟,目前见伤死!这战乱何时休!"
});
} else if (characterType == "merchant") {
personality.setDialogues(EmotionalState::NEUTRAL, {
"西域商人:(展示货物)来自波斯的琉璃,大食的香料,都是上等货色!",
"西域商人:这丝绸之路真是黄金之路啊!从长安到罗马,处处是商机!"
});
}
}
void update(float deltaTime) override {
TangCharacter::update(deltaTime);
// 情绪状态变化
emotionChangeTimer -= deltaTime;
if (emotionChangeTimer <= 0) {
changeEmotionRandomly();
emotionChangeTimer = 10.0f + (rand() % 20);
}
// 说话冷却
if (!canSpeak) {
speakCooldown -= deltaTime;
if (speakCooldown <= 0) canSpeak = true;
}
}
void changeEmotionRandomly() {
if (characterType == "libai") {
std::vector<EmotionalState> emotions = {
EmotionalState::POETIC, EmotionalState::JOYFUL, EmotionalState::POETIC, EmotionalState::NOSTALGIC
};
currentEmotion = emotions[rand() % emotions.size()];
} else if (characterType == "dufu") {
std::vector<EmotionalState> emotions = {
EmotionalState::SAD, EmotionalState::ANGRY, EmotionalState::NOSTALGIC, EmotionalState::SAD
};
currentEmotion = emotions[rand() % emotions.size()];
}
}
void speak(class DialogueUIManager& dialogueManager) {
if (!canSpeak) return;
std::string dialogue = personality.speak(currentEmotion);
if (!dialogue.empty()) {
dialogueManager.addMessage(characterName, dialogue, position, true);
speakCooldown = 8.0f + (rand() % 7);
canSpeak = false;
}
}
const std::string& getName() const { return characterName; }
};
// 对话UI管理器
class DialogueUIManager {
private:
struct DialogueUI {
GLuint VAO, VBO, EBO;
GLuint texture;
glm::vec2 position = glm::vec2(0.1f, 0.1f);
glm::vec2 size = glm::vec2(0.8f, 0.2f);
bool isVisible = false;
};
DialogueUI dialogueUI;
std::vector<DialogueMessage> messageQueue;
DialogueMessage currentMessage;
float messageTimer = 0;
bool isShowingMessage = false;
GLuint shaderProgram;
public:
DialogueUIManager() = default;
bool initialize() {
createDialogueBackground();
const char* vs = R"(
#version 330 core
layout(location = 0) in vec2 aPos;
uniform vec2 uScreenSize;
void main() {
vec2 normalizedPos = aPos / uScreenSize;
gl_Position = vec4(normalizedPos * 2.0 - 1.0, 0.0, 1.0);
}
)";
const char* fs = R"(
#version 330 core
out vec4 FragColor;
uniform vec4 uColor;
void main() {
FragColor = uColor;
}
)";
// shaderProgram = ShaderManager::compileShaders(vs, fs);
return true; // shaderProgram != 0;
}
void createDialogueBackground() {
float x = dialogueUI.position.x, y = dialogueUI.position.y;
float w = dialogueUI.size.x, h = dialogueUI.size.y;
float vertices[] = { x, y, x+w, y, x+w, y+h, x, y+h };
unsigned int indices[] = { 0, 1, 2, 2, 3, 0 };
glGenVertexArrays(1, &dialogueUI.VAO);
glGenBuffers(1, &dialogueUI.VBO);
glGenBuffers(1, &dialogueUI.EBO);
glBindVertexArray(dialogueUI.VAO);
glBindBuffer(GL_ARRAY_BUFFER, dialogueUI.VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dialogueUI.EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
}
void addMessage(const std::string& speaker, const std::string& content,
const glm::vec3& position = glm::vec3(0), bool isHistorical = false) {
DialogueMessage msg{speaker, content, 5.0f, position, isHistorical};
messageQueue.push_back(msg);
}
void update(float deltaTime) {
if (isShowingMessage) {
messageTimer -= deltaTime;
if (messageTimer <= 0) {
isShowingMessage = false;
dialogueUI.isVisible = false;
}
}
if (!isShowingMessage && !messageQueue.empty()) {
currentMessage = messageQueue.front();
messageQueue.erase(messageQueue.begin());
dialogueUI.isVisible = true;
isShowingMessage = true;
messageTimer = currentMessage.displayTime;
}
}
void render() {
if (!dialogueUI.isVisible) return;
glUseProgram(shaderProgram);
glBindVertexArray(dialogueUI.VAO);
// 设置uniform并渲染
GLint screenSizeLoc = glGetUniformLocation(shaderProgram, "uScreenSize");
glUniform2f(screenSizeLoc, 1920.0f, 1080.0f);
glUniform4f(glGetUniformLocation(shaderProgram, "uColor"), 0.0f, 0.0f, 0.0f, 0.7f);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// 这里应该渲染文本
// renderText(currentMessage.speakerName + ":" + currentMessage.content, ...);
}
};
// 主VR应用类
class TangDynastyVRApp {
private:
GLFWwindow* window;
vr::IVRSystem* vrSystem;
// 渲染资源
GLuint leftEyeFramebuffer, rightEyeFramebuffer;
GLuint leftEyeTexture, rightEyeTexture;
// 场景管理
std::vector<std::shared_ptr<SceneObject>> sceneObjects;
std::vector<std::shared_ptr<EnhancedTangCharacter>> characters;
DialogueUIManager dialogueManager;
// 着色器
GLuint shaderProgram;
public:
TangDynastyVRApp() : window(nullptr), vrSystem(nullptr), shaderProgram(0) {}
bool initialize() {
if (!initializeOpenGL() || !initializeVR()) return false;
setupVRRenderTargets();
dialogueManager.initialize();
initializeScene();
return true;
}
bool initializeOpenGL() {
if (!glfwInit()) return false;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
window = glfwCreateWindow(800, 600, "唐朝VR体验", nullptr, nullptr);
if (!window) {
glfwTerminate();
return false;
}
glfwMakeContextCurrent(window);
return glewInit() == GLEW_OK;
}
bool initializeVR() {
vr::EVRInitError error = vr::VRInitError_None;
vrSystem = vr::VR_Init(&error, vr::VRApplication_Scene);
return error == vr::VRInitError_None;
}
void initializeScene() {
// 创建历史人物
auto liBai = std::make_shared<EnhancedTangCharacter>("李白", "libai", glm::vec3(2, 0, -3));
auto duFu = std::make_shared<EnhancedTangCharacter>("杜甫", "dufu", glm::vec3(-2, 0, -3));
auto merchant = std::make_shared<EnhancedTangCharacter>("西域商人", "merchant", glm::vec3(0, 0, -4));
characters.push_back(liBai);
characters.push_back(duFu);
characters.push_back(merchant);
// 添加到场景对象
for (auto& character : characters) {
sceneObjects.push_back(character);
}
}
void setupVRRenderTargets() {
// 创建VR渲染目标
glGenFramebuffers(1, &leftEyeFramebuffer);
glGenFramebuffers(1, &rightEyeFramebuffer);
// ... 更多初始化代码
}
void run() {
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
float deltaTime = 0.016f; // 假设60FPS
// 更新所有对象
for (auto& obj : sceneObjects) {
obj->update(deltaTime);
}
// 随机触发对话
for (auto& character : characters) {
if (rand() % 600 < 1) { // 约每秒有1/600几率触发
character->speak(dialogueManager);
}
}
dialogueManager.update(deltaTime);
// VR渲染
renderVRScene();
glfwSwapBuffers(window);
}
}
void renderVRScene() {
// 渲染左眼
glBindFramebuffer(GL_FRAMEBUFFER, leftEyeFramebuffer);
renderEye(vr::Eye_Left);
// 渲染右眼
glBindFramebuffer(GL_FRAMEBUFFER, rightEyeFramebuffer);
renderEye(vr::Eye_Right);
// 提交到VR合成器
// vr::VRCompositor()->Submit(...);
}
void renderEye(vr::Hmd_Eye eye) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 设置视图和投影矩阵
glm::mat4 view = getEyeViewMatrix(eye);
glm::mat4 projection = getEyeProjectionMatrix(eye);
// 渲染场景对象
for (auto& obj : sceneObjects) {
obj->render(view, projection);
}
// 渲染UI
dialogueManager.render();
}
glm::mat4 getEyeViewMatrix(vr::Hmd_Eye eye) {
// 获取VR眼睛视图矩阵
return glm::mat4(1.0f);
}
glm::mat4 getEyeProjectionMatrix(vr::Hmd_Eye eye) {
// 获取VR眼睛投影矩阵
return glm::mat4(1.0f);
}
~TangDynastyVRApp() {
if (vrSystem) vr::VR_Shutdown();
if (window) glfwDestroyWindow(window);
glfwTerminate();
}
};
// 主函数
int main() {
TangDynastyVRApp app;
if (app.initialize()) {
std::cout << "启动唐朝VR体验..." << std::endl;
app.run();
}
return 0;
}
