3
社区成员
发帖
与我相关
我的任务
分享#include <iostream>
#include <vector>
#include <windows.h>
#include <fstream>
#include <string>
#include <cmath> // 添加数学库
// 【关键】GLFW DLL 定义
#define GLFW_DLL
#include <GLFW/glfw3.h>
#include <glad/glad.h>
// ImGui 头文件
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
// 添加简单的数学结构体
struct Vec3 {
float x, y, z;
Vec3(float x = 0, float y = 0, float z = 0) : x(x), y(y), z(z) {}
};
// --- 修改后的着色器源码,添加变换矩阵 ---
const char* vertexShaderSource = R"(
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
uniform mat4 transform; // 变换矩阵
out vec3 ourColor;
void main() {
gl_Position = transform * vec4(aPos, 1.0);
ourColor = aColor;
}
)";
const char* fragmentShaderSource = R"(
#version 330 core
in vec3 ourColor;
out vec4 FragColor;
void main() {
FragColor = vec4(ourColor, 1.0);
}
)";
// 全局变量:三角形的颜色
float triColorR = 1.0f;
float triColorG = 0.0f;
float triColorB = 0.0f;
// ==========================================
// 变换控制变量
// ==========================================
// 平移
float transX = 0.0f, transY = 0.0f;
// 旋转(角度)
float rotation = 0.0f;
// 缩放
float scale = 1.0f;
// 鼠标控制变量
bool firstMouse = true;
float lastX = 400, lastY = 300;
float yaw = 0.0f; // 绕Y轴旋转(左右)- 用于3D旋转
float pitch = 0.0f; // 绕X轴旋转(上下)- 用于3D旋转
// 鼠标按键状态
bool leftMousePressed = false; // 左键用于旋转
bool rightMousePressed = false; // 右键用于平移
// 键盘控制速度
float moveSpeed = 0.01f; // 降低速度使操作更精细
float rotSpeed = 1.0f; // 降低旋转速度
float scaleSpeed = 0.03f;
// ==========================================
// 生成变换矩阵的函数(修正:先缩放,再旋转,最后平移)
// ==========================================
void generateTransformMatrix(float* matrix) {
// 初始化为单位矩阵
for (int i = 0; i < 16; i++) {
matrix[i] = 0.0f;
}
matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0f;
// 1. 先应用缩放
float scaleMatrix[16] = {
scale, 0, 0, 0,
0, scale, 0, 0,
0, 0, scale, 0,
0, 0, 0, 1
};
// 2. 再应用旋转(绕Z轴)
float rad = rotation * 3.14159f / 180.0f;
float cosR = cos(rad);
float sinR = sin(rad);
float rotMatrix[16] = {
cosR, -sinR, 0, 0,
sinR, cosR, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
// 3. 最后应用平移
float transMatrix[16] = {
1, 0, 0, transX,
0, 1, 0, transY,
0, 0, 1, 0,
0, 0, 0, 1
};
// 组合矩阵:transform = trans * rot * scale
// 先计算 rot * scale
float temp[16];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
temp[i * 4 + j] = 0;
for (int k = 0; k < 4; k++) {
temp[i * 4 + j] += rotMatrix[i * 4 + k] * scaleMatrix[k * 4 + j];
}
}
}
// 再计算 trans * (rot * scale)
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
matrix[i * 4 + j] = 0;
for (int k = 0; k < 4; k++) {
matrix[i * 4 + j] += transMatrix[i * 4 + k] * temp[k * 4 + j];
}
}
}
}
// ==========================================
// 鼠标回调函数 - 左键旋转,右键平移
// ==========================================
void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
// 如果没有按下任何鼠标键,直接返回
if (!leftMousePressed && !rightMousePressed) {
firstMouse = true;
return;
}
if (firstMouse) {
lastX = xpos;
lastY = ypos;
firstMouse = false;
return;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // 反转Y轴
lastX = xpos;
lastY = ypos;
// ==========================================
// 左键:旋转 - 使用累积旋转,更自然
// ==========================================
if (leftMousePressed) {
// 灵敏度
float sensitivity = 0.3f;
xoffset *= sensitivity;
yoffset *= sensitivity;
// 累积旋转角度
rotation += xoffset; // 左右移动控制绕Z轴旋转
// 可以取消下面的注释来实现3D旋转
// yaw += xoffset;
// pitch += yoffset;
// if (pitch > 89.0f) pitch = 89.0f;
// if (pitch < -89.0f) pitch = -89.0f;
// rotation = yaw; // 如果需要3D旋转,这里需要更复杂的矩阵
}
// ==========================================
// 右键:平移 - 直接控制transX和transY
// ==========================================
if (rightMousePressed) {
// 移动速度系数,根据窗口大小调整
int width, height;
glfwGetWindowSize(window, &width, &height);
float panSpeed = 2.0f / (height > 0 ? height : 600); // 归一化到[-1,1]空间
// 直接修改平移量,累积移动
transX += xoffset * panSpeed;
transY -= yoffset * panSpeed; // 注意符号
}
}
// ==========================================
// 鼠标按钮回调 - 区分左右键
// ==========================================
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
// 左键处理
if (button == GLFW_MOUSE_BUTTON_LEFT) {
if (action == GLFW_PRESS) {
leftMousePressed = true;
firstMouse = true;
}
else if (action == GLFW_RELEASE) {
leftMousePressed = false;
}
}
// 右键处理
if (button == GLFW_MOUSE_BUTTON_RIGHT) {
if (action == GLFW_PRESS) {
rightMousePressed = true;
firstMouse = true;
}
else if (action == GLFW_RELEASE) {
rightMousePressed = false;
}
}
}
// 滚轮回调(用于缩放)
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
scale *= (1.0f + yoffset * scaleSpeed); // 使用乘法使缩放更自然
if (scale < 0.1f) scale = 0.1f;
if (scale > 5.0f) scale = 5.0f;
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
// ==========================================
// 键盘输入处理
// ==========================================
void processInput(GLFWwindow* window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
// 平移控制(WASD)
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
transY += moveSpeed;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
transY -= moveSpeed;
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
transX -= moveSpeed;
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
transX += moveSpeed;
// 旋转控制(方向键)
if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS)
rotation -= rotSpeed;
if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS)
rotation += rotSpeed;
// 缩放控制(加减号)
if (glfwGetKey(window, GLFW_KEY_EQUAL) == GLFW_PRESS ||
glfwGetKey(window, GLFW_KEY_KP_ADD) == GLFW_PRESS)
scale += scaleSpeed;
if (glfwGetKey(window, GLFW_KEY_MINUS) == GLFW_PRESS ||
glfwGetKey(window, GLFW_KEY_KP_SUBTRACT) == GLFW_PRESS)
scale -= scaleSpeed;
// 限制范围
if (scale < 0.1f) scale = 0.1f;
if (scale > 5.0f) scale = 5.0f;
// 重置(R键)
if (glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS) {
transX = 0.0f;
transY = 0.0f;
rotation = 0.0f;
scale = 1.0f;
yaw = 0.0f;
pitch = 0.0f;
}
}
// 辅助函数:检查文件是否存在
bool fileExists(const std::string& filename) {
std::ifstream f(filename.c_str());
return f.good();
}
int main() {
// 设置控制台输出编码为UTF-8
SetConsoleOutputCP(CP_UTF8);
// 使用u8前缀输出中文到控制台
std::cout << u8"正在初始化OpenGL程序..." << std::endl;
// 1. 初始化 GLFW
if (!glfwInit()) {
std::cout << u8"初始化GLFW失败" << std::endl;
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 600, u8"OpenGL + ImGui 变换控制器", NULL, NULL);
if (window == NULL) {
std::cout << u8"创建GLFW窗口失败" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// ==========================================
// 设置鼠标回调
// ==========================================
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetScrollCallback(window, scroll_callback);
// 2. 初始化 GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << u8"初始化GLAD失败" << std::endl;
return -1;
}
// ==========================================
// 3. 初始化 ImGui
// ==========================================
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
std::cout << u8"尝试加载中文字体..." << std::endl;
// 获取当前可执行文件路径
char exePath[MAX_PATH];
GetModuleFileNameA(NULL, exePath, MAX_PATH);
std::string exeDir = std::string(exePath);
exeDir = exeDir.substr(0, exeDir.find_last_of("\\/"));
// 要尝试的字体路径列表
std::vector<std::string> fontPaths;
fontPaths.push_back("C:\\Windows\\Fonts\\msyh.ttc");
fontPaths.push_back("C:\\Windows\\Fonts\\simhei.ttf");
fontPaths.push_back("C:\\Windows\\Fonts\\simkai.ttf");
fontPaths.push_back(exeDir + "\\msyh.ttc");
fontPaths.push_back(exeDir + "\\simhei.ttf");
ImFont* font = nullptr;
for (const auto& path : fontPaths) {
std::cout << u8"尝试字体: " << path << std::endl;
if (fileExists(path)) {
std::cout << u8"文件存在,尝试加载..." << std::endl;
io.Fonts->Clear();
font = io.Fonts->AddFontFromFileTTF(
path.c_str(),
18.0f,
NULL,
io.Fonts->GetGlyphRangesChineseFull()
);
if (font) {
std::cout << u8"✓ 成功加载字体: " << path << std::endl;
io.Fonts->Build();
break;
}
else {
std::cout << u8"✗ 文件存在但加载失败" << std::endl;
}
}
else {
std::cout << u8"✗ 文件不存在" << std::endl;
}
}
if (font == NULL) {
std::cout << u8"⚠ 警告:所有字体加载失败,使用默认字体" << std::endl;
io.Fonts->AddFontDefault();
io.Fonts->Build();
}
ImGui::StyleColorsDark();
// ==========================================
// 4. 初始化 ImGui 后端
// ==========================================
std::cout << u8"初始化 ImGui 后端..." << std::endl;
if (!ImGui_ImplGlfw_InitForOpenGL(window, true)) {
std::cout << u8"初始化 ImGui GLFW 后端失败" << std::endl;
return -1;
}
if (!ImGui_ImplOpenGL3_Init("#version 330")) {
std::cout << u8"初始化 ImGui OpenGL3 后端失败" << std::endl;
return -1;
}
std::cout << u8"ImGui 初始化完成!" << std::endl;
// ==========================================
// 5. 编译着色器
// ==========================================
std::cout << u8"编译着色器..." << std::endl;
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << u8"顶点着色器编译失败:\n" << infoLog << std::endl;
return -1;
}
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << u8"片段着色器编译失败:\n" << infoLog << std::endl;
return -1;
}
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << u8"着色器程序链接失败:\n" << infoLog << std::endl;
return -1;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// 获取变换矩阵的uniform位置
int transformLoc = glGetUniformLocation(shaderProgram, "transform");
// ==========================================
// 6. 准备三角形数据
// ==========================================
std::cout << u8"准备顶点数据..." << std::endl;
float vertices[] = {
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f
};
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_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);
glBindVertexArray(0);
float inputR = 1.0f, inputG = 0.0f, inputB = 0.0f;
std::cout << u8"初始化完成,开始渲染循环..." << std::endl;
std::cout << u8"\n控制说明:" << std::endl;
std::cout << u8" 鼠标左键拖动 - 旋转" << std::endl;
std::cout << u8" 鼠标右键拖动 - 平移" << std::endl;
std::cout << u8" 鼠标滚轮 - 缩放" << std::endl;
std::cout << u8" WASD - 平移(备选)" << std::endl;
std::cout << u8" 左右方向键 - 旋转(备选)" << std::endl;
std::cout << u8" +/- - 缩放(备选)" << std::endl;
std::cout << u8" R - 重置" << std::endl;
// ==========================================
// 7. 渲染循环
// ==========================================
while (!glfwWindowShouldClose(window)) {
processInput(window);
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// --- 创建 UI 窗口 ---
ImGui::Begin(u8"变换控制器");
ImGui::Text(u8"变换控制");
ImGui::Separator();
// 显示当前变换参数
ImGui::Text(u8"平移: X=%.2f, Y=%.2f", transX, transY);
ImGui::Text(u8"旋转: %.1f°", rotation);
ImGui::Text(u8"缩放: %.2f", scale);
ImGui::Separator();
// 添加滑块控制
ImGui::SliderFloat(u8"平移 X", &transX, -2.0f, 2.0f, "%.2f");
ImGui::SliderFloat(u8"平移 Y", &transY, -2.0f, 2.0f, "%.2f");
ImGui::SliderFloat(u8"旋转", &rotation, -180.0f, 180.0f, "%.1f°");
ImGui::SliderFloat(u8"缩放", &scale, 0.1f, 5.0f, "%.2f");
if (ImGui::Button(u8"重置所有变换")) {
transX = 0.0f;
transY = 0.0f;
rotation = 0.0f;
scale = 1.0f;
yaw = 0.0f;
pitch = 0.0f;
}
ImGui::Separator();
ImGui::Text(u8"颜色控制");
ImGui::Separator();
ImVec4 color = ImVec4(triColorR, triColorG, triColorB, 1.0f);
if (ImGui::ColorEdit3(u8"选择颜色", (float*)&color)) {
triColorR = color.x;
triColorG = color.y;
triColorB = color.z;
inputR = triColorR;
inputG = triColorG;
inputB = triColorB;
}
ImGui::Separator();
ImGui::Text(u8"或者手动输入 (0.0 - 1.0):");
ImGui::InputFloat(u8"红色", &inputR, 0.1f, 1.0f, "%.2f");
ImGui::InputFloat(u8"绿色", &inputG, 0.1f, 1.0f, "%.2f");
ImGui::InputFloat(u8"蓝色", &inputB, 0.1f, 1.0f, "%.2f");
if (ImGui::Button(u8"应用输入框颜色")) {
triColorR = (inputR < 0) ? 0 : (inputR > 1 ? 1 : inputR);
triColorG = (inputG < 0) ? 0 : (inputG > 1 ? 1 : inputG);
triColorB = (inputB < 0) ? 0 : (inputB > 1 ? 1 : inputB);
}
ImGui::Separator();
ImGui::Text(u8"当前颜色:");
ImGui::ColorButton(u8"当前颜色", ImVec4(triColorR, triColorG, triColorB, 1.0f),
ImGuiColorEditFlags_NoTooltip, ImVec2(100, 20));
ImGui::End();
// 更新三角形颜色
float updatedVertices[] = {
0.0f, 0.5f, 0.0f, triColorR, triColorG, triColorB,
0.5f, -0.5f, 0.0f, triColorR, triColorG, triColorB,
-0.5f, -0.5f, 0.0f, triColorR, triColorG, triColorB
};
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(updatedVertices), updatedVertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// OpenGL 渲染
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
// 生成并传递变换矩阵
float transformMatrix[16];
generateTransformMatrix(transformMatrix);
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, transformMatrix);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
// 渲染 ImGui
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window);
glfwPollEvents();
}
// 清理资源
std::cout << u8"清理资源..." << std::endl;
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);
glfwTerminate();
std::cout << u8"程序正常退出" << std::endl;
return 0;
}