Commit 4d885737 authored by Bastian Krayer's avatar Bastian Krayer
Browse files

added solution 2

parent 8981fe07
#include "BSpline.h"
#include <cmath>
BSpline::BSpline(std::vector<glm::vec3> cpoints, int k)
: m_controlPoints(std::move(cpoints)), m_k(k) {}
BSpline::~BSpline() = default;
glm::vec3 BSpline::evaluate(float t) {
// Aufgabe 5 (c)
// accumulate weighted points
glm::vec3 result(0.0f);
for (int i = 0; i < m_controlPoints.size(); i++) {
result += coxDeBoor(t, i, m_k) * m_controlPoints[i];
}
return result;
}
float BSpline::coxDeBoor(float t, int i, int k) {
// Aufgabe 5 (d)
if (k == 1) {
return m_knotVector[i] <= t && t < m_knotVector[i + 1] ? 1.0f : 0.0f;
}
float denom1 = m_knotVector[i + k - 1] - m_knotVector[i];
float denom2 = m_knotVector[i + k] - m_knotVector[i + 1];
float num1 = (t - m_knotVector[i]) * coxDeBoor(t, i, k - 1);
float num2 = (m_knotVector[i + k] - t) * coxDeBoor(t, i + 1, k - 1);
float s1 = std::abs(denom1) < 1E-7 ? 0 : num1 / denom1;
float s2 = std::abs(denom2) < 1E-7 ? 0 : num2 / denom2;
return s1 + s2;
}
void BSpline::setK(int val) { m_k = val; }
int BSpline::getK() const { return m_k; }
const std::vector<glm::vec3>& BSpline::getVertices() { return m_vertices; }
const std::vector<glm::vec3>& BSpline::getControlPoints() {
return m_controlPoints;
}
#ifndef BSPLINE_H
#define BSPLINE_H
#include <glm/glm.hpp>
#include <vector>
class BSpline {
public:
BSpline(std::vector<glm::vec3> cpoints, int k);
virtual ~BSpline();
virtual bool initialize(int num) = 0;
void setK(int val);
int getK() const;
const std::vector<glm::vec3>& getVertices();
const std::vector<glm::vec3>& getControlPoints();
protected:
float coxDeBoor(float t, int i, int k);
glm::vec3 evaluate(float t);
std::vector<glm::vec3> m_controlPoints;
std::vector<glm::vec3> m_vertices;
std::vector<float> m_knotVector;
int m_k = 0;
};
#endif
\ No newline at end of file
cmake_minimum_required(VERSION 3.1)
include(${CMAKE_MODULE_PATH}/DefaultExecutable.cmake)
\ No newline at end of file
#include "OpenBSpline.h"
// for std::iota
#include <numeric>
// for std::is_sorted
#include <algorithm>
bool OpenBSpline::initialize(int num) {
auto n = m_controlPoints.size();
// check correct size
if (m_knotVector.size() != m_k + n) {
return false;
}
// check if values are in increasing order
// alternatively, loop yourself
if (!std::is_sorted(m_knotVector.begin(), m_knotVector.end())) {
return false;
}
// min param
float min_t = m_knotVector[m_k - 1];
float max_t = m_knotVector[n];
float d_t = max_t - min_t;
// generate points
m_vertices.resize(num);
for (int i = 0; i < num; i++) {
// t value sampled in valid interval
auto t = min_t + d_t * static_cast<float>(i) / static_cast<float>(num);
m_vertices[i] = evaluate(t);
}
return true;
}
OpenBSpline::OpenBSpline(std::vector<glm::vec3> cpoints, int k, int num)
: BSpline(std::move(cpoints), k) {
// number of knots in knot vector is n + k
auto n = m_controlPoints.size();
auto nk = n + k;
m_knotVector.resize(nk);
// first n values are 0
std::fill(m_knotVector.begin(), m_knotVector.begin() + k, 0);
std::iota(m_knotVector.begin() + k, m_knotVector.begin() + n, 1);
std::fill(m_knotVector.begin() + n, m_knotVector.end(), n - k + 1);
initialize(num);
}
#ifndef OPENBSPLINE_H
#define OPENBSPLINE_H
#include "BSpline.h"
class OpenBSpline : public BSpline {
public:
OpenBSpline(std::vector<glm::vec3> cpoints, int k, int num);
bool initialize(int num) override;
};
#endif // OPENBSPLINE_H
#include "PeriodicBSpline.h"
// for std::iota
#include <numeric>
// for std::is_sorted
#include <algorithm>
PeriodicBSpline::PeriodicBSpline(std::vector<glm::vec3> cpoints, int k, int num)
: BSpline(std::move(cpoints), k) {
// Aufgabe 5 (a)
// number of knots in knot vector is n + k
auto n = m_controlPoints.size();
auto nk = n + k;
m_knotVector.resize(nk);
// periodic b-spline has increasing number of values
// std::iota fills vector with increasing values starting at the last
// argument.
// Alternatively loop over size
std::iota(m_knotVector.begin(), m_knotVector.end(), 0);
initialize(num);
}
PeriodicBSpline::~PeriodicBSpline() = default;
bool PeriodicBSpline::initialize(int num) {
// Aufgabe 5 (b)
auto n = m_controlPoints.size();
// check correct size
if (m_knotVector.size() != m_k + n) {
return false;
}
// check if values are in increasing order
// alternatively, loop yourself
if (!std::is_sorted(m_knotVector.begin(), m_knotVector.end())) {
return false;
}
// min param
float min_t = m_knotVector[m_k - 1];
float max_t = m_knotVector[n];
float d_t = max_t - min_t;
// generate points
m_vertices.resize(num);
for (int i = 0; i < num; i++) {
// t value sampled in valid interval
auto t = min_t + d_t * static_cast<float>(i) / static_cast<float>(num);
m_vertices[i] = evaluate(t);
}
return true;
}
\ No newline at end of file
#ifndef PERIODICBSPLINE_H
#define PERIODICBSPLINE_H
#include "BSpline.h"
class PeriodicBSpline : public BSpline {
public:
PeriodicBSpline(std::vector<glm::vec3> cpoints, int k, int num);
~PeriodicBSpline() override;
bool initialize(int num) override;
};
#endif
#include "OpenBSpline.h"
#include "PeriodicBSpline.h"
#include <CVK_2/CVK_Framework.h>
#include <glad/glad.h>
#include <memory>
constexpr int width = 800; // window width
constexpr int height = 800; // window height
class ExBSplineSolution : public CVK::GlfwBase {
public:
ExBSplineSolution();
~ExBSplineSolution();
// run the actual loop and display
void display();
// render the spline
void renderSpline(BSpline& spline);
// callback for key input
static void keyfun(GLFWwindow* window, int key, int, int action, int);
private:
// number of vertices
int numSamples = 1000;
// order
int k = 5;
int drawType = 0;
// render parameters
GLint m_colorHandle = 0;
GLuint m_vbos[2]{};
GLuint m_vaoHandle = 0;
std::unique_ptr<CVK::ShaderSet> m_shaderProgram;
};
int main() {
// Construct and display
ExBSplineSolution demo;
demo.display();
return 0;
}
// Implementation
ExBSplineSolution::ExBSplineSolution() {
m_window = glfwCreateWindow(width, height, "BSpline", nullptr, nullptr);
glfwSetWindowPos(m_window, 600, 50);
glfwMakeContextCurrent(m_window);
glfwSetWindowUserPointer(m_window, this);
glfwSetKeyCallback(m_window, keyfun);
// init opengl
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cerr << "Failed to initialize OpenGL context" << std::endl;
throw std::runtime_error("Failed to initialize OpenGL context");
}
glClearColor(1, 1, 1, 1);
// compile a shader program
m_shaderProgram = std::make_unique<CVK::ShaderSet>(
VERTEX_SHADER_BIT | FRAGMENT_SHADER_BIT,
std::vector<std::string>{CVK::State::getInstance()->getShaderPath() +
"/BSplines/bsplines.vert",
CVK::State::getInstance()->getShaderPath() +
"/BSplines/bsplines.frag"});
// use the shader program
m_shaderProgram->useProgram();
m_colorHandle =
glGetUniformLocation(m_shaderProgram->getProgramID(), "color");
glGenVertexArrays(1, &m_vaoHandle);
glBindVertexArray(m_vaoHandle);
glGenBuffers(2, m_vbos);
}
ExBSplineSolution::~ExBSplineSolution() {
glDeleteBuffers(2, m_vbos);
glDeleteVertexArrays(1, &m_vaoHandle);
}
void ExBSplineSolution::display() {
// controlpoints
std::vector<glm::vec3> cpoints;
// create control points
cpoints.emplace_back(-0.5f, -0.25f, 0.0f);
cpoints.emplace_back(0.0f, 0.5f, 0.0f);
cpoints.emplace_back(0.5f, -0.25f, 0.0f);
cpoints.emplace_back(0.75f, -0.75f, 0.0f);
cpoints.emplace_back(-0.75f, -0.75f, 0.0f);
PeriodicBSpline pSpline(cpoints, k, numSamples);
OpenBSpline oSpline(cpoints, k, numSamples);
// render stuff
// Renderer lives only in this block and will clean up when it is
// destroyed
while (!glfwWindowShouldClose(m_window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (drawType == 0) {
renderSpline(pSpline);
} else {
renderSpline(oSpline);
}
// show what's been drawn
glfwSwapBuffers(m_window);
glfwPollEvents();
}
}
void ExBSplineSolution::keyfun(GLFWwindow* window, int key, int, int action,
int) {
// Since glfw callbacks come from C, we can only pass static member
// functions. But at the beginning, we store a pointer to our object
// with this window and we can retrieve it. "demo" effectively acts as
// "this" here
auto demo =
static_cast<ExBSplineSolution*>(glfwGetWindowUserPointer(window));
if (key == GLFW_KEY_N && action == GLFW_PRESS) {
demo->drawType = (demo->drawType + 1) % 2;
}
}
void ExBSplineSolution::renderSpline(BSpline& spline) {
glm::vec3 black = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 red = glm::vec3(1.0f, 0.0f, 0.0f);
// draw control points
glPointSize(15.0f);
glUniform3fv(m_colorHandle, 1, glm::value_ptr(black));
glBindBuffer(GL_ARRAY_BUFFER, m_vbos[0]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(glm::vec3) * spline.getControlPoints().size(),
spline.getControlPoints().data(), GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glDrawArrays(GL_POINTS, 0, spline.getControlPoints().size());
// draw curve points
glPointSize(5.0f);
glUniform3fv(m_colorHandle, 1, glm::value_ptr(red));
glBindBuffer(GL_ARRAY_BUFFER, m_vbos[1]);
glBufferData(GL_ARRAY_BUFFER,
sizeof(glm::vec3) * spline.getVertices().size(),
spline.getVertices().data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glDrawArrays(GL_LINE_STRIP, 0, spline.getVertices().size());
// unbind the VBO, we don't need it anymore
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment