当前位置: 首页 > article >正文

第一个3D程序!

 运行效果

CPP

#include <iostream>
#include <fstream>
#include <string>
#include <cmath>

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <soil2/SOIL2.h>

#define PI 3.14159f

#define numVAOs 1
#define numVBOs 128

#define SPEED 0.1f
#define ANGLE 0.01f

using namespace std;

GLuint rendering_program;
GLuint vao[numVAOs];
GLuint vbo[numVBOs];
GLuint vbo_count = 0;
GLuint mvloc, ploc, nloc;
GLuint clr_loc;
GLuint global_amb_loc, dirlight_amb_loc, dirlight_dif_loc, dirlight_dir_loc;

int HEIGHT = 724, WIDTH = 1024;
float aspect = (float)WIDTH / (float)HEIGHT;

glm::vec4 GlobalAmbient = { 0.6f, 0.6f, 0.6f, 1.0f };	//全局环境光
glm::vec4 DirLightAmbient = { 0.2f, 0.2f, 0.2f, 1.0f };	//定向光:环境特征
glm::vec4 DirLightDiffuse = { 0.5f, 0.5f, 0.5f, 1.0f };
glm::vec3 DirLightDirection = { -1.0f, -1.732f, 0.0f };

glm::mat4 tmat;											//平移
glm::mat4 rmat;											//旋转
glm::mat4 vmat;											//t_mat * r_mat
glm::mat4 pmat;											//透视
glm::mat4 mvmat;
glm::mat4 invmat;										//mv矩阵的逆

struct Camera {
	float x, y, z;
	float theta, fine;
}camera;

struct Tetrahedron {
	GLuint vbo_index[2] = { 0 };
	glm::vec3 position = { 0.0f, 0.0f, 0.0f };
	float vertex_positions[36] = {
		0.0f, -0.408f, 1.155f, -1.0f, -0.408f, -0.577f, 1.0f, -0.408f, -0.577f,
		0.0f, -0.408f, 1.155f, 0.0f, 1.225f, 0.0f, -1.0f, -0.408f, -0.577f,
		0.0f, -0.408f, 1.155f, 1.0f, -0.408f, -0.577f, 0.0f, 1.225f, 0.0f,
		-1.0f, -0.408f, -0.577f, 0.0f, 1.225f, 0.0f, 1.0f, -0.408f, -0.577f
	};
	float vertex_normal[36] = {
		0.0f, 1.225f, 0.0f, 0.0f, 1.225f, 0.0f, 0.0f, 1.225f, 0.0f,
		1.0f, -0.408f, -0.577f, 1.0f, -0.408f, -0.577f, 1.0f, -0.408f, -0.577f,
		-1.0f, -0.408f, -0.577f, -1.0f, -0.408f, -0.577f, -1.0f, -0.408f, -0.577f,
		0.0f, -0.408f, 1.155f, 0.0f, -0.408f, 1.155f, 0.0f, -0.408f, 1.155f
	};
	void init(float x, float y, float z) {
		vbo_index[0] = vbo_count++;
		vbo_index[1] = vbo_count++;
		position = { x, y, z };
		glBindBuffer(GL_ARRAY_BUFFER, vbo[vbo_index[0]]);
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_positions), vertex_positions, GL_STATIC_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, vbo[vbo_index[1]]);
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_normal), vertex_normal, GL_STATIC_DRAW);
	}
}tetrahedron;
struct Plane {
	GLuint vbo_index[2] = { 0 };
	glm::vec3 position = { 0.0f, 0.0f, 0.0f };
	float vertex_positions[18] = {
		0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
		1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f
	};
	float vertex_normal[18] = {
		0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
		0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f
	};
	void init(float x, float y, float z) {
		vbo_index[0] = vbo_count++;
		vbo_index[1] = vbo_count++;
		position = { x, y, z };
		glBindBuffer(GL_ARRAY_BUFFER, vbo[vbo_index[0]]);
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_positions), vertex_positions, GL_STATIC_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, vbo[vbo_index[1]]);
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_normal), vertex_normal, GL_STATIC_DRAW);
	}
}plane;

string ReadShaderSource(const char* file_path) {
	string content;
	string line = "";
	ifstream file_stream(file_path, ios::in);
	while (!file_stream.eof()) {
		getline(file_stream, line);
		content.append(line + "\n");
	}
	file_stream.close();
	return content;
}
void PrintShaderLog(GLuint shader) {
	int len = 0;
	int ch_writtn = 0;
	char* log;
	glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
	if (len > 0) {
		log = (char*)malloc(len);
		glGetShaderInfoLog(shader, len, &ch_writtn, log);
		cout << "Shader Info Log:" << log << endl;
		free(log);
	}
}
void PrintProgramLog(GLuint program) {
	int len = 0;
	int ch_writtn = 0;
	char* log;
	glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
	if (len > 0) {
		log = (char*)malloc(len);
		glGetProgramInfoLog(program, len, &ch_writtn, log);
		cout << "Program Info Log:" << log << endl;
		free(log);
	}
}
bool CheckOpenGLError() {
	bool found_error = false;
	int glerr = glGetError();
	while (glerr != GL_NO_ERROR) {
		cout << "GL ERROR:" << glerr << endl;
		found_error = true;
		glerr = glGetError();
	}
	return found_error;
}
GLuint CreateShaderProgram() {
	GLuint vshader = glCreateShader(GL_VERTEX_SHADER);
	GLuint fshader = glCreateShader(GL_FRAGMENT_SHADER);
	GLint vert_compiled;
	GLint frag_compiled;
	GLint linked;
	string vert_shader_string = ReadShaderSource("vert_shader.glsl");
	string frag_shader_string = ReadShaderSource("frag_shader.glsl");
	const char* vert_shader_source = vert_shader_string.c_str();
	const char* frag_shader_source = frag_shader_string.c_str();
	glShaderSource(vshader, 1, &vert_shader_source, NULL);
	glShaderSource(fshader, 1, &frag_shader_source, NULL);
	glCompileShader(vshader);
	CheckOpenGLError();
	glGetShaderiv(vshader, GL_COMPILE_STATUS, &vert_compiled);
	if (vert_compiled != 1) {
		cout << "vertex compilation failed" << endl;
		PrintShaderLog(vshader);
	}
	glCompileShader(fshader);
	CheckOpenGLError();
	glGetShaderiv(fshader, GL_COMPILE_STATUS, &frag_compiled);
	if (frag_compiled != 1) {
		cout << "fragment compilation failed" << endl;
		PrintShaderLog(fshader);
	}
	GLuint program = glCreateProgram();
	glAttachShader(program, vshader);
	glAttachShader(program, fshader);
	glLinkProgram(program);
	CheckOpenGLError();
	glGetProgramiv(program, GL_LINK_STATUS, &linked);
	if (linked != 1) {
		cout << "linking failed" << endl;
		PrintProgramLog(program);
	}
	return program;
}
GLuint LoadTexture(const char* ImagePath) {
	GLuint textureID;
	textureID = SOIL_load_OGL_texture(ImagePath, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
	if (textureID == 0) cout << "could not find texture file:" << ImagePath << endl;
	return textureID;
}
void init(GLFWwindow* window) {
	vmat = glm::mat4(1.0f);
	rmat = glm::mat4(1.0f);
	pmat = glm::perspective(1.3f, aspect, 0.1f, 1000.0f);
	rendering_program = CreateShaderProgram();
	glGenVertexArrays(numVAOs, vao);
	glBindVertexArray(vao[0]);
	glGenBuffers(numVBOs, vbo);
	tetrahedron.init(4.0f, 4.0f, 4.0f);
	plane.init(0.0f, 0.0f, 0.0f);
}
void MoveCamera(GLFWwindow* window) {
	bool translate = false;
	bool rotato = false;
	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
		camera.x -= (float)sin(camera.theta) * SPEED;
		camera.z -= (float)cos(camera.theta) * SPEED;
		translate = true;
	}
	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
		camera.x += (float)sin(camera.theta) * SPEED;
		camera.z += (float)cos(camera.theta) * SPEED;
		translate = true;
	}
	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
		camera.x -= (float)cos(camera.theta) * SPEED;
		camera.z += (float)sin(camera.theta) * SPEED;
		translate = true;
	}
	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
		camera.x += (float)cos(camera.theta) * SPEED;
		camera.z -= (float)sin(camera.theta) * SPEED;
		translate = true;
	}
	if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) {
		camera.y += SPEED;
		translate = true;
	}
	if (glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS) {
		camera.y -= SPEED;
		translate = true;
	}
	if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {
		if (camera.fine < PI / 2.0) {
			camera.fine += ANGLE;
			rotato = true;
		}
	}
	if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) {
		if (camera.fine > -PI / 2.0) {
			camera.fine -= ANGLE;
			rotato = true;
		}
	}
	if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) {
		camera.theta += ANGLE;
		rotato = true;
	}
	if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) {
		camera.theta -= ANGLE;
		rotato = true;
	}
	if (translate) tmat = glm::translate(glm::mat4(1.0f), glm::vec3(-camera.x, -camera.y, -camera.z));
	if (rotato) rmat = {
		{ cos(camera.theta)  , sin(camera.fine) * sin(camera.theta), cos(camera.fine) * sin(camera.theta), 0.0f },
		{ 0.0f				 , cos(camera.fine)					 , -sin(camera.fine)				   , 0.0f },
		{ -sin(camera.theta) , sin(camera.fine) * cos(camera.theta), cos(camera.fine) * cos(camera.theta), 0.0f },
		{ 0.0f				 , 0.0f								 , 0.0f								   , 1.0f }
	};
	if (translate || rotato) vmat = rmat * tmat;
}
void WindowReshapeCallback(GLFWwindow* window, int new_width, int new_height) {
	WIDTH = new_width;
	HEIGHT = new_height;
	aspect = (float)WIDTH / (float)HEIGHT;
	pmat = glm::perspective(1.3f, aspect, 0.1f, 1000.0f);
	glViewport(0, 0, WIDTH, HEIGHT);
}
void InstallLight() {
	global_amb_loc = glGetUniformLocation(rendering_program, "GlobalAmbient");
	dirlight_amb_loc = glGetUniformLocation(rendering_program, "DirLightAmbient");
	dirlight_dif_loc = glGetUniformLocation(rendering_program, "DirLightDiffuse");
	dirlight_dir_loc = glGetUniformLocation(rendering_program, "DirLightDirection");
	glProgramUniform4fv(rendering_program, global_amb_loc, 1, glm::value_ptr(GlobalAmbient));
	glProgramUniform4fv(rendering_program, dirlight_amb_loc, 1, glm::value_ptr(DirLightAmbient));
	glProgramUniform4fv(rendering_program, dirlight_dif_loc, 1, glm::value_ptr(DirLightDiffuse));
	glProgramUniform3fv(rendering_program, dirlight_dir_loc, 1, glm::value_ptr(DirLightDirection));
}
void display(GLFWwindow* window, double curretTime) {
	glClear(GL_DEPTH_BUFFER_BIT);
	glClear(GL_COLOR_BUFFER_BIT);
	glUseProgram(rendering_program);
	InstallLight();
	mvloc = glGetUniformLocation(rendering_program, "mvmat");
	ploc = glGetUniformLocation(rendering_program, "pmat");
	nloc = glGetUniformLocation(rendering_program, "nmat");
	clr_loc = glGetUniformLocation(rendering_program, "texture_color");
	glDisable(GL_CULL_FACE);
	for (int x = -32; x < 32; x++)
		for (int z = -32; z < 32; z++) {
			glm::vec4 texture_color(0.0f, 0.0f, 1.0f, 1.0f);
			glm::mat4 mmat_p = glm::translate(glm::mat4(1.0f), glm::vec3((float)x, 0.0f, (float)z));
			if ((x + z) & 1) texture_color = { 0.0f, 1.0f, 0.0f, 1.0f };
			mvmat = vmat * mmat_p;
			invmat = glm::transpose(glm::inverse(mvmat));
			glUniformMatrix4fv(mvloc, 1, GL_FALSE, glm::value_ptr(mvmat));
			glUniformMatrix4fv(ploc, 1, GL_FALSE, glm::value_ptr(pmat));
			glUniformMatrix4fv(nloc, 1, GL_FALSE, glm::value_ptr(invmat));
			glUniform4fv(clr_loc, 1, glm::value_ptr(texture_color));
			glBindBuffer(GL_ARRAY_BUFFER, vbo[plane.vbo_index[0]]);
			glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
			glEnableVertexAttribArray(0);
			glBindBuffer(GL_ARRAY_BUFFER, vbo[plane.vbo_index[1]]);
			glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
			glEnableVertexAttribArray(1);
			glEnable(GL_DEPTH_TEST);
			glDepthFunc(GL_LEQUAL);
			glDrawArrays(GL_TRIANGLES, 0, 6);
		}
	glEnable(GL_CULL_FACE);
	glm::mat4 mmat_t = glm::translate(glm::mat4(1.0f), tetrahedron.position);
	mvmat = vmat * mmat_t;
	invmat = glm::transpose(glm::inverse(mvmat));
	glUniformMatrix4fv(mvloc, 1, GL_FALSE, glm::value_ptr(mvmat));
	glUniformMatrix4fv(ploc, 1, GL_FALSE, glm::value_ptr(pmat));
	glUniformMatrix4fv(nloc, 1, GL_FALSE, glm::value_ptr(invmat));
	glUniform4fv(clr_loc, 1, glm::value_ptr(glm::vec4(1.0f, 0.0f, 0.0f, 1.0f)));
	glBindBuffer(GL_ARRAY_BUFFER, vbo[tetrahedron.vbo_index[0]]);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, vbo[tetrahedron.vbo_index[1]]);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(1);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glDrawArrays(GL_TRIANGLES, 0, 12);
}
int main() {
	if (!glfwInit()) { exit(EXIT_FAILURE); }
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "HelloWorld", NULL, NULL);
	glfwMakeContextCurrent(window);
	if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); }
	glfwSwapInterval(1);
	glfwSetWindowSizeCallback(window, WindowReshapeCallback);

	init(window);

	while (!glfwWindowShouldClose(window)) {
		MoveCamera(window);
		display(window, glfwGetTime());
		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glfwDestroyWindow(window);
	glfwTerminate();
	exit(EXIT_SUCCESS);
}

顶点着色器

#version 430

layout (location=0) in vec3 position;
layout (location=1) in vec3 normal;

out vec3 varying_normal;
out vec3 varying_direction;

uniform mat4 mvmat;
uniform mat4 pmat;
uniform mat4 nmat;
uniform vec4 texture_color;
h
uniform vec4 GlobalAmbient;
uniform vec4 DirLightAmbient;
uniform vec4 DirLightDiffuse;
uniform vec3 DirLightDirection;

void main(void) {
	varying_normal = (nmat * vec4(normal, 1.0)).xyz;
	varying_direction = (nmat * vec4(DirLightDirection, 1.0)).xyz;
	gl_Position = pmat * mvmat * vec4(position, 1.0);
}

片段着色器

#version 430

in vec3 varying_normal;
in vec3 varying_direction;

out vec4 color;

uniform mat4 mvmat;
uniform mat4 pmat;
uniform mat4 nmat;
uniform vec4 texture_color;

uniform vec4 GlobalAmbient;
uniform vec4 DirLightAmbient;
uniform vec4 DirLightDiffuse;
uniform vec3 DirLightDirection;

void main(void) {
	vec3 L = normalize(varying_direction);
	vec3 N = normalize(varying_normal);
	float cos_theta = dot(L, N);
	vec3 ambient = GlobalAmbient.xyz * texture_color.xyz + DirLightAmbient.xyz * texture_color.xyz;
	vec3 diffuse = texture_color.xyz * DirLightDiffuse.xyz * max(cos_theta, 0.0);
	color = vec4(ambient + diffuse, 1.0);
}


