0

I have a very peculiar problem that I can not figure out. For my scene I have created a spline class which I use to generate points for which my camera traverses. This works fine and dandy when I create an instance of the spline class in my scene and use it. I have some functionality in my spline class for showing the points on the spline that use uniform data to draw their position and give them a color. This all works fine when I create an instance directly in my scene.

HOWEVER, I want to create multiple splines to have my camera traverse so I created a fairly simple management class to handle multiple splines. This works however for some reason I can not puzzle out why when I create an instance of a spline with the manager the uniform variables aren't working. Everything else works fine. When I say they don't work what I mean is that the getLocation functions work (they get the locationIDs as expected), the data to be sent is the same, there are no errors or warnings concerning the functions that are supposed to actually send the data down to their locations. The spline draws properly however they are always black and haven't been translated.

Here is my scene class. The constructors for both my manager and the spline class its self are exactly the same so in my ClothScene.hpp I can switch the type of the mSplineManager object from the manager class to the spline class and the uniform variables work fine.

#include "ClothScene.hpp"
#include <atlas/core/GLFW.hpp>
#include <atlas/core/Log.hpp>
#include <atlas/core/Macros.hpp>
#include <atlas/core/Float.hpp>
#include <iostream>

ClothScene::ClothScene() : 
    mIsPlaying(false),
    mLastTime(0.0f),
    mFPS(60.0f),
    mTick(1.0f / mFPS),
    mAnimTime(0.0f),
    mAnimLength(10.0f),
    mSplineManager(int(mAnimLength * mFPS)),
    ballPosition{ -10.0f, 0.0f, 14.0f }
{
    glEnable(GL_DEPTH_TEST);
    auto mat = glm::translate(atlas::math::Matrix4(1.0f), ballPosition);
    mBall.transformGeometry(mat);
}

ClothScene::~ClothScene() {
}

void ClothScene::mousePressEvent(int button, int action, int modifiers, double xPos, double yPos) {
    USING_ATLAS_MATH_NS;

    if (button == GLFW_MOUSE_BUTTON_LEFT && modifiers == GLFW_MOD_ALT)
    {
        if (action == GLFW_PRESS)
        {
            mIsDragging = true;
            //Camera tilt up and down or turn left, right
            mCamera.mouseDown(Point2(xPos, yPos), ClothCamera::CameraMovements::TUMBLE);
        }
        else
        {
            mIsDragging = false;
            mCamera.mouseUp();
        }
    }
    else if (button == GLFW_MOUSE_BUTTON_MIDDLE && modifiers == GLFW_MOD_ALT)
    {
        if (action == GLFW_PRESS)
        {
            mIsDragging = true;
            //Camera move left, right, up, down
            mCamera.mouseDown(Point2(xPos, yPos), ClothCamera::CameraMovements::TRACK);
        }
        else
        {
            mIsDragging = false;
            mCamera.mouseUp();
        }
    }
    else if (button == GLFW_MOUSE_BUTTON_RIGHT && modifiers == GLFW_MOD_ALT)
    {
        if (action == GLFW_PRESS)
        {
            // first click.
            mIsDragging = true;
            //Camera move back and forth
            mCamera.mouseDown(Point2(xPos, yPos), ClothCamera::CameraMovements::DOLLY);
        }
        else
        {
            mIsDragging = false;
            mCamera.mouseUp();
        }
    }
    else if (action != GLFW_PRESS)
    {
        mIsDragging = false;
        mCamera.mouseUp();
    }
}

void ClothScene::mouseMoveEvent(double xPos, double yPos) {
    mCamera.mouseUpdate(glm::vec2(xPos, yPos));
}
void ClothScene::keyPressEvent(int key, int scancode, int action, int mods) {
    UNUSED(scancode);
    UNUSED(mods);

    if (action == GLFW_PRESS)
    {
        switch (key)
        {
        case GLFW_KEY_T:
            mCamera.resetCamera();
            break;
        case GLFW_KEY_W:
            mCamera.strafeCamera(0);
            break;
        case GLFW_KEY_S:
            mCamera.strafeCamera(1);
            break;
        case GLFW_KEY_A:
            mCamera.strafeCamera(2);
            break;
        case GLFW_KEY_D:
            mCamera.strafeCamera(3);
            break;
        case GLFW_KEY_R:
            mCamera.strafeCamera(4);
            break;
        case GLFW_KEY_F:
            mCamera.strafeCamera(5);
            break;
        case GLFW_KEY_Q:
            mCamera.strafeCamera(6);
            break;
        case GLFW_KEY_E:
            mCamera.strafeCamera(7);
            break;
        case GLFW_KEY_C:
            mCamera.newPosition(glm::vec3(0.0f, 3.0f, 0.0f));
            break;
        case GLFW_KEY_U:
            mSplineManager.showSpline();
            break;
        case GLFW_KEY_I:
            mSplineManager.showControlPoints();
            break;
        case GLFW_KEY_O:
            mSplineManager.showCage();
            break;
        case GLFW_KEY_P:
            mSplineManager.showSplinePoints();
            break;
        case GLFW_KEY_SPACE:
            mIsPlaying = !mIsPlaying;
        default:
            break;
        }
    }
}

void ClothScene::screenResizeEvent(int width, int height) {
    glViewport(0, 0, width, height);
    mProjection = glm::perspective(glm::radians(45.0),(double)width / height, 1.0, 1000.0);
}
void ClothScene::renderScene() {
    float grey = 161.0f / 255.0f;
    glClearColor(grey, grey, grey, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);

    mView = mCamera.getCameraMatrix();
    mGrid.renderGeometry(mProjection, mView);
    mSplineManager.renderGeometry(mProjection, mView);
    mBall.renderGeometry(mProjection, mView);
}
void ClothScene::updateScene(double time)
{

    mTime.currentTime = (float)time;
    mTime.totalTime += (float)time;

    if (atlas::core::geq(mTime.currentTime - mLastTime, mTick))
    {
        mLastTime += mTick;
        mTime.deltaTime = mTick;

        if (mIsPlaying)
        {
            mAnimTime += mTick;
            mSplineManager.updateGeometry(mTime);

            if (mSplineManager.doneInterpolation())
            {
                mIsPlaying = false;
                return;
            }

            auto point = mSplineManager.getSplinePosition();
            mCamera.newPosition(point);
            mCamera.lookAt(ballPosition);
            auto mat = glm::translate(atlas::math::Matrix4(1.0f), ballPosition);
            mBall.transformGeometry(mat);
        }

    }
}

Here is my SplineManger class. It super simple, it just creates a vector of splines and then applies the exact same functionality iterated through all of the splines in the vector. For some reason this prevents the shader from receiving the uniform data.

#include "SplineManager.hpp"

SplineManager::SplineManager(int totalFrames) :
    finishedAllSplines(false),
    currentSpline(0)
{
    mTotalFrames = totalFrames;
    addSplines();
}
SplineManager::~SplineManager() {

}
void SplineManager::addSplines() {
    mControlPoints = std::vector<Point>
    {
        { -20, -5, 0 },
        { -19, 5, -15 },
        { 12.7f, -5, -1.4f },
        { 20, 8.2f, 4.4f }
    };
    mSplines.push_back(Spline(mTotalFrames, mControlPoints));
}
void SplineManager::renderGeometry(atlas::math::Matrix4 projection, atlas::math::Matrix4 view) {
    for (int i = 0; i < mSplines.size(); ++i) {
        mSplines[i].renderGeometry(projection, view);
    }
}
void SplineManager::updateGeometry(atlas::utils::Time const& t) {
    mSplines[currentSpline].updateGeometry(t);
    if (mSplines[currentSpline].doneInterpolation()) {
        ++currentSpline;
        if (currentSpline == mSplines.size()) {
            finishedAllSplines = true;
        }
    }
}

atlas::math::Point SplineManager::getSplinePosition() {
    return mSplines[currentSpline].getSplinePosition();
}
void SplineManager::showSpline() {
    for (int i = 0; i < mSplines.size(); ++i) {
        mSplines[i].showSpline();
    }

}
void SplineManager::showControlPoints() {
    for (int i = 0; i < mSplines.size(); ++i) {
        mSplines[i].showControlPoints();
    }
}
void SplineManager::showCage() {
    for (int i = 0; i < mSplines.size(); ++i) {
        mSplines[i].showCage();
    }
}
void SplineManager::showSplinePoints() {
    for (int i = 0; i < mSplines.size(); ++i) {
        mSplines[i].showSplinePoints();
    }
}
bool SplineManager::doneInterpolation() {
    return finishedAllSplines;
}

Here is my spline class. Again, this all works totally fine when I directly create an instance of it in the scene class. When instances are created in the SplineManager the uniform variables don't work.

#include "Spline.h"
#include "ShaderPaths.hpp"
#include <atlas/core/Macros.hpp>

Spline::Spline(int totalFrames) :
    mResolution(500),
    mTotalFrames(totalFrames),
    mCurrentFrame(0),
    mShowControlPoints(false),
    mShowCage(false),
    mShowSplinePoints(false),
    mShowSpline(false),
    mIsInterpolationDone(false)
{
    USING_ATLAS_MATH_NS;
    USING_ATLAS_GL_NS;

    //Bezier
    mBasisMatrix = Matrix4(
        1.0f, 0.0f, 0.0f, 0.0f,
        -3.0f, 3.0f, 0.0f, 0.0f,
        3.0f, -6.0f, 3.0f, 0.0f,
        -1.0f, 3.0f, -3.0f, 1.0f);

    mControlPoints = std::vector<Point>
    {
        { -20, -5, 0 },
        { -19, 5, -15 },
        { 12.7f, -5, -1.4f },
        { 20, 8.2f, 4.4f }
    };

    std::vector<Point> splinePoints;

    float scale = 1.0f / mResolution;
    for (int res = 0; res < mResolution + 1; ++res)
    {
        splinePoints.push_back(evaluateSpline(scale * res));
    }

    generateArcLengthTable();

    glGenVertexArrays(1, &mVao);
    glBindVertexArray(mVao);

    glGenBuffers(1, &mControlBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, mControlBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Point) * mControlPoints.size(),
        mControlPoints.data(), GL_STATIC_DRAW);

    glGenBuffers(1, &mSplineBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, mSplineBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Point) * splinePoints.size(), splinePoints.data(), GL_STATIC_DRAW);

    std::string shaderDir = generated::ShaderPaths::getShaderDirectory();

    std::vector<ShaderInfo> shaders
    {
        { GL_VERTEX_SHADER, shaderDir + "spline.vs.glsl" },
        { GL_FRAGMENT_SHADER, shaderDir + "spline.fs.glsl" }
    };

    mShaders.push_back(ShaderPointer(new Shader));
    mShaders[0]->compileShaders(shaders);
    mShaders[0]->linkShaders();

    GLuint var;
    var = mShaders[0]->getUniformVariable("uMVP");
    mUniforms.insert(UniformKey("uMVP", var));

    var = mShaders[0]->getUniformVariable("fColour");
    mUniforms.insert(UniformKey("fColour", var));

    mShaders[0]->disableShaders();
    glBindVertexArray(0);
}
Spline::~Spline()
{
    glDeleteVertexArrays(1, &mVao);
    glDeleteVertexArrays(1, &mControlBuffer);
    glDeleteVertexArrays(1, &mSplineBuffer);
}

void Spline::renderGeometry(atlas::math::Matrix4 projection,
    atlas::math::Matrix4 view)
{
    USING_ATLAS_MATH_NS;

    mShaders[0]->enableShaders();

    glBindVertexArray(mVao);

    Matrix4 mvp = projection * view * mModel;
    glUniformMatrix4fv(mUniforms["uMVP"], 1, GL_FALSE, &mvp[0][0]);

    // Draw the control points first.
    glUniform3f(mUniforms["fColour"], 1, 0, 0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, mControlBuffer);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

    if (mShowControlPoints)
    {
        glPointSize(5.0f);
        glDrawArrays(GL_POINTS, 0, GLsizei(mControlPoints.size()));
        glPointSize(1.0f);
    }

    if (mShowCage)
    {
        glDrawArrays(GL_LINE_STRIP, 0, GLsizei(mControlPoints.size()));
    }

    // Now draw the spline.
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, mSplineBuffer);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
    glUniform3f(mUniforms["fColour"], 0, 1, 0);

    if (mShowSpline)
    {
        glLineWidth(5.0f);
        glDrawArrays(GL_LINE_STRIP, 0, mResolution + 1);
        glLineWidth(1.0f);
    }

    if (mShowSplinePoints)
    {
        glPointSize(8.0f);
        glDrawArrays(GL_POINTS, 1, mResolution);
        glPointSize(1.0f);
    }

    glDisableVertexAttribArray(0);

    mShaders[0]->disableShaders();
}

void Spline::updateGeometry(atlas::utils::Time const& t)
{
    UNUSED(t);
    mSplinePosition = interpolateOnSpline();

    mCurrentFrame++;
    if (mCurrentFrame == mTotalFrames)
    {
        mIsInterpolationDone = true;
        return;
    }
}

void Spline::showControlPoints()
{
    mShowControlPoints = !mShowControlPoints;
}

void Spline::showCage()
{
    mShowCage = !mShowCage;
}

void Spline::showSplinePoints()
{
    mShowSplinePoints = !mShowSplinePoints;
}

void Spline::showSpline()
{
    mShowSpline = !mShowSpline;
}

bool Spline::doneInterpolation()
{
    return mIsInterpolationDone;
}

atlas::math::Point Spline::getSplinePosition()
{
    return mSplinePosition;
}

atlas::math::Point Spline::interpolateOnSpline()
{
    int n = int(mTable.size());
    float totalDistance = mTable[n - 1];
    float step = totalDistance / mTotalFrames;
    float currDistance = step * mCurrentFrame;

    int index = tableLookUp(currDistance);

    float t = (1.0f / mResolution) * (index % mResolution);
    return evaluateSpline(t);
}

atlas::math::Point Spline::evaluateSpline(float t)
{
    USING_ATLAS_MATH_NS;

    Vector4 xControls =
    {
        mControlPoints[0].x, mControlPoints[1].x,
        mControlPoints[2].x, mControlPoints[3].x
    };

    Vector4 yControls =
    {
        mControlPoints[0].y, mControlPoints[1].y,
        mControlPoints[2].y, mControlPoints[3].y
    };

    Vector4 zControls =
    {
        mControlPoints[0].z, mControlPoints[1].z,
        mControlPoints[2].z, mControlPoints[3].z
    };

    Vector4 xCoeff = xControls * mBasisMatrix;
    Vector4 yCoeff = yControls * mBasisMatrix;
    Vector4 zCoeff = zControls * mBasisMatrix;

    float xcr, ycr, zcr;
    xcr = xCoeff[0] + t * xCoeff[1] + t * t * xCoeff[2] + t * t * t * xCoeff[3];
    ycr = yCoeff[0] + t * yCoeff[1] + t * t * yCoeff[2] + t * t * t * yCoeff[3];
    zcr = zCoeff[0] + t * zCoeff[1] + t * t * zCoeff[2] + t * t * t * zCoeff[3];

    return Point(xcr, ycr, zcr);
}

void Spline::generateArcLengthTable()
{
    USING_ATLAS_MATH_NS;

    if (!mTable.empty())
    {
        mTable.clear();
    }

    float scale = 1.0f / mResolution;
    mTable.push_back(0.0f);

    for (int i = 1; i < mResolution + 1; ++i)
    {
        Point p0 = evaluateSpline((i - 1) * scale);
        Point p1 = evaluateSpline(i * scale);

        Point dist = p0 - p1;
        mTable.push_back(mTable[i - 1] + glm::length(dist));
    }
}

int Spline::tableLookUp(float distance)
{
    // Find the entry in our table that corresponds to the given distance.
    float epsilon = chooseEpsilon();
    for (int i = 0; i < int(mTable.size()); ++i)
    {
        if (glm::abs(mTable[i] - distance) < epsilon)
        {
            return i;
        }
    }

    return -1;
}

float Spline::chooseEpsilon()
{
    // Find the largest difference and use that to look up distances
    // in our table.
    float epsilon = 0.0f;
    float diff;
    for (int i = 0; i < mTable.size() - 1; ++i)
    {
        diff = glm::abs(mTable[i] - mTable[i + 1]);
        if (diff > epsilon)
        {
            epsilon = diff;
        }
    }

    return epsilon;
}
void Spline::setSplineCoordinates(std::vector<atlas::math::Point> mControlPoints_) {
    mControlPoints = mControlPoints_;
} 

The header files for anyone interested.

SplineManager.hpp

#ifndef SPLINEMANAGER_HPP
#define SPLINEMANAGER_HPP
#pragma once
#include <atlas/utils/Geometry.hpp>
#include "Spline.h"
USING_ATLAS_MATH_NS;
USING_ATLAS_GL_NS;
class SplineManager : public atlas::utils::Geometry {
public:
    SplineManager(int totalFrames);
    ~SplineManager();

    atlas::math::Point getSplinePosition();
    void addSplines();
    void showSpline();
    void showControlPoints();
    void showCage();
    void showSplinePoints();
    bool doneInterpolation();
    void updateGeometry(atlas::utils::Time const& t) override;
    void renderGeometry(atlas::math::Matrix4 projection, atlas::math::Matrix4 view) override;
private:
    std::vector<Spline> mSplines;
    std::vector<atlas::math::Point> mControlPoints;
    int mTotalFrames;
    int currentSpline;
    bool finishedAllSplines;
};
#endif

Spline.h

#ifndef LAB04_INCLUDE_SPLINE_HPP
#define LAB04_INCLUDE_SPLINE_HPP

#pragma once

#include <atlas/utils/Geometry.hpp>
#include <fstream>
class Spline : public atlas::utils::Geometry
{
public:
    Spline(int totalFrames, std::vector<atlas::math::Point> mControlPoints_);
    Spline(int totalFrames);
    ~Spline();

    void renderGeometry(atlas::math::Matrix4 projection,
        atlas::math::Matrix4 view) override;

    void updateGeometry(atlas::utils::Time const& t) override;

    void showControlPoints();
    void showCage();
    void showSplinePoints();
    void showSpline();
    bool doneInterpolation();

    atlas::math::Point getSplinePosition();
    void setSplineCoordinates(std::vector<atlas::math::Point> mControlPoints_);
private:
    atlas::math::Point interpolateOnSpline();

    atlas::math::Point evaluateSpline(float t);
    void generateArcLengthTable();
    int tableLookUp(float distance);
    float chooseEpsilon();

    atlas::math::Matrix4 mBasisMatrix;
    std::vector<atlas::math::Point> mControlPoints;

    std::vector<float> mTable;

    atlas::math::Point mSplinePosition;

    GLuint mVao;
    GLuint mControlBuffer;
    GLuint mSplineBuffer;

    int mResolution;
    int mTotalFrames;
    int mCurrentFrame;

    bool mShowControlPoints;
    bool mShowCage;
    bool mShowSplinePoints;
    bool mShowSpline;
    bool mIsInterpolationDone;
};

#endif

ClothScene.hpp

#ifndef SCENE_HPP
#define SCENE_HPP
#pragma once

#include <atlas\utils\Scene.hpp>
#include "ClothCamera.hpp"
#include "SplineManager.hpp"
#include "Grid.hpp"
#include "Spline.h"
#include "Ball.hpp"
//#include "Cloth.hpp"
class ClothScene : public atlas::utils::Scene {
public:
    ClothScene();
    ~ClothScene();

    void mousePressEvent(int button, int action, int modifiers, double xPos, double yPos) override;
    void mouseMoveEvent(double xPos, double yPos) override;
    void keyPressEvent(int key, int scancode, int action, int mods) override;
    void screenResizeEvent(int width, int height) override;
    void renderScene() override;
    void updateScene(double time) override;
private:
    bool mIsDragging;
    bool mIsPlaying;

    float mLastTime;
    float mFPS;
    float mTick;

    float mAnimTime;
    float mAnimLength;
    glm::vec3 ballPosition;
    ClothCamera mCamera;
    Grid mGrid;
    SplineManager mSplineManager;//, mSpline2;
    Ball mBall;

    std::vector<atlas::math::Point> mControlPoints;
};

#endif
Nick
  • 862
  • 12
  • 35
  • 1
    there is too much code, not sure someone will read all that. Could you reduce the code quoted ? – Pierre Emmanuel Lallemant Feb 06 '16 at 22:42
  • To me, your management of `Spline` objects (containing opengl object names) in a `std::vector` seems like you are running into the usual "GL objects get destroyed by the destructor while the names are copied" issue when wrapping GL objects naively in C++ objects. See [this answer](http://stackoverflow.com/questions/28929452/mesh-class-called-with-default-constructor-not-working-opengl-c/28930189#28930189) for more details. – derhass Feb 07 '16 at 19:07
  • @derhass, this is a great thought which completely escaped me. Thank you. – Nick Feb 07 '16 at 22:58

0 Answers0