first commit
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
.cache/
|
||||||
|
.idea/
|
||||||
|
build/
|
||||||
|
cmake-build*/
|
||||||
19
CMakeLists.txt
Normal file
19
CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
project(3dviewer)
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
include_directories(.)
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
main.cpp
|
||||||
|
glad.c
|
||||||
|
lopenglprogram.cpp
|
||||||
|
camera.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
PRIVATE
|
||||||
|
libglfw3.a
|
||||||
|
)
|
||||||
96
camera.h
Normal file
96
camera.h
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
//
|
||||||
|
// Created by Lenn on 2026/1/30.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef INC_3DVIEWER_CAMERA_H
|
||||||
|
#define INC_3DVIEWER_CAMERA_H
|
||||||
|
#include <glad/glad.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
class Camera {
|
||||||
|
public:
|
||||||
|
typedef enum CameraMoveBit {
|
||||||
|
FORWARD = 0x0001,
|
||||||
|
BACKWARD = 0x0002,
|
||||||
|
LEFT = 0x0004,
|
||||||
|
RIGHT = 0x0008,
|
||||||
|
} CameraMove;
|
||||||
|
|
||||||
|
Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f),
|
||||||
|
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f),
|
||||||
|
float yaw = -90.0f, float pitch = 0.0f)
|
||||||
|
: front_(glm::vec3(0.0f, 0.0f, -1.0f)), yaw_(yaw), pitch_(pitch), position_(position)
|
||||||
|
, worldUp_(up){
|
||||||
|
zoom_ = 45.0f;
|
||||||
|
mouseSensitivity_ = 0.1f;
|
||||||
|
moveSpeed_ = 2.5f;
|
||||||
|
updateCameraVectors();
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyboardCallback(CameraMove direction, float deltaTime) {
|
||||||
|
float velocity = moveSpeed_ * deltaTime;
|
||||||
|
if (direction == CameraMove::FORWARD) {
|
||||||
|
position_ += front_ * velocity;
|
||||||
|
}
|
||||||
|
else if (direction == CameraMove::BACKWARD) {
|
||||||
|
position_ -= front_ * velocity;
|
||||||
|
}
|
||||||
|
else if (direction == CameraMove::LEFT) {
|
||||||
|
position_ -= right_ * velocity;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
position_ += right_ * velocity;
|
||||||
|
}
|
||||||
|
updateCameraVectors();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mouseCallback(float xoffset, float yoffset, GLboolean constrainPitch = true) {
|
||||||
|
xoffset *= mouseSensitivity_;
|
||||||
|
yoffset *= mouseSensitivity_;
|
||||||
|
|
||||||
|
yaw_ += xoffset;
|
||||||
|
pitch_ += yoffset;
|
||||||
|
|
||||||
|
if (constrainPitch) {
|
||||||
|
if (pitch_ > 89.0f) {
|
||||||
|
pitch_ = 89.0f;
|
||||||
|
}
|
||||||
|
if (pitch_ < -89.0f) {
|
||||||
|
pitch_ = -89.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateCameraVectors();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 getViewMatrix() {
|
||||||
|
return glm::lookAt(position_, position_ + front_, up_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateCameraVectors() {
|
||||||
|
glm::vec3 front;
|
||||||
|
front.x = std::cos(glm::radians(yaw_)) * std::cos(glm::radians(pitch_));
|
||||||
|
front.y = std::sin(glm::radians(pitch_));
|
||||||
|
front.z = std::sin(glm::radians(yaw_)) * std::cos(glm::radians(pitch_));
|
||||||
|
front_ = glm::normalize(front);
|
||||||
|
|
||||||
|
right_ = glm::normalize(glm::cross(front_, worldUp_));
|
||||||
|
up_ = glm::normalize(glm::cross(right_, front_));
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
glm::vec3 position_;
|
||||||
|
glm::vec3 up_;
|
||||||
|
glm::vec3 right_;
|
||||||
|
glm::vec3 front_;
|
||||||
|
glm::vec3 worldUp_;
|
||||||
|
|
||||||
|
float yaw_;
|
||||||
|
float pitch_;
|
||||||
|
|
||||||
|
float moveSpeed_;
|
||||||
|
float mouseSensitivity_;
|
||||||
|
float zoom_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //INC_3DVIEWER_CAMERA_H
|
||||||
190
lopenglprogram.cpp
Normal file
190
lopenglprogram.cpp
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
#include "lopenglprogram.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
LOpenGLShader::LOpenGLShader(LOpenGLShader::ShaderType type)
|
||||||
|
: shaderType_(type), compiled_(false) {}
|
||||||
|
|
||||||
|
LOpenGLShader::~LOpenGLShader() {
|
||||||
|
if (shaderId_ != 0) {
|
||||||
|
glDeleteShader(shaderId_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LOpenGLShader::compileShaderFromSource(const char *source) {
|
||||||
|
if (!source || compiled_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (shaderType_) {
|
||||||
|
case Vertex:
|
||||||
|
shaderId_ = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
break;
|
||||||
|
case Fragment:
|
||||||
|
shaderId_ = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glShaderSource(shaderId_, 1, &source, NULL);
|
||||||
|
glCompileShader(shaderId_);
|
||||||
|
int success = 0;
|
||||||
|
glGetShaderiv(shaderId_, GL_COMPILE_STATUS, &success);
|
||||||
|
if (!success) {
|
||||||
|
char infoLog[512];
|
||||||
|
glGetShaderInfoLog(shaderId_, 512, NULL, infoLog);
|
||||||
|
shaderLog_ = std::string(infoLog);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
compiled_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LOpenGLShader::compileShaderFromSource(const std::string &source) {
|
||||||
|
if (source.empty() || compiled_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (shaderType_) {
|
||||||
|
case Vertex:
|
||||||
|
shaderId_ = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
break;
|
||||||
|
case Fragment:
|
||||||
|
shaderId_ = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto source_ch = source.c_str();
|
||||||
|
glShaderSource(shaderId_, 1, &source_ch, nullptr);
|
||||||
|
glCompileShader(shaderId_);
|
||||||
|
int success = 0;
|
||||||
|
glGetShaderiv(shaderId_, GL_COMPILE_STATUS, &success);
|
||||||
|
if (!success) {
|
||||||
|
char infoLog[512];
|
||||||
|
glGetShaderInfoLog(shaderId_, 512, nullptr, infoLog);
|
||||||
|
shaderLog_ = std::string(infoLog);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
compiled_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LOpenGLShader::compileShaderFromFile(const std::string &path) {
|
||||||
|
std::string shaderCode;
|
||||||
|
std::fstream shaderFile;
|
||||||
|
std::stringstream shaderStream;
|
||||||
|
|
||||||
|
shaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||||
|
|
||||||
|
try {
|
||||||
|
shaderFile.open(path);
|
||||||
|
shaderStream << shaderFile.rdbuf();
|
||||||
|
shaderFile.close();
|
||||||
|
shaderCode = shaderStream.str();
|
||||||
|
} catch (std::ifstream::failure e) {
|
||||||
|
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shaderCode.empty() || compiled_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (shaderType_) {
|
||||||
|
case Vertex:
|
||||||
|
shaderId_ = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
break;
|
||||||
|
case Fragment:
|
||||||
|
shaderId_ = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto source_ch = shaderCode.c_str();
|
||||||
|
glShaderSource(shaderId_, 1, &source_ch, NULL);
|
||||||
|
glCompileShader(shaderId_);
|
||||||
|
int success = 0;
|
||||||
|
glGetShaderiv(shaderId_, GL_COMPILE_STATUS, &success);
|
||||||
|
if (!success) {
|
||||||
|
char infoLog[512];
|
||||||
|
glGetShaderInfoLog(shaderId_, 512, NULL, infoLog);
|
||||||
|
shaderLog_ = std::string(infoLog);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
compiled_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOpenGLProgram::LOpenGLProgram() : linked_(false) {
|
||||||
|
Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOpenGLProgram::~LOpenGLProgram() {
|
||||||
|
glDeleteProgram(programId_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOpenGLProgram::Create() { programId_ = glCreateProgram(); }
|
||||||
|
|
||||||
|
bool LOpenGLProgram::Link() const {
|
||||||
|
if (!created_ || linked_ || shaderList_.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
glLinkProgram(programId_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOpenGLProgram::Use() const {
|
||||||
|
if (!linked_)
|
||||||
|
return;
|
||||||
|
glUseProgram(programId_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOpenGLProgram::setUniformValue(const std::string &name, float value) const {
|
||||||
|
glUniform1f(glGetUniformLocation(programId_, name.c_str()), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOpenGLProgram::setUniformValue(const std::string &name, int value) const {
|
||||||
|
glUniform1i(glGetUniformLocation(programId_, name.c_str()), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOpenGLProgram::setUniformValue(const std::string &name, bool value) const {
|
||||||
|
glUniform1i(glGetUniformLocation(programId_, name.c_str()), static_cast<int>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOpenGLProgram::setUniformValue(const std::string &name, glm::vec3 value) const {
|
||||||
|
glUniform3fv(glGetUniformLocation(programId_, name.c_str()), 1, &value[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOpenGLProgram::setUniformValue(const std::string &name, float x, float y, float z) const {
|
||||||
|
glUniform3f(glGetUniformLocation(programId_, name.c_str()), x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOpenGLProgram::setUniformValue(const std::string &name, glm::mat4 value) const {
|
||||||
|
glUniform4fv(glGetUniformLocation(programId_, name.c_str()), 1, &value[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LOpenGLProgram::addShader(std::unique_ptr<LOpenGLShader> shader) {
|
||||||
|
if (!shader || !shader->Compiled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!created_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
glAttachShader(programId_, shader->shaderId_);
|
||||||
|
shaderList_.push_back(std::move(shader));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOpenGLProgram::removeShader(GLuint id) {
|
||||||
|
for (auto ite = shaderList_.begin(); ite != shaderList_.end(); ++ite) {
|
||||||
|
if ((*ite)->shaderId_ == id) {
|
||||||
|
glDetachShader(programId_, id);
|
||||||
|
shaderList_.erase(ite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
61
lopenglprogram.h
Normal file
61
lopenglprogram.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glad/glad.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
class LOpenGLProgram;
|
||||||
|
class LOpenGLShader {
|
||||||
|
public:
|
||||||
|
typedef enum ShaderTypeBit {
|
||||||
|
Vertex = 0x0001,
|
||||||
|
Fragment = 0x0002,
|
||||||
|
} ShaderType;
|
||||||
|
LOpenGLShader() = delete;
|
||||||
|
LOpenGLShader(LOpenGLShader::ShaderType type);
|
||||||
|
~LOpenGLShader();
|
||||||
|
bool compileShaderFromSource(const char *source);
|
||||||
|
bool compileShaderFromSource(const std::string &source);
|
||||||
|
bool compileShaderFromFile(const std::string &path);
|
||||||
|
bool Compiled() const { return compiled_; }
|
||||||
|
std::string Log() const { return shaderLog_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
GLuint shaderId_{};
|
||||||
|
std::string shaderSource_;
|
||||||
|
LOpenGLShader::ShaderType shaderType_;
|
||||||
|
bool compiled_;
|
||||||
|
std::string shaderLog_;
|
||||||
|
|
||||||
|
friend class LOpenGLProgram;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LOpenGLProgram {
|
||||||
|
public:
|
||||||
|
LOpenGLProgram();
|
||||||
|
~LOpenGLProgram();
|
||||||
|
|
||||||
|
bool addShader(std::unique_ptr<LOpenGLShader> shader);
|
||||||
|
void removeShader(GLuint id);
|
||||||
|
void Create();
|
||||||
|
bool Link() const;
|
||||||
|
void Use() const;
|
||||||
|
bool Linked() const { return linked_; }
|
||||||
|
|
||||||
|
void setUniformValue(const std::string& name, float value) const;
|
||||||
|
void setUniformValue(const std::string& name, int value) const;
|
||||||
|
void setUniformValue(const std::string& name, bool value) const;
|
||||||
|
void setUniformValue(const std::string& name, glm::vec3 value) const;
|
||||||
|
void setUniformValue(const std::string& name, float x, float y, float z) const;
|
||||||
|
void setUniformValue(const std::string& name, glm::mat4 value) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::list<std::unique_ptr<LOpenGLShader>> shaderList_;
|
||||||
|
GLuint programId_;
|
||||||
|
bool linked_;
|
||||||
|
bool created_;
|
||||||
|
};
|
||||||
61
main.cpp
Normal file
61
main.cpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#include "lopenglprogram.h"
|
||||||
|
#include "camera.h"
|
||||||
|
#include <iostream>
|
||||||
|
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
|
||||||
|
glViewport(0, 0, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_input(GLFWwindow* window) {
|
||||||
|
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
|
||||||
|
glfwSetWindowShouldClose(window, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<LOpenGLProgram> initBackgroundGeometry() {
|
||||||
|
auto vshader = std::make_unique<LOpenGLShader>(LOpenGLShader::ShaderType::Vertex);
|
||||||
|
auto fshader = std::make_unique<LOpenGLShader>(LOpenGLShader::ShaderType::Fragment);
|
||||||
|
vshader->compileShaderFromFile("shader/bg.vert");
|
||||||
|
fshader->compileShaderFromFile("shader/bg.frag");
|
||||||
|
auto program = std::make_unique<LOpenGLProgram>();
|
||||||
|
program->addShader(std::move(vshader));
|
||||||
|
program->addShader(std::move(fshader));
|
||||||
|
auto ret = program->Link();
|
||||||
|
if (!ret)
|
||||||
|
return nullptr;
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
glfwInit();
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||||
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
#if __APPLE__
|
||||||
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
|
||||||
|
if (window == NULL) {
|
||||||
|
std::cout << "Failed to create GLFW window" << std::endl;
|
||||||
|
glfwTerminate();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
glfwMakeContextCurrent(window);
|
||||||
|
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
|
||||||
|
std::cout << "Failed to initialize GLAD" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
glViewport(0, 0, 800, 600);
|
||||||
|
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
||||||
|
|
||||||
|
initBackgroundGeometry();
|
||||||
|
|
||||||
|
|
||||||
|
while (!glfwWindowShouldClose(window)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwTerminate();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
51
shader/bg.frag
Normal file
51
shader/bg.frag
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
uniform vec2 uViewport;
|
||||||
|
uniform float uMajorStep;
|
||||||
|
uniform float uMinorStep;
|
||||||
|
uniform bool uLightMode;
|
||||||
|
|
||||||
|
float gridLine(float stepPx) {
|
||||||
|
vec2 coord = gl_FragCoord.xy;
|
||||||
|
vec2 q = coord / stepPx;
|
||||||
|
|
||||||
|
vec2 q = abs(fract(q - 0.5) - 0.5) / fwidth(stepPx);
|
||||||
|
float line = 1.0 - min(min(q.x, q.y), 1.0);
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 viewport = max(uViewport, vec2(1.0));
|
||||||
|
vec2 uv = gl_FragCoord.xy / viewport;
|
||||||
|
|
||||||
|
vec3 topCol, botCol, majCol, minCol;
|
||||||
|
float majStrength, minStrength;
|
||||||
|
float vignettePow, vignetteStrength;
|
||||||
|
|
||||||
|
topCol = vec3(0.99, 0.99, 1.00);
|
||||||
|
botCol = vec3(0.94, 0.95, 0.98);
|
||||||
|
|
||||||
|
minorCol = vec3(0.80, 0.82, 0.87);
|
||||||
|
majorCol = vec3(0.70, 0.73, 0.80);
|
||||||
|
|
||||||
|
minorStrength = 0.22;
|
||||||
|
majorStrength = 0.35;
|
||||||
|
vignettePow = 0.12;
|
||||||
|
vignetteStrength = 0.35;
|
||||||
|
|
||||||
|
vec3 col = mix(botCol, topCol, uv.y);
|
||||||
|
float minor = gridLine(max(uMinorStep, 1.0));
|
||||||
|
float major = gridLine(max(uMajorStep, 1.0));
|
||||||
|
|
||||||
|
col = mix(col, minorCol, minStrength * minor);
|
||||||
|
col = mix(col, majorCol, majStrength * major);
|
||||||
|
|
||||||
|
vec2 p = uv * 2.0 - 1.0;
|
||||||
|
float v = clamp(1.0 - dot(p, p) * 0.12 , 0.0, 1.0);
|
||||||
|
col *= mix(1.0, v, 0.35);
|
||||||
|
|
||||||
|
FragColor = vec4(col, 1.0);
|
||||||
|
}
|
||||||
7
shader/bg.vert
Normal file
7
shader/bg.vert
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 aPos;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(aPos, 0.0, 1.0);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user