OpenGL(可编程管线):Bezier曲面
Bezier曲面
- Bezier線
- de Casteljau算法
- Bezier曲面
- bezier曲面編程思想
- 實(shí)例
- 代碼
- 運(yùn)行結(jié)果
Bezier線
貝塞爾曲線由一組參數(shù)方程定義,方程組中使用控制點(diǎn)指定特定的曲線的形狀,每個(gè)控制點(diǎn)都是2D空間中的一個(gè)點(diǎn)。
de Casteljau算法
其中B(t)為Bernstein多項(xiàng)式,另外了解,這里不做解釋(主要是沒(méi)有深入研究…)。
此圖來(lái)自《計(jì)算機(jī)圖形學(xué)編程(使用OpenGL和C++)》
Bezier曲面
Bezier曲面定義了3D空間中的曲面,從Bezier曲線拓展,需要將bezier曲線的參數(shù)方程從一個(gè)參數(shù)拓展為兩個(gè)參數(shù)。對(duì)于bezier曲線參數(shù)為t,在bezier曲面中參數(shù)為u和v。曲面的點(diǎn)由P(u, v)組成。
此圖來(lái)自《計(jì)算機(jī)圖形學(xué)編程(使用OpenGL和C++)》,此圖為二次bezier曲面,有9個(gè)控制點(diǎn)
此時(shí)的參數(shù)方程為:
bezier曲面編程思想
我們將曲面橫豎分別分成m,n份,那么曲面分成了m×n份,我們可以通過(guò)繪制m×n份近似矩形,就可以模擬出bezier曲面
實(shí)例
以三次bezier曲面為例:
假如我把bezier曲面分成了6×6塊,如下圖
在圖中我們可以清晰的看出u,v坐標(biāo)每次的增量是1/6,我們只要算出(u,v)坐標(biāo)所在處的坐標(biāo)就可以繪制出所需要的bezier曲面。
代碼
構(gòu)建bezier曲面類
#pragma once #include <vector> #include <glm/glm.hpp> using namespace std;class BezierFace {//頂點(diǎn)個(gè)數(shù)int numVertices;//索引個(gè)數(shù)int numIndices;//頂點(diǎn)vector<glm::vec3> vertices;//法線vector<glm::vec3> normals;//紋理vector<glm::vec2> texCoords;//索引vector<int> indices;//計(jì)算數(shù)據(jù)void init(int prec);//控制點(diǎn)float* controlPoints;vector<glm::vec3> controlPointsVector;//曲線階數(shù)int step;float toRadians(float degrees);float Bernstein(float u, int index); public:BezierFace();BezierFace(int step, float controlPoints[], int prec);int getNumVertices();int getNumIndices();vector<glm::vec3> getVertices();vector<glm::vec3> getNormals();vector<glm::vec2> getTexCoords();vector<int> getIndices();}; #include "BezierFace.h"void BezierFace::init(int prec) {numVertices = (prec + 1) * (prec + 1);numIndices = prec * prec * 6;for (int i = 0; i < numVertices; i++){vertices.push_back(glm::vec3());normals.push_back(glm::vec3());texCoords.push_back(glm::vec2());}for (int i = 0; i < numIndices; i++){indices.push_back(0);}for (int i = 0; i < (step + 1) * (step + 1) * 3; i += 3){controlPointsVector.push_back(glm::vec3(controlPoints[i], controlPoints[i + 1], controlPoints[i + 2]));}for (int i = 0; i <= prec; i++){for (int j = 0; j <= prec; j++){float x = 0.0f;float y = 0.0f;float z = 0.0f;float u = (float)i / prec;float v = (float)j / prec;for (int i = 0; i <= 3; i++){for (int j = 0; j <= 3; j++){int index = i * 4 + j;x += controlPointsVector[index].x * Bernstein(u, i) * Bernstein(v, j);y += controlPointsVector[index].y * Bernstein(u, i) * Bernstein(v, j);z += controlPointsVector[index].z * Bernstein(u, i) * Bernstein(v, j);}}vertices[i * (prec + 1) + j] = glm::vec3(x, y, z);normals[i * (prec + 1) + j] = glm::vec3(x, y, z);texCoords[i * (prec + 1) + j] = glm::vec2((float)j / prec, (float)i / prec);}}//計(jì)算索引for (int i = 0; i < prec; i++) {for (int j = 0; j < prec; j++) {indices[6 * (i * prec + j) + 0] = i * (prec + 1) + j;indices[6 * (i * prec + j) + 1] = i * (prec + 1) + j + 1;indices[6 * (i * prec + j) + 2] = (i + 1) * (prec + 1) + j;indices[6 * (i * prec + j) + 3] = i * (prec + 1) + j + 1;indices[6 * (i * prec + j) + 4] = (i + 1) * (prec + 1) + j + 1;indices[6 * (i * prec + j) + 5] = (i + 1) * (prec + 1) + j;}} } float BezierFace::toRadians(float degrees) { return (degrees * 2.0f * 3.14159f) / 360.0f; }float BezierFace::Bernstein(float t, int index) {switch (index){default:case 0:return pow(1.0 - t, 3);break;case 1:return 3 * t * pow(1.0 - t, 2);break;case 2:return 3 * pow(t, 2) * (1 - t);break;case 3:return pow(t, 3);break;}} BezierFace::BezierFace(){}BezierFace::BezierFace(int step, float controlPoints[], int prec) {this->step = step;this->controlPoints = controlPoints;init(prec); }int BezierFace::getNumVertices() {return numVertices; }int BezierFace::getNumIndices() {return numIndices; }vector<glm::vec3> BezierFace::getVertices() {return vertices; }vector<glm::vec3> BezierFace::getNormals() {return normals; }vector<glm::vec2> BezierFace::getTexCoords() {return texCoords; }vector<int> BezierFace::getIndices() {return indices; }運(yùn)行實(shí)例:
#define GLEW_STATIC #include <iostream> #include "Camera.h" #include "Circle.h" #include "Shader.h" #include <GL/glew.h> #include <glm/glm.hpp> #include <glm\gtc\type_ptr.hpp> // glm::value_ptr #include <glm\gtc\matrix_transform.hpp> #include <GLFW/glfw3.h> #include <SOIL2/SOIL2.h> #include "Ellipse.h" #include "Ellipsoid.h" #include "BezierFace.h" #include "BezierLine.h"using namespace std;float controlPoints[] = {-1.5, -1.5, 2.0, -0.5, -1.5, 2.0, 0.5, -1.5, -1.0, 1.5, -1.5, 2.0,-1.5, -0.5, 1.0, -0.5, 1.5, 2.0, 0.5, 0.5, 1.0, 1.5, -0.5, -1.0,-1.5, 0.5, 2.0, -0.5, 0.5, 1.0, 0.5, 0.5, 3.0, 1.5, -1.5, 1.5, -1.5, 1.5, -2.0, -0.5, 1.5, -2.0, 0.5, 0.5, 1.0, 1.5, 1.5, -1.0 }; BezierFace myBezier = BezierFace(3, controlPoints, 100); GLuint VAO, VBO[3]; GLuint texture; Shader myShader; Camera myCamera(glm::vec3(0.0f, 0.0f, 2.0f)); GLFWwindow* window; float deltaTime = 0.0f; // time between current frame and last frame float lastFrame = 0.0f; float lastX = 400.f; float lastY = 300.f; bool firstMouse = true;void processInput(GLFWwindow* window) {if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS){glfwSetWindowShouldClose(window, true);}if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS){myCamera.ProcessKeyboard(FORWARD, deltaTime);}else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS){myCamera.ProcessKeyboard(BACKWARD, deltaTime);}else if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS){myCamera.ProcessKeyboard(LEFT, deltaTime);}else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS){myCamera.ProcessKeyboard(RIGHT, deltaTime);} }void mouse_callback(GLFWwindow* window, double xPos, double yPos) {if (firstMouse){lastX = xPos;lastY = yPos;firstMouse = false;}float deltaX, deltaY;deltaX = xPos - lastX;deltaY = lastY - yPos;lastX = xPos;lastY = yPos;myCamera.ProcessMouseMovement(deltaX, deltaY);}void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {myCamera.ProcessMouseScroll(yoffset); }void framebuffer_size_callback(GLFWwindow* window, int width, int height) {// make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays.glViewport(0, 0, width, height); }GLuint loadTexture(const char* texImagePath) {GLuint textureRef;textureRef = SOIL_load_OGL_texture(texImagePath, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);if (textureRef == 0) cout << "didnt find texture file " << texImagePath << endl;// ----- mipmap/anisotropic sectionglBindTexture(GL_TEXTURE_2D, textureRef);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glGenerateMipmap(GL_TEXTURE_2D);if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) {GLfloat anisoset = 0.0f;glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisoset);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoset);}// ----- end of mipmap/anisotropic sectionreturn textureRef; }void setupVertices() {vector<float> pvalues; //頂點(diǎn)坐標(biāo)vector<float> tvalues; //紋理坐標(biāo)vector<float> nvalues; //法線vector<int> ind = myBezier.getIndices();vector<glm::vec3> verts = myBezier.getVertices();vector<glm::vec2> tex = myBezier.getTexCoords();vector<glm::vec3> norm = myBezier.getNormals();for (int i = 0; i < myBezier.getNumIndices(); i++){pvalues.push_back(verts[ind[i]].x);pvalues.push_back(verts[ind[i]].y);pvalues.push_back(verts[ind[i]].z);tvalues.push_back(tex[ind[i]].s);tvalues.push_back(tex[ind[i]].t);nvalues.push_back(norm[ind[i]].x);nvalues.push_back(norm[ind[i]].y);nvalues.push_back(norm[ind[i]].z);}glGenVertexArrays(1, &VAO);glGenBuffers(3, VBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);glBufferData(GL_ARRAY_BUFFER, pvalues.size() * 4, &pvalues[0], GL_STATIC_DRAW);glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);glBufferData(GL_ARRAY_BUFFER, tvalues.size() * 4, &tvalues[0], GL_STATIC_DRAW);glBindBuffer(GL_ARRAY_BUFFER, VBO[2]);glBufferData(GL_ARRAY_BUFFER, nvalues.size() * 4, &nvalues[0], GL_STATIC_DRAW);}void init(GLFWwindow* window) {myShader = Shader("bezierVert.vert", "bezierFrag.frag");glfwSetCursorPosCallback(window, mouse_callback);glfwSetCursorPosCallback(window, mouse_callback);glfwSetScrollCallback(window, scroll_callback);glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);setupVertices();texture = loadTexture("flower.png"); }void display(GLFWwindow* window, double currentTime) {float currentFrame = glfwGetTime();deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;glClearColor(1.0f, 1.0f, 1.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//輸入processInput(window);myShader.use();glm::mat4 projection = glm::perspective(glm::radians(myCamera.Zoom), 800.0f / 600.0f, 0.1f, 100.0f);glm::mat4 view = myCamera.GetViewMatrix();glm::mat4 model = glm::mat4(1.0f);myShader.setMat4("projection", projection);myShader.setMat4("view", view);myShader.setMat4("model", model);glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);glEnableVertexAttribArray(0);glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);glEnableVertexAttribArray(1);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, texture);glEnable(GL_CULL_FACE);glFrontFace(GL_CCW);glDrawArrays(GL_TRIANGLES, 0, myBezier.getNumIndices()); }int main() {if(!glfwInit()) {exit(EXIT_FAILURE);}glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);GLFWwindow* window = glfwCreateWindow(1600, 1200, "Ellipsoid", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); }//glfwSwapInterval(1);glViewport(0, 0, 1600, 1200);glEnable(GL_DEPTH_TEST);init(window);while (!glfwWindowShouldClose(window)) {display(window, glfwGetTime());glfwSwapBuffers(window);glfwPollEvents();}glfwDestroyWindow(window);glfwTerminate();exit(EXIT_SUCCESS); }著色器
#version 330 layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aTexCoord;out vec2 TexCoord;uniform mat4 model; uniform mat4 view; uniform mat4 projection;void main() {gl_Position = projection * view * model * vec4(aPos, 1.0);TexCoord = aTexCoord; } #version 330 out vec4 FragColor; in vec2 TexCoord;uniform sampler2D s; void main() {FragColor = texture(s, TexCoord); }運(yùn)行結(jié)果
總結(jié)
以上是生活随笔為你收集整理的OpenGL(可编程管线):Bezier曲面的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 游戏:致那个曾经热血的青春
- 下一篇: 【font-spider】网页中引用字体