Skip to content

Instantly share code, notes, and snippets.

@Plasmoxy
Created November 8, 2022 19:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Plasmoxy/e21f4425a9a94845a7c98d85a2790c7b to your computer and use it in GitHub Desktop.
Save Plasmoxy/e21f4425a9a94845a7c98d85a2790c7b to your computer and use it in GitHub Desktop.
// 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