Jump to content

  • Log In with Google      Sign In   
  • Create Account


uglybdavis

Member Since 06 Mar 2012
Offline Last Active Aug 05 2014 09:23 AM

#5167639 Dissecting idTech4

Posted by uglybdavis on 18 July 2014 - 11:02 AM

Dissecting a production engine is never a fun learning experience. In production, things make it into code that shouldn't. That's just life.

 

How about starting with a more modern engine, that was made specifically to learn from: 

https://github.com/blackberry/GamePlay

 

There is an older GDC video about it, but i lost the link.




#5160530 Visual Studio 2013 _tmain ?

Posted by uglybdavis on 14 June 2014 - 12:29 PM

Thank you! That is the exact info i needed!!




#5145709 I need help with matrices

Posted by uglybdavis on 09 April 2014 - 10:18 AM

I think the core question here is, how to directly modify a matrix, instead of storing an additional data for position, rotation, scale and then rebuilding the matrix

 

For this, i'll point you to what i guess is the canonical resource on matrices: http://www.cs.princeton.edu/~gewang/projects/darth/stuff/quat_faq.html

If you look at the breakdown of the matrix composition, M[3][0] M[3][1] M[3][2] holds the translation vector. So, a function to set the position would simply modify these three bits of the matrix.

 

I hope this addresses the question.

Good luck!




#5143733 Need help finding an open source game with GLSL 330 or newer

Posted by uglybdavis on 01 April 2014 - 11:12 AM

http://www.gameplay3d.org/




#5137952 Instruments and memory usage going up without any leaks

Posted by uglybdavis on 10 March 2014 - 04:43 PM

From: http://memo.tv/archive/memory_management_with_objective_c_cocoa_iphone

 

An autorelease pool is an instance of NSAutoreleasePool and defines a scope for temporary objects (objects which are to be autoreleased). Any objects which are to be autoreleased (e.g. objects you send the autorelease message to or created with convenience methods) are added to the current autorelease pool. When the autorelease pool is popped (released) all objects that were added to it are also automatically released. This is a simple way of managing automatic release for objects which are needed temporarily.

E.g. You want to create a bunch of objects for temporary calculations, and instead of keeping track of all the local variables you define and then calling release for all of them at the end of your function, you can create them all with autorelease (or convenience methods) safe in the knowledge that they are going to be released next time the autorelease pool is popped. Note: there is a downside to this which I'll discuss in the Convenience vs Explicit section.

Autorelease pools can be nested, in which case autorelease objects are added to the latest autorelease pool to be created (the pools are stacked in a Last In First Out type stack).

 

Do you have any auto release pools? If so they are probably in a context that doesn't get destroyed (such as main)




#5134156 C++ IDEs for Linux

Posted by uglybdavis on 24 February 2014 - 12:03 PM

I'm currently using mono-develop, it's pretty awesome (though minimalistic)!

 

sudo apt-get install software-properties-common

sudo add-apt-repository ppa:keks9n/monodevelop-latest
sudo apt-get update
sudo apt-get install monodevelop-latest



#5131652 [Assimp] Getting bind pose bone positions

Posted by uglybdavis on 15 February 2014 - 11:16 PM

To my knowledge, assimp does not store bind pose.

 

The skeleton you have is stored in whatever frame 1 is.

 

The offset matrix is what you need to multiply a vertex (taking the joint's weight into account) by in order to get it into the bone space of frame 1.

 

I love assimp, but i can't stand the datastructures / orgonization / matrix handedness they chose.




#5129073 Flattening some polygons into an arbitrary plane

Posted by uglybdavis on 05 February 2014 - 11:06 AM

struct Plane {

  vec3 normal;

  float distance;

 

  Plane(const vec3& point, const vec3& norm) {

      normal = normalize(norm);

      distance = -dot(normal, point);

  }

 

  vec3 ProjectPoint(const vec3& point) {

      vec3 pointOnPlane = (-normal) * distance;

      float dist = dot(normal, point - pointOnPlane);

      return point - dist * normal;

  }

};

 

The constructor takes any point on the plane, and a normal.

The ProjectPoint function takes any arbitrary 3D point and returns that point projected onto the plane.




#5128785 GLM rotation isn't working right?

Posted by uglybdavis on 04 February 2014 - 12:53 PM

Scale it, Rotate it, Translate it. Correct.

 

OpenGL's (and glm) matrix multiplication works in reverse.

This is because the matrix is column major.

 

Scale, Translate, Rotate = rotate * translate * scale

 

Model, View, Projection = projection * model * view




#5127332 Raw draw functions in Game Engine (C++)?

Posted by uglybdavis on 29 January 2014 - 05:58 PM

If you already have drawing functionality in place, you just need to load models. Almost every package can export to .obj files.

Easy to use parser: https://github.com/tamato/simple-obj-loader




#5089332 GDI+ DrawString Invalid Parameter

Posted by uglybdavis on 26 August 2013 - 06:41 PM

Set length to -1, instead of 1. The proper number to pass in for you would be 2, it expects the number of characters, not string length.

 

http://msdn.microsoft.com/en-us/library/windows/desktop/ms535993(v=vs.85).aspx

 

Integer that specifies the number of characters in the string array. The length parameter can be set to –1 if the string is null terminated.

 



#5076992 OpenGL Connundrum

Posted by uglybdavis on 11 July 2013 - 06:15 PM

Nothing is going to solve the problem of not having proper drivers. Nothing.

 

From the original post i gather that the game must work under OpenGL 1.1 emulated environment (Hence no ANGLE). There was no mention of it needing to be performant. 

 

 

It honestly sounds to me like the idea of the assignment is to implement multiple render paths, which is what the poster seems to want to avoid.

 

Could be wrong tough....




#5072935 how to I design my mesh class

Posted by uglybdavis on 25 June 2013 - 10:49 PM

You should look at a 3D format like collada. Maybe milkshape would be easier to start with.

It's a tad harder, but assimp is interesting to work with, definateley has good data layout.

 

You will save yourself a LOT of toruble by seperating a mesh into mesh data (vertex soup), submesh data (indices into the soup), skeleton data and animation data. Assuming at some point you want to animate these things.

struct MeshData {
    // Positions, normals, uv's basically one big mesh soup
    unsigned int m_nVertexBuffer;
};

struct SubmeshData {
    // Just indices into the mesh soup
    unsigned int m_nIndexBuffer;
    unsigned int m_nMaterialIndex; // Indexes into mesh classes materials
};

struct Mesh { // Tough, i'd call this 'struct Model'
    MeshData mesh;
    std::vector<SubmeshData> submeshes;
    SkeletonData skeleton;
    std::vector<ClipData> animations;
    std::vector<Material> materials; // All the materials submeshes may use
    // Materials are shaders with some way of setting uniform data.
};

Rendering would be something like:

void RenderMesh(Mesh& mesh) {
   mesh.BindVertexBuffer();
   for (int i = 0; i < mesh.submeshes; ++i) {
      Submesh& submesh = mesh.submeshes[i];
      submesh.BindMaterial();
      submesh.DrawIndexBuffer();
      submesh.UnbindMaterial();
   }
   mesh.UnbindVertexBuffer();
}

Keep in mind, there is no logic up there. It's all data! you would also need something to represent the current animation state. Also, vbo's are useful when animating on the gpu, you will need to hold on to vertex data for cpu animation.

 

Edit: Did not read your post about needing to traverse triangles from outside, sorry.




#5068470 CPU Skinning, mesh to joint space (Offset matrix)

Posted by uglybdavis on 09 June 2013 - 02:01 PM

Turns out my hunch was right.

First, i got the bind pose from the mOffsetMatrix assimp has.

4.png

 

Holly crap that works. I can bind correctly now! Then lets play an animation:

5.png

 

Poop. That's not right. Everything is skinned correctly, and even moves correctly, but is oriented wrong. Why? Well after a few hours of debugging i realized assimp is only exporting bones that skin at least one vertex. So the bones in the model used to position everything are well, not there. Not a big problem tough, i'm going to convert assimps position of the bone to a local offset, then add that local offset to the parent bone in bind space to get the missing bones in bind space (I didn't do this yet because by the time i figured it out it was 4 am, but after i'm done running errands for the day, i'll get to it)

 

For your questions:

There is a rotating camera in place, i just take screenshots as son as the app loads. They are all slightly differently rotated :)

 

Image 2 is just me skinning everything with assimps data, i'm trying to convert to my own format where we have one mesh file, one skeleton file and multiple clip files. The mesh and skeleton both need to be in bind pose

 

Image 3 above is screwed up because i was trying to skin a bind pose mesh, to a non-bind pose skeleton

 

Yeah, i realize what the offset matrix is. I play a bit fast and loose with terminology (I should really buckle down and use proper terms)

 

Images 2 and 3 from my previous pose show the skeleton i had, in frame 1. Image 1 here shows bind position

 

Unfortunately i can't post the model (It's from 3drt.com, bikers collections)

 

This problem is pretty much solved. Thanks for helping me hash it out.

 

This is the second time assimp got me with storing data in a manner i didn't expect it to. I wish there was more documentation on the topic. One day, when i have some time to write it maybe i'll go ahead and create said documentation.

 

For future googlers:

Assimp does not store the skeleton of your animation in bind pose. It stores frame 1 of the files animation (With .x and collada files anyway)

To get the bind pose first collect your skeleton by looping trough each bone each mesh, and all of the parents of said bone:

std::vector<std::string> CollectBoneNames(aiScene* scene) {
    std::vector<std::string> bones;
    for(int i = 0; i < scene->mNumMeshes; ++i) {
        std::string meshName = scene->mMeshes[i]->mName.data;
        aiNode* meshNode = FindNode(scene->mRootNode, meshName);
        
        for (int j = 0; j < scene->mMeshes[i]->mNumBones; ++j) {
            std::string boneName = scene->mMeshes[i]->mBones[j]->mName.data;
            aiNode* boneNode = FindNode(scene->mRootNode, boneName);
            
            while (boneNode != 0 && boneNode != meshNode) {
                boneName = boneNode->mName.data;
                bool contains = std::find(bones.begin(), bones.end(), boneName) != bones.end();
                if (!contains)
                    bones.push_back(boneName);
                boneNode = boneNode->mParent;
            }
        }
    }
    return bones;
}

 

Now, bones will have a mOffset variable, This is the inverse bind pose. Get every bone in world space:

Matrix GetWorldMat(aiBone* bone) {
    aiMatrix4x4 matAbs = bone->mOffsetMatrix.Inverse();
    return FromTransposedSource(&matAbs.a1);
}

 

Remember, not every node that is a part of the skeleton is a bone. The ones not bones you need to get their global transform, multiply it by the inverse of the nodes parent global transform to get a local offset. Add this local offset to the parent bone in world space, to get the nodes with no bones in the same space as everything else in bind pose.

 

At this point you have bind pose, with every joint being in global space, i prefer my joints stored relative to their parents. Just multiply every joint by the inverse of its parent (Traverse your hierarchy bottom up)

for (int i = int(skeleton.size()) - 1; i >= 0; --i) {
        Joint& joint = target->m_vSkeleton[i];
        
        if (joint.parent != -1)
            joint.working = Multiply(joint.working, Inverse(target->m_vSkeleton[joint.parent].working));
        
        joint.rotation = ToQuaternion(joint.working);
        joint.translation = ToVector4(joint.working);
    }



#5029906 memory and not using NEW ?

Posted by uglybdavis on 07 February 2013 - 06:25 PM

The simplest example in C++ i can think of:

#include "CModel.h"

class NotSoGreatFactory {
protected:
	std::vector<CModel*> m_vPreAllocatedModels;
public:
	~NotSoGreatFactory {
		ClearReferences();
	}
	
	void ClearReferences() {
		for (int i = 0, size = int(m_vPreAllocatedModels.size(); i < size; ++i)
			delete m_vPreAllocatedModels[i];
		m_vPreAllocatedModels.clear();
	}
	
	CModel* GetModel() {
		if (m_vPreAllocatedModels.size() >= 1) {
			CModel* target = m_vPreAllocatedModels.pop_back();
			target->Reset();
			return target;
		} else return new CModel();
	}
	
	void ReturnModel(CModel* model) {
		m_vPreAllocatedModels.push_back(model);
	}
};

// And then in your code
NotSoGreatFactory modelFactory;
for (int i = 0; i < 100000; ++i) {
	CModel* tempModel = modelFactory.GetModel();
	// Do some stuff until temp model is no longer needed
	modelFactory.ReturnModel(tempModel);
}

 

In this scenario we only ever allocate one model.

Start with that, see how you can improve.






PARTNERS