博主最近时间不多,所以不过多阐述,直接上代码
// 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>
#include <iostream>
// ==================== 核心系统枚举和结构 ====================
enum class EmotionalState { NEUTRAL, JOYFUL, ANGRY, SAD, POETIC, NOSTALGIC, PROUD };
enum class TimePeriod { MORNING, NOON, AFTERNOON, EVENING, NIGHT };
struct DialogueMessage {
std::string speakerName, content;
float displayTime;
glm::vec3 speakerPosition;
bool isHistoricalFigure;
};
struct PBRMaterial {
glm::vec3 albedo = glm::vec3(0.8f, 0.8f, 0.8f);
float metallic = 0.0f, roughness = 0.8f, ao = 1.0f;
GLuint albedoMap = 0, normalMap = 0;
};
// ==================== 场景对象基类 ====================
class SceneObject {
public:
virtual ~SceneObject() = default;
virtual void render(const glm::mat4& view, const glm::mat4& projection) = 0;
virtual void update(float deltaTime) = 0;
virtual glm::vec3 getPosition() const = 0;
virtual void setSelected(bool selected) {}
virtual std::string getName() const { return "Unknown"; }
};
// ==================== 时间与季节系统 ====================
class TimeWeatherSystem {
private:
float timeOfDay = 8.0f; // 8:00 AM开始
float dayCounter = 0.0f;
float timeSpeed = 60.0f;
glm::vec3 sunDirection, sunColor, ambientLight;
TimePeriod currentPeriod = TimePeriod::MORNING;
public:
void update(float deltaTime) {
timeOfDay += deltaTime * timeSpeed / 3600.0f;
if (timeOfDay >= 24.0f) {
timeOfDay -= 24.0f;
dayCounter += 1.0f;
}
updateTimePeriod();
updateLighting();
}
void updateTimePeriod() {
if (timeOfDay >= 5.0f && timeOfDay < 8.0f) currentPeriod = TimePeriod::MORNING;
else if (timeOfDay >= 8.0f && timeOfDay < 12.0f) currentPeriod = TimePeriod::NOON;
else if (timeOfDay >= 12.0f && timeOfDay < 17.0f) currentPeriod = TimePeriod::AFTERNOON;
else if (timeOfDay >= 17.0f && timeOfDay < 21.0f) currentPeriod = TimePeriod::EVENING;
else currentPeriod = TimePeriod::NIGHT;
}
void updateLighting() {
float hourAngle = (timeOfDay - 6.0f) * 15.0f;
float radianAngle = glm::radians(hourAngle);
sunDirection = glm::normalize(glm::vec3(glm::sin(radianAngle), glm::cos(radianAngle), 0.0f));
if (currentPeriod == TimePeriod::NIGHT) {
sunColor = glm::vec3(0.1f, 0.1f, 0.2f);
ambientLight = glm::vec3(0.05f, 0.05f, 0.1f);
} else {
float intensity = 1.0f - abs(timeOfDay - 12.0f) / 6.0f;
sunColor = glm::vec3(1.0f, 0.9f, 0.8f) * intensity;
ambientLight = glm::vec3(0.3f, 0.3f, 0.4f) * intensity;
}
}
TimePeriod getCurrentPeriod() const { return currentPeriod; }
float getTimeOfDay() const { return timeOfDay; }
glm::vec3 getSunDirection() const { return sunDirection; }
glm::vec3 getSunColor() const { return sunColor; }
glm::vec3 getAmbientLight() const { return ambientLight; }
std::string getTimeString() const {
int hour = static_cast<int>(timeOfDay);
int minute = static_cast<int>((timeOfDay - hour) * 60);
return std::to_string(hour) + ":" + (minute < 10 ? "0" : "") + std::to_string(minute);
}
std::string getPeriodString() const {
switch(currentPeriod) {
case TimePeriod::MORNING: return "清晨";
case TimePeriod::NOON: return "正午";
case TimePeriod::AFTERNOON: return "下午";
case TimePeriod::EVENING: return "傍晚";
case TimePeriod::NIGHT: return "夜晚";
default: return "未知";
}
}
};
// ==================== 历史人物性格系统 ====================
class HistoricalPersonality {
private:
std::map<EmotionalState, std::vector<std::string>> dialogues;
std::map<TimePeriod, std::vector<std::string>> timeBasedDialogues;
public:
void setDialogues(EmotionalState state, const std::vector<std::string>& lines) {
dialoguesstate = lines;
}
void setTimeDialogues(TimePeriod period, const std::vector<std::string>& lines) {
timeBasedDialoguesperiod = lines;
}
std::string speak(EmotionalState state, TimePeriod period) {
// 70%几率使用情感对话,30%几率使用时间对话
if ((rand() % 10) < 3 && !timeBasedDialoguesperiod.empty()) {
auto& periodDialogues = timeBasedDialoguesperiod;
return periodDialoguesrand() % periodDialogues.size();
} else {
auto& stateDialogues = dialoguesstate;
if (!stateDialogues.empty()) {
return stateDialoguesrand() % stateDialogues.size();
}
}
return "";
}
};
// ==================== 增强历史人物类 ====================
class EnhancedHistoricalCharacter : public SceneObject {
private:
std::string characterName, characterType;
glm::vec3 position, historicalHeight;
glm::mat4 modelMatrix;
EmotionalState currentEmotion;
HistoricalPersonality personality;
TimeWeatherSystem* timeSystem;
// 渲染资源
GLuint VAO, VBO, textureID;
PBRMaterial material;
// 动画状态
float animationTime = 0.0f, emotionChangeTimer = 0.0f;
float speakCooldown = 0.0f, blinkTimer = 0.0f;
bool canSpeak = true, isSelected = false;
// 日常安排
std::map<TimePeriod, std::string> activities;
std::map<TimePeriod, glm::vec3> locations;
public:
EnhancedHistoricalCharacter(const std::string& name, const std::string& type,
const glm::vec3& pos, TimeWeatherSystem* timeSys)
: characterName(name), characterType(type), position(pos), timeSystem(timeSys),
currentEmotion(EmotionalState::NEUTRAL) {
initializeHistoricalData();
initializePersonality();
initializeDailySchedule();
setupRendering();
}
void initializeHistoricalData() {
// 基于历史记录设置特征
if (characterName == "李白") {
historicalHeight = glm::vec3(1.0f, 1.75f, 1.0f);
material.albedo = glm::vec3(0.3f, 0.3f, 0.5f); // 文人青衫
} else if (characterName == "杜甫") {
historicalHeight = glm::vec3(1.0f, 1.72f, 1.0f);
material.albedo = glm::vec3(0.4f, 0.3f, 0.2f); // 朴素褐衣
} else if (characterName == "杨贵妃") {
historicalHeight = glm::vec3(1.0f, 1.65f, 1.0f);
material.albedo = glm::vec3(0.9f, 0.1f, 0.1f); // 华贵红装
}
modelMatrix = glm::scale(glm::mat4(1.0f), historicalHeight);
}
void initializePersonality() {
if (characterType == "libai") {
personality.setDialogues(EmotionalState::POETIC, {
"李白:(举杯邀月)人生得意须尽欢,莫使金樽空对月!",
"李白:天生我材必有用,千金散尽还复来!当浮一大白!",
"李白:我本楚狂人,凤歌笑孔丘。手持绿玉杖,朝别黄鹤楼。"
});
personality.setTimeDialogues(TimePeriod::EVENING, {
"李白:如此良辰美景,当对月饮酒,吟诗作对!",
"李白:店家,再来一壶好酒!今夜不醉不归!"
});
} else if (characterType == "dufu") {
personality.setDialogues(EmotionalState::SAD, {
"杜甫:(忧心忡忡)朱门酒肉臭,路有冻死骨...",
"杜甫:国破山河在,城春草木深。感时花溅泪,恨别鸟惊心。"
});
personality.setTimeDialogues(TimePeriod::MORNING, {
"杜甫:晨起读书,当思天下百姓疾苦。",
"杜甫:这清晨的宁静,不知能持续到几时..."
});
}
}
void initializeDailySchedule() {
// 基于历史记载的日常安排
activitiesTimePeriod::MORNING = "晨读";
activitiesTimePeriod::NOON = "用膳";
activitiesTimePeriod::AFTERNOON = (characterType == "libai") ? "饮酒作诗" : "忧思国事";
activitiesTimePeriod::EVENING = "赏月";
activitiesTimePeriod::NIGHT = "就寝";
// 不同时间段的位置
locationsTimePeriod::MORNING = glm::vec3(2, 0, -3);
locationsTimePeriod::NOON = glm::vec3(0, 0, -4);
locationsTimePeriod::AFTERNOON = glm::vec3(-2, 0, -3);
locationsTimePeriod::EVENING = glm::vec3(0, 0, -5);
locationsTimePeriod::NIGHT = glm::vec3(1, 0, -2);
}
void setupRendering() {
// 创建简单的人物几何体(实际应用应加载3D模型)
float vertices\[\] = {
// 位置 // 颜色
-0.3f, 0.0f, 0.0f, material.albedo.r, material.albedo.g, material.albedo.b,
0.3f, 0.0f, 0.0f, material.albedo.r, material.albedo.g, material.albedo.b,
0.0f, 1.5f, 0.0f, material.albedo.r, material.albedo.g, material.albedo.b,
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
}
void update(float deltaTime) override {
animationTime += deltaTime;
// 情绪变化
emotionChangeTimer -= deltaTime;
if (emotionChangeTimer <= 0) {
changeEmotionBasedOnTime();
emotionChangeTimer = 15.0f + (rand() % 15);
}
// 基于时间的活动
updateTimeBasedBehavior();
// 自然动画
float breath = sin(animationTime * 2.0f) * 0.005f;
modelMatrix = glm::translate(glm::mat4(1.0f), position + glm::vec3(0, breath, 0));
modelMatrix = glm::scale(modelMatrix, historicalHeight);
// 说话冷却
if (!canSpeak) {
speakCooldown -= deltaTime;
if (speakCooldown <= 0) canSpeak = true;
}
// 眨眼动画
blinkTimer += deltaTime;
}
void changeEmotionBasedOnTime() {
TimePeriod period = timeSystem->getCurrentPeriod();
switch(period) {
case TimePeriod::MORNING:
currentEmotion = (characterType == "libai") ? EmotionalState::POETIC : EmotionalState::NEUTRAL;
break;
case TimePeriod::EVENING:
currentEmotion = (characterType == "libai") ? EmotionalState::JOYFUL : EmotionalState::NOSTALGIC;
break;
case TimePeriod::NIGHT:
currentEmotion = EmotionalState::SAD;
break;
default:
currentEmotion = EmotionalState::NEUTRAL;
}
}
void updateTimeBasedBehavior() {
TimePeriod period = timeSystem->getCurrentPeriod();
position = locationsperiod; // 移动到对应时间段的位置
// 根据活动调整姿态(简化实现)
if (activitiesperiod == "就寝") {
// 睡眠姿态
} else if (activitiesperiod == "饮酒作诗") {
// 豪放姿态
}
}
void speak(class DialogueUIManager& dialogueManager) {
if (!canSpeak) return;
std::string dialogue = personality.speak(currentEmotion, timeSystem->getCurrentPeriod());
if (!dialogue.empty()) {
dialogueManager.addMessage(characterName, dialogue, position, true);
speakCooldown = 10.0f + (rand() % 10);
canSpeak = false;
}
}
void render(const glm::mat4& view, const glm::mat4& projection) override {
// 简化渲染 - 实际应用应使用PBR着色器和复杂模型
glBindVertexArray(VAO);
// 基础着色器设置
// 如果是选中状态,改变颜色为高亮
if (isSelected) {
// 使用高亮颜色
}
glDrawArrays(GL_TRIANGLES, 0, 3);
}
glm::vec3 getPosition() const override { return position; }
void setSelected(bool selected) override { isSelected = selected; }
std::string getName() const override { return characterName; }
std::string getCurrentActivity() const {
return activities.at(timeSystem->getCurrentPeriod());
}
};
// ==================== 调试棒系统 ====================
class DebugWand {
private:
glm::vec3 position, direction;
bool isActive = false;
GLuint wandVAO, wandVBO;
SceneObject* selectedObject = nullptr;
public:
DebugWand() { initializeWandModel(); }
void initializeWandModel() {
float vertices\[\] = {
0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 红色调试棒
0.0f, 0.5f, 0.0f, 1.0f, 0.5f, 0.5f,
};
glGenVertexArrays(1, &wandVAO);
glGenBuffers(1, &wandVBO);
glBindVertexArray(wandVAO);
glBindBuffer(GL_ARRAY_BUFFER, wandVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
}
void update(const glm::vec3& wandPos, const glm::vec3& wandDir,
std::vector<std::shared_ptr<SceneObject>>& objects) {
position = wandPos;
direction = wandDir;
// 选择逻辑
selectedObject = nullptr;
float minDistance = 5.0f;
for (auto& obj : objects) {
float distance = glm::length(obj->getPosition() - position);
if (distance < minDistance) {
selectedObject = obj.get();
minDistance = distance;
}
}
// 更新选择状态
for (auto& obj : objects) {
obj->setSelected(obj.get() == selectedObject);
}
}
void handleInput(bool rightClick, std::vector<std::shared_ptr<SceneObject>>& objects) {
if (rightClick && selectedObject) {
// 从场景中移除选中的对象
auto it = std::find_if(objects.begin(), objects.end(),
this(const std::shared_ptr<SceneObject>& obj) {
return obj.get() == selectedObject;
});
if (it != objects.end()) {
std::cout << "调试棒: 删除 " << selectedObject->getName() << std::endl;
objects.erase(it);
selectedObject = nullptr;
}
}
}
void render(const glm::mat4& view, const glm::mat4& projection) {
if (!isActive) return;
glBindVertexArray(wandVAO);
// 设置调试棒变换矩阵
glm::mat4 model = glm::translate(glm::mat4(1.0f), position);
// 应用控制器旋转...
glDrawArrays(GL_LINES, 0, 2);
}
void setActive(bool active) { isActive = active; }
};
// ==================== 对话UI系统 ====================
class DialogueUIManager {
private:
struct DialogueUI {
GLuint VAO, VBO, EBO;
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;
public:
bool initialize() {
createDialogueBackground();
return true;
}
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) {
messageQueue.push_back({speaker, content, 5.0f, position, isHistorical});
}
void update(float deltaTime) {
if (isShowingMessage) {
messageTimer -= deltaTime;
if (messageTimer <= 0) {
isShowingMessage = dialogueUI.isVisible = false;
}
}
if (!isShowingMessage && !messageQueue.empty()) {
currentMessage = messageQueue.front();
messageQueue.erase(messageQueue.begin());
dialogueUI.isVisible = isShowingMessage = true;
messageTimer = currentMessage.displayTime;
}
}
void render() {
if (!dialogueUI.isVisible) return;
// 渲染对话框背景
glBindVertexArray(dialogueUI.VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// 实际应用中这里应该渲染文本:
// currentMessage.speakerName + ":" + currentMessage.content
}
void renderTimeInfo(const TimeWeatherSystem& timeSystem) {
// 在实际应用中渲染时间信息
std::string timeInfo = "大唐 " + timeSystem.getPeriodString() + " " + timeSystem.getTimeString();
// 渲染时间文本...
}
};
// ==================== 主VR应用类 ====================
class TangDynastyVRApp {
private:
GLFWwindow* window;
vr::IVRSystem* vrSystem;
// 渲染资源
GLuint leftEyeFramebuffer, rightEyeFramebuffer;
GLuint leftEyeTexture, rightEyeTexture;
GLuint mainShaderProgram;
// 场景管理
std::vector<std::shared_ptr<SceneObject>> sceneObjects;
std::vector<std::shared_ptr<EnhancedHistoricalCharacter>> characters;
DialogueUIManager dialogueManager;
TimeWeatherSystem timeSystem;
DebugWand debugWand;
public:
TangDynastyVRApp() : window(nullptr), vrSystem(nullptr), mainShaderProgram(0) {}
bool initialize() {
if (!initializeOpenGL() || !initializeVR()) return false;
setupVRRenderTargets();
dialogueManager.initialize();
debugWand.setActive(true);
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);
if (error != vr::VRInitError_None) {
std::cout << "VR系统初始化失败,使用桌面模式运行" << std::endl;
// 可以继续运行,但VR功能受限
}
return true;
}
void initializeScene() {
// 创建历史人物
auto liBai = std::make_shared<EnhancedHistoricalCharacter>("李白", "libai",
glm::vec3(2, 0, -3), &timeSystem);
auto duFu = std::make_shared<EnhancedHistoricalCharacter>("杜甫", "dufu",
glm::vec3(-2, 0, -3), &timeSystem);
auto yangGuifei = std::make_shared<EnhancedHistoricalCharacter>("杨贵妃", "noble",
glm::vec3(0, 0, -4), &timeSystem);
characters.push_back(liBai);
characters.push_back(duFu);
characters.push_back(yangGuifei);
// 添加到场景
for (auto& character : characters) {
sceneObjects.push_back(character);
}
// ================ 【你的创意功能插入点1】================
// 在这里初始化你的创意功能
// initializeYourCreativeFeatures();
std::cout << "场景初始化完成,包含 " << characters.size() << " 个历史人物" << std::endl;
}
void setupVRRenderTargets() {
// 创建VR渲染目标
if (vrSystem) {
glGenFramebuffers(1, &leftEyeFramebuffer);
glGenFramebuffers(1, &rightEyeFramebuffer);
// 更多VR特定的初始化...
}
}
void run() {
std::cout << "启动盛唐VR体验..." << std::endl;
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
float deltaTime = 0.016f; // 约60FPS
// 更新时间系统
timeSystem.update(deltaTime);
// 更新所有场景对象
for (auto& obj : sceneObjects) {
obj->update(deltaTime);
}
// 更新调试棒
glm::vec3 wandPos = getControllerPosition();
glm::vec3 wandDir = getControllerDirection();
debugWand.update(wandPos, wandDir, sceneObjects);
// 处理调试棒输入
bool rightClick = isRightControllerClicked();
debugWand.handleInput(rightClick, sceneObjects);
// 随机触发对话
for (auto& character : characters) {
if (rand() % 600 < 2) { // 约每秒有0.3%几率触发
character->speak(dialogueManager);
}
}
// 更新UI
dialogueManager.update(deltaTime);
// ================ 【你的创意功能插入点2】================
// 在这里更新你的创意功能
// updateYourCreativeFeatures(deltaTime);
// 渲染场景
renderVRScene();
glfwSwapBuffers(window);
}
}
void renderVRScene() {
if (vrSystem) {
// VR模式渲染
glBindFramebuffer(GL_FRAMEBUFFER, leftEyeFramebuffer);
renderEye(vr::Eye_Left);
glBindFramebuffer(GL_FRAMEBUFFER, rightEyeFramebuffer);
renderEye(vr::Eye_Right);
// 提交到VR合成器
} else {
// 桌面模式渲染
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderEye(vr::Eye_Left); // 使用单眼渲染
}
}
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);
// 设置时间相关光照
setupTimeBasedLighting();
// 渲染场景对象
for (auto& obj : sceneObjects) {
obj->render(view, projection);
}
// 渲染调试棒
debugWand.render(view, projection);
// 渲染UI
dialogueManager.render();
dialogueManager.renderTimeInfo(timeSystem);
// ================ 【你的创意功能插入点3】================
// 在这里渲染你的创意效果
// renderYourCreativeFeatures(view, projection);
}
void setupTimeBasedLighting() {
// 设置着色器中的光照uniform
// 实际应用中需要设置PBR着色器的光照参数
}
glm::vec3 getControllerPosition() {
// 获取VR控制器位置(简化实现)
return glm::vec3(0, 1.5f, -1.0f);
}
glm::vec3 getControllerDirection() {
// 获取VR控制器方向(简化实现)
return glm::vec3(0, 0, -1.0f);
}
bool isRightControllerClicked() {
// 检测右键点击(简化实现)
return glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS;
}
glm::mat4 getEyeViewMatrix(vr::Hmd_Eye eye) {
// 获取VR眼睛视图矩阵(简化实现)
return glm::lookAt(glm::vec3(0, 1.7f, 3.0f), glm::vec3(0, 1.7f, 0), glm::vec3(0, 1, 0));
}
glm::mat4 getEyeProjectionMatrix(vr::Hmd_Eye eye) {
// 获取VR眼睛投影矩阵(简化实现)
return glm::perspective(glm::radians(60.0f), 16.0f/9.0f, 0.1f, 100.0f);
}
~TangDynastyVRApp() {
if (vrSystem) vr::VR_Shutdown();
if (window) glfwDestroyWindow(window);
glfwTerminate();
}
};
// ==================== 主函数 ====================
int main() {
TangDynastyVRApp app;
if (app.initialize()) {
app.run();
} else {
std::cerr << "应用程序初始化失败!" << std::endl;
return -1;
}
return 0;
}