计算机图形学练习(四)——画球

以线框模式画一个球,可由鼠标键盘控制

ball.cpp
#include <iostream>

// GLEW
#define GLEW_STATIC
#include <GL/glew.h>

// GLFW
#include <GLFW/glfw3.h>

//glm
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "glm/gtx/rotate_vector.hpp"        //直接对点进行操作

//头文件
#include "Shader.h"
#include "Camera.h"

//SOIL
#include "SOIL2/SOIL2.h"
#include "SOIL2/stb_image.h"


const GLint WIDTH = 600, HEIGHT = 600;

void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mode);
void MouseCallback(GLFWwindow* window, double xPos, double yPos);
void DoMovement();
void DoMovement_Model();
//void ScrollCallback(GLFWwindow* window, double xPos, double yPos);
void ScrollCallback(GLFWwindow* window, double xOffset, double yOffset);

bool keys[1024];        //记录所有按键信息
//计算鼠标自上一帧的偏移量。我们必须先在程序中储存上一帧的鼠标位置,
//我们把它的初始值设置为屏幕的中心(屏幕的尺寸是800x600);

GLfloat lastX = WIDTH / 2.0f;
GLfloat lastY = HEIGHT / 2.0f;
bool firstMouse = true;

Camera camera(glm::vec3(0.0f, 0.0f, 2.0f));
GLfloat deltaTime = 0.0f;
GLfloat lastTime = 0.0f;

//glm::vec3 lightPos = glm::vec3(0.0f, 0.0f, 0.0f);

const GLfloat PI = 3.14159265358979323846f;
//将球横纵划分成50*50的网格
const int Y_SEGMENTS = 50;
const int X_SEGMENTS = 50;

float Model_front = 0.0f;
float Model_right = 0.0f;
float Model_height = 0.0f;
float temp = 0.0f;

int main()
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "ball", nullptr, nullptr);

    // retina display
    int screenWidth, screenHeight;
    glfwGetFramebufferSize(window, &screenWidth, &screenHeight);

    if (window == nullptr) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);

    glfwSetKeyCallback(window, KeyCallback);    //接收键盘传来的信息
    glfwSetCursorPosCallback(window, MouseCallback);


    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK) {
        std::cout << "Failed to initialize GLEW" << std::endl;
        glfwTerminate();
        return -1;
    }

    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);    // tell GLFW to capture our mouse
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_DEPTH_TEST);    //开启深度测试,深度信息小的可以覆盖深度信息大的,也就是说,符合人体观察事物的透视特征,前面的将覆盖后面的
    glDepthFunc(GL_LESS);
    glfwSetScrollCallback(window, ScrollCallback);

    Shader shader = Shader("res/shaders/core.vs", "res/shaders/core.fs");

    //Sphere
    std::vector<float> sphereVertices;
    std::vector<int> sphereIndices;

    //计算球体的顶点
    //生成顶点
    for (int y = 0; y <= Y_SEGMENTS; y++) {
        for (int x = 0; x <= X_SEGMENTS; x++) {
            float xSegment = (float)x / (float)X_SEGMENTS;
            float ySegment = (float)y / (float)Y_SEGMENTS;
            float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
            float yPos = std::cos(ySegment * PI);
            float zPos = std::sin(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
            sphereVertices.push_back(xPos);
            sphereVertices.push_back(yPos);
            sphereVertices.push_back(zPos);
        }
    }

    //生成球体的Indices
    for (int i = 0; i < Y_SEGMENTS; i++) {
        for (int j = 0; j < X_SEGMENTS; j++) {
            sphereIndices.push_back(i * (X_SEGMENTS + 1) + j);
            sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j);
            sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j + 1);
            sphereIndices.push_back(i * (X_SEGMENTS + 1) + j);
            sphereIndices.push_back((i + 1) * (X_SEGMENTS + 1) + j + 1);
            sphereIndices.push_back(i * (X_SEGMENTS + 1) + j + 1);
        }
    }

    //------------------------------------------------------------------

    GLuint VAO, VBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sphereVertices.size() * sizeof(float), &sphereVertices[0], GL_STATIC_DRAW);

    GLuint element_buffer_object; //EBO
    glGenBuffers(1, &element_buffer_object);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_buffer_object);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(int), &sphereIndices[0], GL_STATIC_DRAW);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // 解绑VAO和VBO
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    //------------------------------------------------------------------

    while (!glfwWindowShouldClose(window)) {
        GLfloat currentTime = glfwGetTime();
        deltaTime = currentTime - lastTime;
        lastTime = currentTime;
        glViewport(0, 0, screenWidth, screenHeight);
        glfwPollEvents();       //接收所有得到的信息

        DoMovement();       //接收到信息后做运动
        DoMovement_Model();
        //render
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        shader.Use();
        //activate shader
        //绘制球
        //开启面剔除(只需要展示一个面,否则会有重合)
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glBindVertexArray(VAO);
        //使用线框模式绘制
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        glDrawElements(GL_TRIANGLES, X_SEGMENTS * Y_SEGMENTS * 6, GL_UNSIGNED_INT, 0);

        glm::mat4 view = camera.GetViewMatrix();
        glm::mat4 projection = glm::perspective(glm::radians(camera.GetZoom()), static_cast<GLfloat>(screenWidth) /
            static_cast<GLfloat>(screenHeight), 0.1f, 100.0f);

        //后生成
        shader.Use();

        glm::mat4 transform = glm::mat4(1.0f);  //生成矩阵

        //GLfloat currentTime_rn = currentTime;
        transform = glm::translate(transform, glm::vec3(Model_right, Model_height, Model_front));//平移
        if (keys[GLFW_KEY_SPACE]) {
            Model_height = temp;//回到原来的位置
        }

        transform = glm::scale(transform, glm::vec3(0.5f, 0.5f, 0.5f));  //缩放

        GLuint transLoc = glGetUniformLocation(shader.Program, "transform");
        glUniformMatrix4fv(transLoc, 1, GL_FALSE, glm::value_ptr(transform));

        GLuint viewLoc = glGetUniformLocation(shader.Program, "view");
        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));

        GLuint proLoc = glGetUniformLocation(shader.Program, "projection");
        glUniformMatrix4fv(proLoc, 1, GL_FALSE, glm::value_ptr(projection));

        //glUniform3f(glGetUniformLocation(shader.Program, "LightPos"),
         //   lightPos.x, lightPos.y, lightPos.z);
        glUniform3f(glGetUniformLocation(shader.Program, "ViewPos"),
            camera.GetPosition().x, camera.GetPosition().y, camera.GetPosition().z);


        glfwSwapBuffers(window);
    }
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &element_buffer_object);

    glfwTerminate();
    return 0;
}

//------------------------------------------------------------------



void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
    {
        glfwSetWindowShouldClose(window, GL_TRUE);
    }
    if (key >= 0 && key < 1024) {
        if (action == GLFW_PRESS) {
            keys[key] = true;

        }
        else if (action == GLFW_RELEASE)
        {
            keys[key] = false;
        }
    }
}


void MouseCallback(GLFWwindow* window, double xPos, double yPos)
{
    if (firstMouse) {  //只有第一次才把鼠标的初始位置更新为 xPos 和 yPos 值
        lastX = xPos;
        lastY = yPos;
        firstMouse = false;
    }

    GLfloat xOffset = xPos - lastX;
    GLfloat yOffset = lastY - yPos;

    lastX = xPos;
    lastY = yPos;

    //Do something
    camera.ProcessMouseMovement(xOffset, yOffset);
}

void DoMovement()
{
    if (keys[GLFW_KEY_W]) {
        //up
        //printf("w");
        camera.ProcessKeyboard(FOWARD, deltaTime);
    }
    if (keys[GLFW_KEY_S]) {
        //down
        camera.ProcessKeyboard(BACKWARD, deltaTime);
    }
    if (keys[GLFW_KEY_A]) {
        //left
        camera.ProcessKeyboard(LEFT, deltaTime);
    }
    if (keys[GLFW_KEY_D]) {
        //right
        camera.ProcessKeyboard(RIGHT, deltaTime);
    }
}



void DoMovement_Model() {
    if (keys[GLFW_KEY_UP])
        //Model_height += deltaTime;
        Model_height += 0.001;

    if (keys[GLFW_KEY_DOWN])
        //Model_height -= deltaTime;
        Model_height -= 0.001;

    if (keys[GLFW_KEY_LEFT])
        Model_right -= 0.001;

    if (keys[GLFW_KEY_RIGHT])
        Model_right += 0.001;

    if (keys[GLFW_KEY_SPACE]) {
        temp = Model_height;
        Model_height += 0.5;
    }
}

void ScrollCallback(GLFWwindow* window, double xOffset, double yOffset) {
    camera.ProcessScroll(yOffset);
}
Shader.h
#pragma once

#include <string.h>
#include <fstream>
#include <sstream>
#include <iostream>

#include <GL/glew.h>

class Shader
{
	GLuint vertex, fragment;
public:
	GLuint Program;
	Shader(const GLchar* vertexPath, const GLchar* fragmentPath)
	{
		std::string vertexCode;
		std::string fragmentCode;
		std::ifstream vShaderFile;
		std::ifstream fShaderFile;

		vShaderFile.exceptions(std::ifstream::badbit);
		fShaderFile.exceptions(std::ifstream::badbit);

		try
		{
			vShaderFile.open(vertexPath);
			fShaderFile.open(fragmentPath);

			std::stringstream vShaderStream, fShaderStream;
			vShaderStream << vShaderFile.rdbuf();
			fShaderStream << fShaderFile.rdbuf();

			vShaderFile.close();
			fShaderFile.close();

			vertexCode = vShaderStream.str();
			fragmentCode = fShaderStream.str();

		}
		catch (std::ifstream::failure e)
		{
			std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ" << std::endl;
		}
		const GLchar* vShaderCode = vertexCode.c_str();
		const GLchar* fShaderCode = fragmentCode.c_str();

		//compile Shaders
		GLint success;
		GLchar infoLog[512];
		vertex = glCreateShader(GL_VERTEX_SHADER);
		glShaderSource(vertex, 1, &vShaderCode, NULL);
		glCompileShader(vertex);

		glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
		if (!success) {
			glGetShaderInfoLog(vertex, 512, NULL, infoLog);
			std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n"
				<< infoLog << std::endl;
		}

		fragment = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fragment, 1, &fShaderCode, NULL);
		glCompileShader(fragment);

		glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
		if (!success) {
			glGetShaderInfoLog(fragment, 512, NULL, infoLog);
			std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n"
				<< infoLog << std::endl;
		}

		this ->Program = glCreateProgram();
		glAttachShader(this->Program, vertex);
		glAttachShader(this->Program, fragment);
		glLinkProgram(this->Program);

		glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
		if (!success) {
			glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
			std::cout << "ERROR::SHADER::PROGRAM::LINK_FAILED\n"
				<< infoLog << std::endl;
		}
	}
	~Shader() {
		glDetachShader(this->Program, vertex);
		glDetachShader(this->Program, fragment);
		glDeleteShader(vertex);
		glDeleteShader(fragment);
		glDeleteProgram(this->Program);
	}
	void Use()
	{
		glUseProgram(this->Program);
	}
};
Camera.h
#pragma once

#include<vector>

#define GLEW_STATIC
#include<GL/glew.h>

#include"glm/glm.hpp"
#include"glm/gtc/matrix_transform.hpp"

enum Camera_Movement                           //定义四个方向
{
	FOWARD,
	BACKWARD,
	LEFT,
	RIGHT
};

const GLfloat YAW = -90.0f;
const GLfloat PITCH = 0.0f;
const GLfloat SPEED = 6.0f;
const GLfloat SENSITIVITY = 0.1f;
const GLfloat ZOOM = 45.0f;

class Camera
{
public:
	Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), GLfloat yaw = YAW, GLfloat pitch = PITCH)
		:front(glm::vec3(0.0f, 0.0f, -1.0f)), movementSpeed(SPEED), mouseSensitivity(SENSITIVITY), zoom(ZOOM)
	{
		this->position = position;
		this->worldUp = up;
		this->yaw = yaw;
		this->pitch = pitch;
		this->updateCameraVectors();

	}
	Camera(GLfloat posX, GLfloat posY, GLfloat posZ, GLfloat upX, GLfloat upY, GLfloat upZ, GLfloat yaw = YAW, GLfloat pitch = PITCH)
		:front(glm::vec3(0.0f, 0.0f, -1.0f)), movementSpeed(SPEED), mouseSensitivity(SENSITIVITY), zoom(ZOOM)
	{
		this->position = glm::vec3(posX, posY, posZ);
		this->worldUp = glm::vec3(upX, upY, upZ);
		this->yaw = yaw;
		this->pitch = pitch;
		this->updateCameraVectors();
	}
	void ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime)
	{
		GLfloat velocity = this->movementSpeed * deltaTime;
		if (direction == FOWARD)										//键盘控制向前移动
		{
			this->position += this->front * velocity;
		}
		if (direction == BACKWARD)										//键盘控制向后移动
		{
			this->position -= this->front * velocity;
		}
		if (direction == LEFT)											//键盘控制向左移动
		{
			this->position -= this->right * velocity;
		}
		if (direction == RIGHT)										    //键盘控制向右移动
		{
			this->position += this->right * velocity;
		}
	}
	void ProcessMouseMovement(GLfloat xOffset, GLfloat yOffset)
	{
		xOffset *= this->mouseSensitivity;								//计算鼠标偏移量
		yOffset *= this->mouseSensitivity;

		this->yaw += xOffset;
		this->pitch += yOffset;

		this->updateCameraVectors();
	}
	void ProcessScroll(GLfloat yOffset)
	{
		this->zoom += yOffset;
	}
	GLfloat GetZoom()
	{
		return this->zoom;
	}
	glm::mat4 GetViewMatrix()
	{
		return glm::lookAt(this->position, this->position + this->front, this->up);
	}
	glm::vec3 GetPosition()
	{
		return this->position;
	}
private:
	GLfloat yaw;
	GLfloat pitch;
	GLfloat movementSpeed;
	GLfloat mouseSensitivity;
	GLfloat zoom;

	glm::vec3 position;       //相机位置
	//相机朝向,三个朝向可以设置相机坐标系
	glm::vec3 front;
	glm::vec3 up;
	glm::vec3 right;
	glm::vec3 worldUp;
	void updateCameraVectors()   //更新相机视角
	{
		glm::vec3 front;
		front.x = cos(glm::radians(this->pitch)) * cos(glm::radians(this->yaw));	 //x为两个cos相乘
		front.y = sin(glm::radians(this->pitch));                                    //y用sin算
		front.z = cos(glm::radians(this->pitch)) * sin(glm::radians(this->yaw));	 //z为两个cos相乘
		//构建坐标系
		this->front = glm::normalize(front);
		this->right = glm::normalize(glm::cross(this->front, this->worldUp));		 //normalize为标准化,cross为叉乘
		this->up = glm::normalize(glm::cross(this->right, this->front));

	}
};
core.vs
#version 330 core
layout(location = 0) in vec3 position;
//layout(location = 1) in vec3 color;
//layout(location = 2) in vec3 normal;

uniform mat4 transform;
uniform mat4 view;
uniform mat4 projection;

//out vec3 ourColor;
//varying vec3 Normal;
//varying vec3 FragPos;

void main(){
//从右向左乘:先乘 transform,最后乘 projection,这是重点中的重点,因为是矩阵相乘,交换律不成立!!!
    gl_Position = projection * view * transform * vec4(position, 1.0f);
}

core.fs
#version 330 core
//in vec3 ourColor;
out vec4 color;

void main(){
    color = vec4(1.0f, 0.635f, 0.345f, 1.0f);  
}

运行结果

在这里插入图片描述

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值