// 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 #include #define GLM_ENABLE_EXPERIMENTAL #include #include #include #include #include #include #include #include const unsigned int SIZE = 512; // Object to represent Bezier patch class BezierPatch { private: // 3D vectors define points/vertices of the shape std::vector vertices; // Texture coordinates std::vector texCoords; // Define our face using indexes to 3 vertices struct face { GLuint v0, v1, v2; }; // Define our mesh as collection of faces std::vector mesh; // These will hold the data and object buffers GLuint vao, vbo, tbo, ibo; glm::mat4 modelMatrix{1.0f}; glm::vec3 recCasteljau(std::vector &pts, const float t) { if (pts.size() == 1) return pts[0]; std::vector 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 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; }