Created
November 8, 2022 19:00
-
-
Save Plasmoxy/e21f4425a9a94845a7c98d85a2790c7b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Task 6 - Generate a Bezier surface of variable density with UV coordinates. | |
// - Confine the Bezier data and associated methods into a reusable class. | |
// - Define a modelMatrix that uses position, rotation and scale. | |
// - Render the generated mesh with texturing applied. | |
// - Animate rotation. | |
#include <iostream> | |
#include <vector> | |
#define GLM_ENABLE_EXPERIMENTAL | |
#include <glm/glm.hpp> | |
#include <glm/gtc/matrix_transform.hpp> | |
#include <glm/gtx/euler_angles.hpp> | |
#include <glm/gtx/transform.hpp> | |
#include <ppgso/ppgso.h> | |
#include <shaders/texture_vert_glsl.h> | |
#include <shaders/texture_frag_glsl.h> | |
#include <iterator> | |
const unsigned int SIZE = 512; | |
// Object to represent Bezier patch | |
class BezierPatch { | |
private: | |
// 3D vectors define points/vertices of the shape | |
std::vector<glm::vec3> vertices; | |
// Texture coordinates | |
std::vector<glm::vec2> texCoords; | |
// Define our face using indexes to 3 vertices | |
struct face { | |
GLuint v0, v1, v2; | |
}; | |
// Define our mesh as collection of faces | |
std::vector<face> mesh; | |
// These will hold the data and object buffers | |
GLuint vao, vbo, tbo, ibo; | |
glm::mat4 modelMatrix{1.0f}; | |
glm::vec3 recCasteljau(std::vector<glm::vec3> &pts, const float t) { | |
if (pts.size() == 1) return pts[0]; | |
std::vector<glm::vec3> newPts; | |
for (unsigned long i = 0; i < pts.size(); i += 2) { | |
newPts.push_back(glm::lerp(pts[i], pts[i + 1], t)); | |
} | |
return recCasteljau(newPts, t); | |
} | |
glm::vec3 bezierPoint(const glm::vec3 controlPoints[4], float t) { | |
std::vector<glm::vec3> controls(controlPoints, controlPoints + 4); | |
return recCasteljau(controls, t); | |
} | |
ppgso::Shader program{texture_vert_glsl, texture_frag_glsl}; | |
ppgso::Texture texture{ppgso::image::loadBMP("lena.bmp")}; | |
public: | |
// Public attributes that define position, color .. | |
glm::vec3 position{0, 0, 0}; | |
glm::vec3 rotation{0, 0, 0}; | |
glm::vec3 scale{1, 1, 1}; | |
// Initialize object data buffers | |
BezierPatch(const glm::vec3 controlPoints[4][4]) { | |
// std::cout << "Creating bezier..." << std::endl; | |
// Generate Bezier patch points and incidences | |
unsigned int PATCH_SIZE = 10; | |
for (unsigned int i = 0; i < PATCH_SIZE; i++) { | |
auto u = 1.0 * i / PATCH_SIZE; | |
// control points by u | |
glm::vec3 uControls[4]; | |
for (unsigned int ci = 0; ci < 4; ci++) { | |
uControls[ci] = bezierPoint(controlPoints[ci], u); | |
} | |
for (unsigned int j = 0; j < PATCH_SIZE; j++) { | |
// TODO: Compute points on the bezier patch | |
auto v = 1.0 * j / PATCH_SIZE; | |
glm::vec3 point = bezierPoint(uControls, v); | |
// std::cout << point.x << " " << point.y << " " << point.z << std::endl; | |
vertices.push_back(point); | |
texCoords.emplace_back(u, -v); | |
} | |
} | |
// Generate indices | |
// CHANGE from 0 indexing | |
auto P = PATCH_SIZE; | |
for (unsigned int i = 0; i < PATCH_SIZE - 1; i++) { | |
for (unsigned int j = 0; j < PATCH_SIZE - 1; j++) { | |
// TODO: Compute indices for triangle 1 | |
mesh.push_back({P * j + i, P * j + i + 1, P * (j + 1) + i + 1}); | |
// TODO: Compute indices for triangle 2 | |
mesh.push_back({P * j + i, P * (j + 1) + i + 1, P * (j + 1) + i}); | |
} | |
} | |
// Copy data to OpenGL | |
glGenVertexArrays(1, &vao); | |
glBindVertexArray(vao); | |
// Copy positions to gpu | |
glGenBuffers(1, &vbo); | |
glBindBuffer(GL_ARRAY_BUFFER, vbo); | |
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW); | |
// Set vertex program inputs | |
auto position_attrib = program.getAttribLocation("Position"); | |
glEnableVertexAttribArray(position_attrib); | |
glVertexAttribPointer(position_attrib, 3, GL_FLOAT, GL_FALSE, 0, 0); | |
// Copy texture positions to gpu | |
glGenBuffers(1, &tbo); | |
glBindBuffer(GL_ARRAY_BUFFER, tbo); | |
glBufferData(GL_ARRAY_BUFFER, texCoords.size() * sizeof(glm::vec2), texCoords.data(), GL_STATIC_DRAW); | |
// Set vertex program inputs | |
auto texCoord_attrib = program.getAttribLocation("TexCoord"); | |
glEnableVertexAttribArray(texCoord_attrib); | |
glVertexAttribPointer(texCoord_attrib, 2, GL_FLOAT, GL_FALSE, 0, 0); | |
// Copy indices to gpu | |
glGenBuffers(1, &ibo); | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); | |
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh.size() * sizeof(face), mesh.data(), GL_STATIC_DRAW); | |
}; | |
// Clean up | |
~BezierPatch() { | |
// Delete data from OpenGL | |
glDeleteBuffers(1, &ibo); | |
glDeleteBuffers(1, &tbo); | |
glDeleteBuffers(1, &vbo); | |
glDeleteVertexArrays(1, &vao); | |
} | |
// Set the object transformation matrix | |
void update() { | |
// TODO: Compute transformation by scaling, rotating and then translating the shape | |
auto I = glm::mat4{1}; | |
modelMatrix = glm::eulerAngleXYZ(rotation.x, rotation.y, rotation.z) * glm::translate(I, position) * | |
glm::scale(I, scale); | |
} | |
// Draw polygons | |
void render() { | |
// Update transformation and color uniforms in the shader | |
program.use(); | |
// Initialize projection | |
// Create projection matrix (field of view (radians), aspect ratio, near plane distance, far plane distance) | |
// You can think of this as the camera objective settings | |
auto projection = glm::perspective((ppgso::PI / 180.f) * 60.0f, 1.0f, 0.1f, 10.0f); | |
program.setUniform("ProjectionMatrix", projection); | |
// Create view matrix (translate camera a bit backwards, so we can see the geometry) | |
// This can be seen as the camera position/rotation in space | |
auto view = glm::translate(glm::mat4{1}, {0.0f, 0.0f, -5.0f}); | |
program.setUniform("ViewMatrix", view); | |
// Set model position | |
program.setUniform("ModelMatrix", modelMatrix); | |
// Bind texture | |
program.setUniform("Texture", texture); | |
glBindVertexArray(vao); | |
// TODO: Use correct rendering mode to draw the result | |
glDrawElements(GL_TRIANGLES, (GLsizei) mesh.size() * 3, GL_UNSIGNED_INT, 0); | |
}; | |
}; | |
class BezierSurfaceWindow : public ppgso::Window { | |
private: | |
// Define 16 control points | |
// bortacina: | |
// glm::vec3 controlPoints[4][4]{ | |
// {{-1, 1, 0}, {-0.5, 1, 0}, {.5, 1, 0}, {1, 1, 3},}, | |
// {{-1, .5, 0}, {-0.5, .5, 0}, {.5, .5, 0}, {1, .5, 0},}, | |
// {{-1, -.5, 0}, {-0.5, -.5, 0}, {.5, -.5, 0}, {1, -.5, -1},}, | |
// {{-1, -1, 3}, {-0.5, -1, 0}, {.5, -1, 0}, {1, -1, 0},}, | |
// }; | |
public: | |
BezierSurfaceWindow() : Window{"๐๐LANA = RYBA OMG xDDDDDD ๐๐", SIZE, SIZE} { | |
// Initialize OpenGL state | |
// Enable Z-buffer | |
glEnable(GL_DEPTH_TEST); | |
glDepthFunc(GL_LEQUAL); | |
// vidime strukturu polygonov | |
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); | |
} | |
void onIdle() final { | |
auto time = (float) glfwGetTime(); | |
// Set gray background | |
glClearColor(.1f, .1f, .1f, 1.0f); | |
// Clear depth and color buffers | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
// DYNAMIC BEZIEROS | |
auto a = 1 * std::sin(time); | |
auto b = 1 * std::sin(time + 1); | |
auto c = 1 * std::sin(time + 2); | |
auto d = 1 * std::sin(time + 3); | |
glm::vec3 controlPoints[4][4]{ | |
{{-1, 1, a}, {-0.5, 1, b}, {.5, 1, c}, {1, 1, d},}, | |
{{-1, .5, a}, {-0.5, .5, b}, {.5, .5, c}, {1, .5, d},}, | |
{{-1, -.5, a}, {-0.5, -.5, b}, {.5, -.5, c}, {1, -.5, d},}, | |
{{-1, -1, a}, {-0.5, -1, b}, {.5, -1, c}, {1, -1, d},}, | |
}; | |
BezierPatch bezier {controlPoints}; | |
// Move and Render shape | |
bezier.rotation = {0.5, 1.5, 0}; | |
bezier.update(); | |
bezier.render(); | |
} | |
}; | |
int main() { | |
// Create new window | |
auto window = BezierSurfaceWindow{}; | |
// Main execution loop | |
while (window.pollEvents()) {} | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment