I have a problem with new vertices being rendered

So I run my program and I see a flicker of my model which I think means that the original vertices have been rendered and ether the new ones have not been passed correctly or they have been miscalculated. I am trying to do mesh skinnig on the CPU side so I can understand it before I do the work for the GPU. It runs at over 33fps on my machine. I want access to the skinned model for physics.

The Model class is probably not important but hear it is

#pragma once
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "assimp/Importer.hpp"
#include "assimp/scene.h"
#include "assimp/postprocess.h"
#include <iostream>
#include <vector>
#include "SkelMesh.h"
#include "Bones.h"

using namespace std;
class Model
{
public:

	Model(glm::vec3 pos = glm::vec3(0.0f), glm::vec3 siz = glm::vec3(1.0f));
	glm::vec3 position;
	glm::vec3 size;

	void init();
	void loadModel(string path);
	void render(ShaderProgram shade, glm::mat4 model);
	void cleanup();
	void setRotation(string name, glm::vec3 rotation);
	glm::vec3 getRotation(string name);
protected:
	vector<SkelMesh> meshes;
	
	
	void processNode(aiNode* node, const aiScene* scene);
	SkelMesh processMesh(aiMesh* mesh, const aiScene* scene);
	glm::mat4 assimpToGlmMatrix(aiMatrix4x4 mat);
};

#include "Model.h"

Model::Model(glm::vec3 pos, glm::vec3 siz)
	:position(pos), size(siz)
{}
void Model::init() {}

void Model::loadModel(string path) {
	Assimp::Importer importer;
	const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate);
	if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
		cout << "could not load Model at " << path << " " << importer.GetErrorString() << endl;
		return;
	}
	
	processNode(scene->mRootNode, scene);
}

void Model::render(ShaderProgram shade, glm::mat4 model) {
	
	shade.setUniform("model", model);

	for (SkelMesh mesh : meshes) {
		mesh.render(shade);
	}
}
void Model::cleanup() {
	for (SkelMesh mesh : meshes) {
		mesh.cleanup();
	}
}

void Model::processNode(aiNode* node, const aiScene* scene) {
	for (unsigned int i = 0; i < node->mNumMeshes; i++) {
		aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
		meshes.push_back(processMesh(mesh, scene));
	}
	for (unsigned int i = 0; i < node->mNumChildren; i++) {
		processNode(node->mChildren[i], scene);
	}
}
SkelMesh Model::processMesh(aiMesh* mesh, const aiScene* scene) {
	vector<Vertex> vertices;
	vector<unsigned int> induces;
	
	
	for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
		Vertex vertex;
		vertex.position = glm::vec3(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z);
		vertex.normal = glm::vec3(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z);
		if (mesh->mTextureCoords[0]) {
			vertex.texCoords = glm::vec2(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y);
		}
		else {
			vertex.texCoords = glm::vec2(0.0f);
		}
		vertices.push_back(vertex);
	}
	for (unsigned int i = 0; i < mesh->mNumFaces; i++) {
		aiFace face = mesh->mFaces[i];
		for (unsigned int j = 0; j < face.mNumIndices; j++) {
			induces.push_back(face.mIndices[j]);
		}
	}
	
	for (unsigned int i = 0; i < mesh->mNumBones; i++) {
		aiBone* bone = mesh->mBones[i];
		glm::mat4 m = assimpToGlmMatrix(bone->mOffsetMatrix);
		for (int j = 0; j < bone->mNumWeights; j++) {
			unsigned int id = bone->mWeights[j].mVertexId;
			float weight = bone->mWeights[j].mWeight;
		}
	}
	return SkelMesh(vertices, induces, mesh, scene);
}

glm::mat4 Model::assimpToGlmMatrix(aiMatrix4x4 mat) {
	glm::mat4 m;
	for (int y = 0; y < 4; y++)
	{
		for (int x = 0; x < 4; x++)
		{
			m[x][y] = mat[y][x];
		}
	}
	return m;
}

void Model::setRotation(string name, glm::vec3 rotation) {
	meshes[0].setRotation(name, rotation);
}
glm::vec3 Model::getRotation(string name) {
	return meshes[0].getRotation(name);
}

The Mesh class

#pragma once
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"
#include <vector>
#include "Texture2D.h"
#include "ShaderProgram.h"
#include "Mesh.h"
#include "Bones.h"
#include "assimp/scene.h"
#include "assimp/postprocess.h"
using namespace std;

typedef struct Vertex;
class SkelMesh
{
public:
	SkelMesh();
	SkelMesh(vector<Vertex> verts, vector<unsigned int>indus, aiMesh* mesh, const aiScene* scene);
	vector<Vertex> vertices;
	vector<unsigned int> induces;
	unsigned int VAO;
	void setRotation(string name, glm::vec3 rotation);
	glm::vec3 getRotation(string name);
	void render(ShaderProgram shade);
	void cleanup();
private:
	aiMesh* amesh;
	const aiScene* ascene;
	Bones armatures;
	unsigned int IBO, VBO;
	void setup();
};


#include "SkelMesh.h"

vector<struct Vertex> Vertex::genList(float* vertices, int vertNum) {
	vector<Vertex> ret(vertNum);
	int stride = sizeof(Vertex) / sizeof(float);
	for (int i = 0; i < vertNum; i++) {
		ret[i].position = glm::vec3{
			vertices[i * stride],
			vertices[i * stride + 1],
			vertices[i * stride + 2]
		};
		ret[i].normal = glm::vec3{
			vertices[i * stride + 3],
			vertices[i * stride + 4],
			vertices[i * stride + 5]
		};
		ret[i].texCoords = glm::vec2{
			vertices[i * stride + 6],
			vertices[i * stride + 7]
		};
	}
	return ret;
}

SkelMesh::SkelMesh() {

}
SkelMesh::SkelMesh(vector<Vertex> verts, vector<unsigned int>indus, aiMesh* mesh, const aiScene* scene)
	:vertices(verts), induces(indus), amesh(mesh), ascene(scene)
{
	setup();
	
}
void SkelMesh::render(ShaderProgram shade) {
	armatures.update();
	unsigned int diffuseIdx = 0;
	unsigned int specularIdx = 0;
	//shade.use();
	glBindVertexArray(VAO);
	glDrawElements(GL_TRIANGLES, induces.size(), GL_UNSIGNED_INT, 0);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &armatures.newVertices[0], GL_DYNAMIC_DRAW);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, induces.size() * sizeof(unsigned int), &induces[0], GL_DYNAMIC_DRAW);
	glBindVertexArray(0);
	glActiveTexture(GL_TEXTURE0);
}
void SkelMesh::cleanup() {
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	glDeleteBuffers(1, &IBO);
}
void SkelMesh::setup() {
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glGenBuffers(1, &IBO);
	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_DYNAMIC_DRAW);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, induces.size() * sizeof(unsigned int), &induces[0], GL_DYNAMIC_DRAW);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
	glEnableVertexAttribArray(0);

	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));
	glEnableVertexAttribArray(1);

	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texCoords));
	glEnableVertexAttribArray(2);
	glBindVertexArray(0);
	armatures.init(amesh, vertices, ascene);
}

void SkelMesh::setRotation(string name, glm::vec3 rotation) {
	armatures.setRotation(name, rotation);
}
glm::vec3 SkelMesh::getRotation(string name) {
	return armatures.getRotation(name);
}

Armatures class.

#pragma once
#include <vector>
#include <string>
#include <unordered_map>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "assimp/scene.h"
#include "assimp/postprocess.h"
#include "Mesh.h"
using namespace std;
struct boneVert {
	vector<int> ids;
	vector<float> weights;
};
struct Bone {
	int id = 0; // position of the bone in final upload array
	string name = "";
	glm::mat4 offset = glm::mat4(1.0f);
	vector<Bone> children = {};
};


class Bones
{
public:
	vector<Vertex> origVertices;
	vector<Vertex> newVertices;
	vector<boneVert> boneVerts;
	void init(aiMesh* mesh, vector<Vertex> inpos, const aiScene* scene);
	void setRotation(string name, glm::vec3 rotation);
	glm::vec3 getRotation(string name);
	void update();
	void updateVerts(vector<glm::mat4> boneTransforms);
private:
	glm::mat4 globalInverseTransform;
	unordered_map<string, glm::vec3> rots;
	Bone structure;
	std::vector<glm::mat4> currentPose = {};
	void getPose(Bone& skeletion, std::vector<glm::mat4>& output, glm::mat4& parentTransform, glm::mat4& globalInverseTransform);
	bool readSkeleton(Bone& boneOutput, aiNode* node, std::unordered_map<std::string, std::pair<int, glm::mat4>>& boneInfoTable);
	glm::mat4 assimpToGlmMatrix(aiMatrix4x4 mat);
};


#include "Bones.h"

void Bones::init(aiMesh* mesh, vector<Vertex> inpos, const aiScene* scene) {
	std::unordered_map<std::string, std::pair<int, glm::mat4>> boneInfo = {};
	origVertices = inpos;
	
	for (int i = 0; i < origVertices.size(); i++) {
		Vertex tran1;
		tran1 = origVertices.at(i);
		newVertices.push_back(tran1);
		boneVert tran;
		boneVerts.push_back(tran);
	}
	for (unsigned int i = 0; i < mesh->mNumBones; i++) {
		aiBone* bone = mesh->mBones[i];
		glm::mat4 m = assimpToGlmMatrix(bone->mOffsetMatrix);
		boneInfo[bone->mName.C_Str()] = { i, m };
		rots[bone->mName.C_Str()] = glm::vec3(0, 0, 0);
		
		float total = 0;
		for (int j = 0; j < bone->mNumWeights; j++) {
			unsigned int id = bone->mWeights[j].mVertexId;
			float weight = bone->mWeights[j].mWeight;
			boneVerts.at(id).ids.push_back(i);
			
			total += weight;
		}
		for (int j = 0; j < bone->mNumWeights; j++) {
			unsigned int id = bone->mWeights[j].mVertexId;
			float weight = bone->mWeights[j].mWeight;
			boneVerts.at(id).weights.push_back(weight / total);
		}
	}
	glm::mat4 toinverse = assimpToGlmMatrix(scene->mRootNode->mTransformation);
	globalInverseTransform = glm::inverse(toinverse);
	readSkeleton(structure, scene->mRootNode, boneInfo);
}

bool Bones::readSkeleton(Bone& boneOutput, aiNode* node, std::unordered_map<std::string, std::pair<int, glm::mat4>>& boneInfoTable) {

	if (boneInfoTable.find(node->mName.C_Str()) != boneInfoTable.end()) { // if node is actually a bone
		boneOutput.name = node->mName.C_Str();
		boneOutput.id = boneInfoTable[boneOutput.name].first;
		boneOutput.offset = boneInfoTable[boneOutput.name].second;

		for (int i = 0; i < node->mNumChildren; i++) {
			Bone child;
			readSkeleton(child, node->mChildren[i], boneInfoTable);
			boneOutput.children.push_back(child);
		}
		return true;
	}
	else { // find bones in children
		for (int i = 0; i < node->mNumChildren; i++) {
			if (readSkeleton(boneOutput, node->mChildren[i], boneInfoTable)) {
				return true;
			}

		}
	}
	return false;
}
void Bones::setRotation(string name, glm::vec3 rotation) {
	glm::vec3 conv = glm::vec3(glm::radians(rotation.x), glm::radians(rotation.y), glm::radians(rotation.y));
	rots[name] = conv;
}
glm::vec3 Bones::getRotation(string name) {
	glm::vec3 rotations = rots[name];
	return glm::vec3(glm::degrees(rotations.x), glm::degrees(rotations.y), glm::degrees(rotations.z));
}
void Bones::update() {
	glm::mat4 identity(1.0f);
	vector<glm::mat4> transforms;
	transforms.resize(50);
	getPose(structure, transforms, identity, globalInverseTransform);
	updateVerts(transforms);
}
void Bones::updateVerts(vector<glm::mat4> boneTransforms) {
	for (int i = 0; i < boneVerts.size(); i++) {
		glm::mat4 boneTrans(0.0f);
		for (int j = 0; j < boneVerts.at(i).ids.size(); j++) {
			boneTrans += boneTransforms.at(boneVerts.at(i).ids.at(j)) * boneVerts.at(i).weights.at(j);
		}
		glm::vec3 posin = origVertices.at(i).position;
		glm::vec4 posout = boneTrans * glm::vec4(posin, 1.0f);
		glm::vec3 apos = glm::vec3(posout.x, posout.y, posout.z);
		newVertices.at(i).position = apos;
	}
}

void Bones::getPose(Bone& skeletion, std::vector<glm::mat4>& output, glm::mat4& parentTransform, glm::mat4& globalInverseTransform) {
	glm::vec3 rotVal(0, 0, 0);
	unordered_map<string, glm::vec3>::iterator itr;
	for (itr = rots.begin(); itr != rots.end(); itr++) {
		if (itr->first == skeletion.name) {
			rotVal = itr->second;
			break;
		}
	}
	//glm::vec3 rotVal = rots[skeletion.name];
	glm::mat4 iden(1.0f);
	glm::mat4 boneRot = glm::rotate(iden, rotVal.x, glm::vec3(1, 0, 0)) * glm::rotate(iden, rotVal.y, glm::vec3(0, 1, 0)) * glm::rotate(iden, rotVal.z, glm::vec3(0, 0, 1));
	glm::mat4 globalTransform = parentTransform * boneRot;
	
	
	
	output[skeletion.id] = globalInverseTransform * globalTransform * skeletion.offset;
	
	for (Bone& child : skeletion.children) {
		getPose(child, output, globalTransform, globalInverseTransform);
	}
}

glm::mat4 Bones::assimpToGlmMatrix(aiMatrix4x4 mat) {
	glm::mat4 m;
	for (int y = 0; y < 4; y++)
	{
		for (int x = 0; x < 4; x++)
		{
			m[x][y] = mat[y][x];
		}
	}
	return m;
}

There is a lot of C++ wrappage code here that has nothing to do with OpenGL rendering. Most folks (all?) aren’t going to wade through all this to debug your program for you.

Suggestion for troubleshooting:

  1. Disable all this code, and render 2 simple models, each one rendered on alternate frames. Get that working first. Use the same context creation and GL state to render these as you do your SkelMesh.
  2. Use a GL call trace tool, extract just the GL calls your app is making during a frame, and inspect that. You’ll very likely spot the problem. If not, post that here (init + 1-2 frames of rendering)

This is pretty well all the OpenGL-related code you posted:

You don’t show where you’re clearing the color and depth buffers at the beginning of the frame, nor where you’re calling SwapBuffers to display it at the end of the frame. We also don’t see where you’re creating the context and setting up the GL state that you’re rendering your SkelMesh instances with. That may explain the artifact you’re seeing.