http://www.kler.cn/a/523402.html

相关文章:

  • 乌兰巴托的夜---音乐里的故事
  • 1.27补题 回训练营
  • Ollama 运行从 ModelScope 下载的 GGUF 格式的模型
  • [MySQL]事务的理论、属性与常见操作
  • 世上本没有路,只有“场”et“Bravo”
  • 关于使用Mybatis-plus的TableNameHandler动态表名处理器实现分表业务的详细介绍
  • 在虚拟机里运行frida-server以实现对虚拟机目标软件的监测和修改参数(一)(android Google Api 35高版本版)
  • 借DeepSeek-R1东风,开启创业新机遇
  • nosql mysql的区别
  • SQL server 数据库使用整理
  • 实时数据处理与模型推理:利用 Spring AI 实现对数据的推理与分析
  • 29. 【.NET 8 实战--孢子记账--从单体到微服务】--项目发布
  • 如何保证缓存与数据库的数据一致性?
  • 《多线程基础之条件变量》
  • @RestControllerAdvice 的作用
  • 【信息系统项目管理师-选择真题】2010下半年综合知识答案和详解
  • C#面试常考随笔5:简单讲述下反射
  • 腾讯云开发提供免费GPU服务
  • 大数运算:整数、小数的加减乘除与取余乘方(c++实现)
  • 我们需要有哪些知识体系,知识体系里面要有什么哪些内容?
  • 面试被问的一些问题汇总(持续更新)
  • Python帝王學集成-母稿
  • 【开源免费】基于Vue和SpringBoot的在线文档管理系统(附论文)
  • AIGC常见基础概念
  • DeepSeek R1学习
  • 27.日常算法