Opengl Spazzing out for no reason

Started by
19 comments, last by 21st Century Moose 9 years, 5 months ago

Post a screenshot to give us a better idea of what's going on.

Advertisement

30nag68.jpg

I'll also add, as I said above, this is occuring in projects that worked perfectly fine before, but are now all spazzing out in the same way without any new changes.

If other OpenGL projects than your own are also now "spazzing out" then it is likely a hardware issue. If it is only your own then it is highly likely that as the other posters have been saying, you are in undefined behavior territory. In such a case, you do something wrong but there is no set way for the driver to deal with it. It might spaz out. It might silently ignore and seemingly function perfectly. It might nuke your harddrive. It might end the universe. That is what undefined behavior means.

If you are seeing displaced vertices and corruption over time, then you may have a heat or voltage issue. I have had it many times before, the last one being because my power unit could not give enough Watts to the GPU (and machine overall).

Here are some diagnosable examples from a random Google search:

http://www.playtool.com/pages/artifacts/artifacts.html

I had what happens in the second image, slow corruption over time. It was fixed by upgrading to a better PSU, and was not bad GPU memory.

This smells a lot like uninitialized memory or undefined behaviour to me.

Can you post code for where you load your matrices, your vertex data and how you submit draw calls (glDrawArrays, glDrawElements, etc)?

Get ready for code overload:

LOADING


bool MESH::Load(const char* filename)
{
	Clear();

	m_hasTexture = false;
	m_numBones = 0;

	std::vector<VECTOR3f> positions;
	std::vector<VECTOR3f> normals;
	std::vector<VECTOR2f> texCoords;
	std::vector<VertexBoneData> bones;
	std::vector<uint> indices;

	uint numVertices = 0;
	uint numIndices = 0;

	// Use assimp to get data from the file
	Assimp::Importer Importer;
	m_pScene = m_Importer.ReadFile(filename, aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs);

	if (!m_pScene)
	{
		printf("Error parsing '%s': '%s'\n", filename, Importer.GetErrorString());
		return false;
	}

	m_globalInverseTransform = m_pScene->mRootNode->mTransformation;
	m_globalInverseTransform.Inverse();

	// Make all vectors the appropriate size for the data
	m_objects.resize(m_pScene->mNumMeshes);

	for (uint i = 0; i < m_objects.size(); i++)
	{
		m_objects[i].numVertices	= m_pScene->mMeshes[i]->mNumVertices;
		m_objects[i].numIndices		= m_pScene->mMeshes[i]->mNumFaces * 3;
		m_objects[i].startVertex	= numVertices;
		m_objects[i].startIndex		= numIndices;

		numVertices += m_objects[i].numVertices;
		numIndices	+= m_objects[i].numIndices;
	}

	positions.reserve(numVertices);
	normals.reserve(numVertices);
	texCoords.reserve(numVertices);
	bones.resize(numVertices);
	indices.reserve(numIndices);

	// Initialize the meshes
	int fuck = m_objects.size();

	for (uint i = 0; i < m_objects.size(); i++)
	{
		const aiMesh* paiMesh = m_pScene->mMeshes[i];
		const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);

		// Populate Vertex Attributes
		for (uint j = 0; j < paiMesh->mNumVertices; j++)
		{
			const aiVector3D* aiTexCoord	= paiMesh->HasTextureCoords(0) ? &(paiMesh->mTextureCoords[0][j]) : &Zero3D;

			positions.push_back(VECTOR3f(paiMesh->mVertices[j].x, paiMesh->mVertices[j].y, paiMesh->mVertices[j].z));
			normals.push_back(VECTOR3f(paiMesh->mNormals[j].x, paiMesh->mNormals[j].y, paiMesh->mNormals[j].z));
			texCoords.push_back(VECTOR2f(aiTexCoord->x, aiTexCoord->y));
		}

		// Populate Indices
		for (uint j = 0; j < paiMesh->mNumFaces; j++)
		{
			const aiFace& face = paiMesh->mFaces[j];
			assert(face.mNumIndices == 3);

			indices.push_back(face.mIndices[0]);
			indices.push_back(face.mIndices[1]);
			indices.push_back(face.mIndices[2]);
		}

		// Load Bones for current Mesh
		for (uint j = 0; j < paiMesh->mNumBones; j++)
		{
			uint boneIndex = 0;
			std::string boneName(paiMesh->mBones[j]->mName.data);

			if (m_boneMapping.find(boneName) == m_boneMapping.end())
			{
				boneIndex = m_numBones;
				m_numBones++;
				m_boneInfo.push_back(BoneInfo());
				m_boneInfo[boneIndex].BoneOffset = paiMesh->mBones[j]->mOffsetMatrix;
				m_boneMapping[boneName] = boneIndex;
			}
			else
				boneIndex = m_boneMapping[boneName];

			m_boneMapping[boneName] = boneIndex;
			m_boneInfo[boneIndex].BoneOffset = paiMesh->mBones[j]->mOffsetMatrix;

			for (uint k = 0; k < paiMesh->mBones[j]->mNumWeights; k++)
			{
				uint VertexID = m_objects[i].startVertex + paiMesh->mBones[j]->mWeights[k].mVertexId;
				float weight = paiMesh->mBones[j]->mWeights[k].mWeight;
				bones[VertexID].AddBoneData(boneIndex, weight);
			}
		}
	}

	// Load the material (only using one for now)
	// We assume the texture file is in the same directory as the model file
	const aiMaterial* pMaterial = m_pScene->mMaterials[0];
	aiString path;
	if (pMaterial->GetTexture(aiTextureType_DIFFUSE, 0, &path, NULL, NULL, NULL, NULL, NULL) == AI_SUCCESS)
	{
		std::string::size_type startIndex = std::string(path.C_Str()).find_last_of("\\");
		if (startIndex == std::string::npos)
			startIndex = std::string(path.C_Str()).find_last_of("/");

		std::string texFilename;

		if (startIndex != std::string::npos)
		{
			texFilename = std::string(path.C_Str()).substr(startIndex + 1);
		}
		else
			texFilename = path.C_Str();

		// get texture path, and make it lower case		
		std::string texPath = std::string(filename).substr(0, std::string(filename).find_last_of("/")) + "/";
		
		for (uint i = 0; i < texFilename.length(); i++)
			texPath += texFilename[i];

		// Load Texture
		if (!m_texture.Load(texPath.c_str()))
		{
			printf("Failed to load texture: \"%s\"", texPath.c_str());
		}
		else
			m_hasTexture = true;
	}

	const aiNodeAnim* pNodeAnim = NULL;
	uint i = 0;

	while (!pNodeAnim)
	{
		pNodeAnim = FindNodeAnim(m_pScene->mAnimations[0], m_pScene->mRootNode->mChildren[i]->mName.data);
		i++;

		if (i > 500)	// Too many loops
			continue;
	}
		//FindNodeAnim(pAnimation, nodeName);
		//m_pScene->mAnimations[0]->mChannels->

	if (pNodeAnim)
	{
		m_animInfo.numKeyframes = pNodeAnim->mNumPositionKeys;
		m_animInfo.frameDuration = m_pScene->mAnimations[0]->mDuration / (pNodeAnim->mNumPositionKeys);
	}

	// Negate the last frame, as it is the same as the first
	m_animInfo.MaxAnimTime = m_animInfo.frameDuration * (m_animInfo.numKeyframes - 1);

	// Initialize buffers with the data
	InitBuffers(positions, normals, texCoords, indices, bones);

	return true;
}

bool MESH::InitBuffers(const std::vector<VECTOR3f>& positions,
					   const std::vector<VECTOR3f>& normals,
					   const std::vector<VECTOR2f>& texCoords,
					   const std::vector<uint>& indices,
					   const std::vector<VertexBoneData>& bones)
{
	// Create the VAO
	glGenVertexArrays(1, &m_VAO);
	glBindVertexArray(m_VAO);

	// Create the buffers for the vertices attributes
	glGenBuffers(ArraySizeInElements(m_buffers), m_buffers);



	// Generate and populate the buffers with vertex attributes and the indices
	glBindBuffer(GL_ARRAY_BUFFER, m_buffers[POS_VB]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(positions[0]) * positions.size(), &positions[0], GL_STATIC_DRAW);
	glEnableVertexAttribArray(POSITION_LOCATION);
	glVertexAttribPointer(POSITION_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, m_buffers[TEXCOORD_VB]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords[0]) * texCoords.size(), &texCoords[0], GL_STATIC_DRAW);
	glEnableVertexAttribArray(TEX_COORD_LOCATION);
	glVertexAttribPointer(TEX_COORD_LOCATION, 2, GL_FLOAT, GL_FALSE, 0, 0);

	glBindBuffer(GL_ARRAY_BUFFER, m_buffers[NORMAL_VB]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(normals[0]) * normals.size(), &normals[0], GL_STATIC_DRAW);
	glEnableVertexAttribArray(NORMAL_LOCATION);
	glVertexAttribPointer(NORMAL_LOCATION, 3, GL_FLOAT, GL_FALSE, 0, 0);

	if (m_numBones > 0)
	{
		glBindBuffer(GL_ARRAY_BUFFER, m_buffers[BONE_VB]);
		glBufferData(GL_ARRAY_BUFFER, sizeof(bones[0]) * bones.size(), &bones[0], GL_STATIC_DRAW);
		glEnableVertexAttribArray(BONE_ID_LOCATION);
		glVertexAttribIPointer(BONE_ID_LOCATION, 4, GL_INT, sizeof(VertexBoneData), (const GLvoid*)0);
		glEnableVertexAttribArray(BONE_WEIGHT_LOCATION);
		glVertexAttribPointer(BONE_WEIGHT_LOCATION, 4, GL_FLOAT, GL_FALSE, sizeof(VertexBoneData), (const GLvoid*)16);
	}

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[INDEX_BUFFER]);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), &indices[0], GL_STATIC_DRAW);
	


	glBindVertexArray(0);

	return true;
}

void MESH::Clear()
{
	if (m_buffers[0] != 0)
		glDeleteBuffers(ArraySizeInElements(m_buffers), m_buffers);

	if (m_VAO != 0)
	{
		glDeleteVertexArrays(1, &m_VAO);
		m_VAO = 0;
	}

	if (m_objects.size() > 0)
		m_objects.empty();
}

DRAWING


void GAME::RenderModels()
{
	// Draw Geometry / Scene Objects
	m_pipeline.MatrixMode(MODEL_MATRIX);
	m_pipeline.PushMatrix();

	stdShader->Bind();

		m_pipeline.CalcMatrices(stdShader->GetProgramID());
		plane.Render();
		
	stdShader->Unbind();
	skinShader->Bind();

		m_pipeline.RotateY(angle);
		m_pipeline.Scale(0.10f);
		//m_pipeline.Translate(0.0f, 0.0f, -6.0f);
		//m_pipeline.Translate(0.0f, 1.0f, 0.0f);

		std::vector<MATRIX4f> transforms;

		float time = m_timer.m_secsPassedSinceStart / ninja.GetAnimTime() * 0.5f;

		ninja.BoneTransform(time, transforms);

		for (uint i = 0; i < transforms.size(); i++)
			glUniformMatrix4fv(m_boneLocations[i], 1, GL_TRUE, (const GLfloat*)transforms[i].m_matrix);

		m_pipeline.Translate(0.0f, 0.0f, 1.0f);
		m_pipeline.CalcMatrices(skinShader->GetProgramID());
		ninja.Render();

	skinShader->Unbind();

	m_pipeline.PopMatrix();
}

void MESH::Render()
{
	glBindVertexArray(m_VAO);

	if (m_hasTexture)
		m_texture.Bind(GL_TEXTURE0);

	for (uint i = 0; i < m_objects.size(); i++)
	{
		glDrawElementsBaseVertex(GL_TRIANGLES,
								 m_objects[i].numIndices,
								 GL_UNSIGNED_INT,
								 (void*)(sizeof(uint) * m_objects[i].startIndex),
								 m_objects[i].startVertex);
	}

	if (m_hasTexture)
		m_texture.Unbind(GL_TEXTURE0);

	glBindVertexArray(0);
}

// This function simply has the bones be where they're supposed to be depending on the time in seconds passed in. At the moment its used as a loop
void MESH::BoneTransform(float& TimeInSeconds, std::vector<MATRIX4f>& transforms)
{
	MATRIX4f identity;
	identity.LoadIdentity();

	float ticksPerSecond = (float)(m_pScene->mAnimations[0]->mTicksPerSecond != 0 ? m_pScene->mAnimations[0]->mTicksPerSecond : 25.0f);
	float TimeInTicks = TimeInSeconds * ticksPerSecond;
    //float AnimationTime = fmod(TimeInTicks, (float)m_pScene->mAnimations[0]->mDuration);
	float AnimationTime = fmod(TimeInTicks, m_animInfo.MaxAnimTime);
	

	ReadNodeHeirarchy(AnimationTime, m_pScene->mRootNode, identity);

	transforms.resize(m_numBones);

	for (uint i = 0; i < m_numBones; i++)
		transforms[i] = m_boneInfo[i].FinalTransformation;
}

void MESH::ReadNodeHeirarchy(float AnimationTime, const aiNode* pNode, const MATRIX4f& ParentTransform)
{
	std::string nodeName(pNode->mName.data);

	const aiAnimation* pAnimation = m_pScene->mAnimations[0];

	MATRIX4f NodeTransformation(pNode->mTransformation);

	const aiNodeAnim* pNodeAnim = FindNodeAnim(pAnimation, nodeName);

	if (pNodeAnim)
	{
		// Interpolate scaling and generate scaling transformation matrix
        aiVector3D Scaling;
        CalcInterpolatedScaling(Scaling, AnimationTime, pNodeAnim);
        MATRIX4f ScalingM;
        ScalingM.InitScale(Scaling.x, Scaling.y, Scaling.z);
        
        // Interpolate rotation and generate rotation transformation matrix
        aiQuaternion RotationQ;
        CalcInterpolatedRotation(RotationQ, AnimationTime, pNodeAnim);        
        MATRIX4f RotationM = MATRIX4f(RotationQ.GetMatrix());

        // Interpolate translation and generate translation transformation matrix
        aiVector3D Translation;
        CalcInterpolatedPosition(Translation, AnimationTime, pNodeAnim);
        MATRIX4f TranslationM;
        TranslationM.InitTranslate(Translation.x, Translation.y, Translation.z);
        
        // Combine the above transformations
        NodeTransformation = TranslationM * RotationM * ScalingM;
	}

	MATRIX4f GlobalTransformation = ParentTransform * NodeTransformation;

	if (m_boneMapping.find(nodeName) != m_boneMapping.end())
	{
		uint boneIndex = m_boneMapping[nodeName];
		m_boneInfo[boneIndex].FinalTransformation = m_globalInverseTransform * GlobalTransformation * m_boneInfo[boneIndex].BoneOffset;;
	}

	for (uint i = 0; i < pNode->mNumChildren; i++)
		ReadNodeHeirarchy(AnimationTime, pNode->mChildren[i], GlobalTransformation);
}

Now this is where I suspect the problem may lie, however I don't really understand it:


void MESH::CalcInterpolatedPosition(aiVector3D& Out, float AnimationTime, const aiNodeAnim* pNodeAnim)
{
    if (pNodeAnim->mNumPositionKeys == 1) {
        Out = pNodeAnim->mPositionKeys[0].mValue;
        return;
    }
            
    uint PositionIndex = FindPosition(AnimationTime, pNodeAnim);
    uint NextPositionIndex = (PositionIndex + 1);
    assert(NextPositionIndex < pNodeAnim->mNumPositionKeys);
    float DeltaTime = (float)(pNodeAnim->mPositionKeys[NextPositionIndex].mTime - pNodeAnim->mPositionKeys[PositionIndex].mTime);
    float Factor = (AnimationTime - (float)pNodeAnim->mPositionKeys[PositionIndex].mTime) / DeltaTime;
	
	//assert(Factor >= 0.0f && Factor <= 1.0f);
    const aiVector3D& Start = pNodeAnim->mPositionKeys[PositionIndex].mValue;
    const aiVector3D& End = pNodeAnim->mPositionKeys[NextPositionIndex].mValue;
    aiVector3D Delta = End - Start;
    Out = Start + Factor * Delta;
}
void MESH::CalcInterpolatedRotation(aiQuaternion& Out, float AnimationTime, const aiNodeAnim* pNodeAnim)
{
	// we need at least two values to interpolate...
    if (pNodeAnim->mNumRotationKeys == 1) {
        Out = pNodeAnim->mRotationKeys[0].mValue;
        return;
    }
    
    uint RotationIndex = FindRotation(AnimationTime, pNodeAnim);
    uint NextRotationIndex = (RotationIndex + 1);
    assert(NextRotationIndex < pNodeAnim->mNumRotationKeys);
    float DeltaTime = (float)(pNodeAnim->mRotationKeys[NextRotationIndex].mTime - pNodeAnim->mRotationKeys[RotationIndex].mTime);
    float Factor = (AnimationTime - (float)pNodeAnim->mRotationKeys[RotationIndex].mTime) / DeltaTime;
    
	//assert(Factor >= 0.0f && Factor <= 1.0f);
    const aiQuaternion& StartRotationQ = pNodeAnim->mRotationKeys[RotationIndex].mValue;
    const aiQuaternion& EndRotationQ   = pNodeAnim->mRotationKeys[NextRotationIndex].mValue;    
    aiQuaternion::Interpolate(Out, StartRotationQ, EndRotationQ, Factor);
    Out = Out.Normalize();
}
void MESH::CalcInterpolatedScaling(aiVector3D& Out, float AnimationTime, const aiNodeAnim* pNodeAnim)
{
    if (pNodeAnim->mNumScalingKeys == 1) {
        Out = pNodeAnim->mScalingKeys[0].mValue;
        return;
    }

    uint ScalingIndex = FindScaling(AnimationTime, pNodeAnim);
    uint NextScalingIndex = (ScalingIndex + 1);
    assert(NextScalingIndex < pNodeAnim->mNumScalingKeys);
    float DeltaTime = (float)(pNodeAnim->mScalingKeys[NextScalingIndex].mTime - pNodeAnim->mScalingKeys[ScalingIndex].mTime);
    float Factor = (AnimationTime - (float)pNodeAnim->mScalingKeys[ScalingIndex].mTime) / DeltaTime;

	//assert(Factor >= 0.0f && Factor <= 1.0f);
    const aiVector3D& Start = pNodeAnim->mScalingKeys[ScalingIndex].mValue;
    const aiVector3D& End   = pNodeAnim->mScalingKeys[NextScalingIndex].mValue;
    aiVector3D Delta = End - Start;
    Out = Start + Factor * Delta;
}

You will notice i commented out the assertion because i do actually get values outside 0 and 1. I must confess I don't really understand this function.

Any help is greatly appreciated!

You will notice i commented out the assertion because i do actually get values outside 0 and 1.

So what do you think will happen to Factor at the end of the animation, or if 2 keyframes are on the same time-stamp, etc.?


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Have you tried calling glGetError()?

Aether3D Game Engine: https://github.com/bioglaze/aether3d

Blog: http://twiren.kapsi.fi/blog.html

Control

Sorry everyone I'm retarded.

My shader:


void main()
{
	mat4 BoneTransform;
	BoneTransform += gBones[BoneIDs[0]] * Weights[0];
	BoneTransform += gBones[BoneIDs[1]] * Weights[1];
	BoneTransform += gBones[BoneIDs[2]] * Weights[2];
	BoneTransform += gBones[BoneIDs[3]] * Weights[3];

bonetransform is just full of nothing. Changed to:


void main()
{
	mat4 BoneTransform = gBones[BoneIDs[0]] * Weights[0];
	BoneTransform += gBones[BoneIDs[1]] * Weights[1];
	BoneTransform += gBones[BoneIDs[2]] * Weights[2];
	BoneTransform += gBones[BoneIDs[3]] * Weights[3];

All better

So, it was well-defined undefined behavior after all :)

It's something we've all been struggling with over the years..

This topic is closed to new replies.

Advertisement