I am loading 3D models from multiple formats, each possibly with its own coordinate system.
Transforming them so that they are all in the same coordinate system is easy.
The issue is when I try to attach one model to another, when both are of the same format.
Because they were already in the same coordinate system, the transformation that changes them to whatever shared coordinate system will be applied twice to the child.
I could make specific code for each format, and every time I want to attach something to another something, check formats, and ughhhh.
My current node structure is very generic, and I wonder if there is a generic solution to this problem.
Once the models are in your program, they should no longer be in "its own coordinate system." Pick a convention and stick to it.
If you're loading models that have a different convention, that's fine. But you transform their vertices after loading them. So there's no need to fiddle around with coordinate system transforms in your scene graph.
Related
I am building a small game engine and using fbx sdk to ipmort fbx mesh and animation, which means I want to store animation in my own class. Now, there are two ways to achieve this:
The first way is to store key frames only. If I store key frames only, I will have the raw animation data within the fbx file, and I can manipulate or adjust the animation whenever I want.
The second way is to sample frames at a fixed rate. Instead of storing key frames, I obtain some of the frames that I need from the fbx file and store them. This way, I may lost the raw animation data, because when I sample frames, the chosen frames may not be the key frames, resulting in minor loss of details.
From my perspective, the first way is the best way but most of the tutorails on the Internet are using the second way. For example, here. Below is a snippet of it:
for (FbxLongLong i = start.GetFrameCount(FbxTime::eFrames24); i <= end.GetFrameCount(FbxTime::eFrames24); ++i)
{
FbxTime currTime;
currTime.SetFrame(i, FbxTime::eFrames24);
*currAnim = new Keyframe();
(*currAnim)->mFrameNum = i;
FbxAMatrix currentTransformOffset = inNode->EvaluateGlobalTransform(currTime) * geometryTransform;
(*currAnim)->mGlobalTransform = currentTransformOffset.Inverse() * currCluster->GetLink()->EvaluateGlobalTransform(currTime);
currAnim = &((*currAnim)->mNext);
}
Notice that the function EvaluateGlobalTransform(..) is an fbxsdk function and it seems the only safe interface between us and an fbx animation on which we can rely. Also it seems the second way(use EvaluateGlobalTransform to sample at a specific rate) is the standard and commonly accepted way to do the job. And there is an explation says:
"The FBX SDK gives you a number of ways to get the data you might
want. Unfortunately due to different DCC tools (Max/Maya/etc) you may
not be able to get exactly the data you want. For instance, let's say
you find the root bone and it has translation on it in the animation.
You can access the transform in a number of ways. You can use the
LclTransform property and ask for the FbxAMatrix at various times. Or
you can call the evaluation functions with a time to get the matrix.
Or you can use the evaluator's EvaluateNode function to evaluate the
node at a time. And finally, the most complicated version is you can
get the curve nodes from the properties and look at the curve's keys.
Given all those options, you might think getting the curves would be
the way to go. Unfortunately Maya, for instance, bakes the animation
data to a set of keys which have nothing to do with the keys actually
setup in Maya. The reason for this is that the curves Maya uses are
not the same as those FBX supports. So, even if you get the curves
directly, they may have hundreds of keys in them since they might have
been baked.
What this means is that basically unless Max has curves supported by
FBX, it may be baking them and you won't have a way to find what the
original two poses in your terms were. Generally you will iterate
through time and sample the scene at a fixed rate. Yup, it kinda sucks
and generally you'll want to simplify the data after sampling."
To sum up:
The first way:
pros: easy to manipulate and adjust, accurate detail, less memory comsuption(if you generate your vertex transformation matrix on the fly)
cons:difficult to get these key frames, not applicable to some fbx files
The second way:
pros:easy to get chosen frames, adaptable to all fbx files
cons:difficult to change the animation, large memory comsuption, inaccurate details
So, my questions are:
Is the second way really is the common way to do this?
Which way do the famous game engines, like Unreal and Unity, use?
If I want to use the first way even though it may not work under some circumstances, how can I get only key frames from an fbx file(i.e. not using EvaluateGlobalTransform but working with FbxAnimStack, FbxAnimLayer, FbxAnimCurveNode, FbxAnimCurve, FbxAnimCurveKey)?
In short: What is the "preferred" way to wrap OpenGL's buffers, shaders and/or matrices required for a more high level "model" object?
I am trying to write this tiny graphics engine in C++ built on core OpenGL 3.3 and I would like to implement an as clean as possible solution to wrapping a higher level "model" object, which would contain its vertex buffer, global position/rotation, textures (and also a shader maybe?) and potentially other information.
I have looked into this open source engine, called GamePlay3D and don't quite agree with many aspects of its solution to this problem. Is there any good resource that discusses this topic for modern OpenGL? Or is there some simple and clean way to do this?
That depends a lot on what you want to be able to do with your engine. Also note that these concepts are the same with DirectX (or any other graphic API), so don't focus too much your search on OpenGL. Here are a few points that are very common in a 3D engine (names can differ):
Mesh:
A mesh contains submeshes, each submesh contains a vertex buffer and an index buffer. The idea being that each submesh will use a different material (for example, in the mesh of a character, there could be a submesh for the body and one for the clothes.)
Instance:
An instance (or mesh instance) references a mesh, a list of materials (one for each submesh in the mesh), and contains the "per instance" shader uniforms (world matrix etc.), usually grouped in a uniform buffer.
Material: (This part changes a lot depending on the complexity of the engine). A basic version would contain some textures, some render states (blend state, depth state), a shader program, and some shader uniforms that are common to all instances (for example a color, but that could also be in the instance depending on what you want to do.)
More complex versions usually separates the materials in passes (or sometimes techniques that contain passes) that contain everything that's in the previous paragraph. You can check Ogre3D documentation for more info about that and to take a look at one possible implementation. There's also a very good article called Designing a Data-Driven Renderer in GPU PRO 3 that describes an even more flexible system based on the same idea (but also more complex).
Scene: (I call it a scene here, but it could really be called anything). It provides the shader parameters and textures from the environment (lighting values, environment maps, this kind of things).
And I thinks that's it for the basics. With that in mind, you should be able to find your way around the code of any open-source 3D engine if you want the implementation details.
This is in addition to Jerem's excellent answer.
At a low level, there is no such thing as a "model", there is only buffer data and the code used to process it. At a high level, the concept of a "model" will differ from application to application. A chess game would have a static mesh for each chess piece, with shared textures and materials, but a first-person shooter could have complicated models with multiple parts, swappable skins, hit boxes, rigging, animations, et cetera.
Case study: chess
For chess, there are six pieces and two colors. Let's over-engineer the graphics engine to show how it could be done if you needed to draw, say, thousands of simultaneous chess games in the same screen, instead of just one game. Here is how you might do it.
Store all models in one big buffer. This buffer has all of the vertex and index data for all six models clumped together. This means that you never have to switch buffers / VAOs when you're drawing pieces. Also, this buffer never changes, except when the user goes into settings and chooses a different style for the chess pieces.
Create another buffer containing the current location of each piece in the game, the color of each piece, and a reference to the model for that piece. This buffer is updated every frame.
Load the necessary textures. Maybe the normals would be in one texture, and the diffuse map would be an array texture with one layer for white and another for black. The textures are designed so you don't have to change them while you're drawing chess pieces.
To draw all the pieces, you just have to update one buffer, and then call glMultiDrawElementsIndirect()... once per frame, and it draws all of the chess pieces. If that's not available, you can fall back to glDrawElements() or something else.
Analysis
You can see how this kind of design won't work for everything.
What if you have to stream new models into memory, and remove old ones?
What if the models have different size textures?
What if the models are more complex, with animations or forward kinematics?
What about translucent models?
What about hit boxes and physics data?
What about different LODs?
The problem here is that your solution, and even the very concept of what a "model" is, will be very different depending on what your needs are.
I'm provided with an application which renders highly complex geometries either via X11 or OpenGL (a computed voronoi diagram and other things).
I'm searching for a way to export renderings to a vector file. Because of the complexity of how the geometries are rendered, this does not seem to be as easy as thought.
I thought I could use Xfvb to fake parts of the rendering. But how can I later vectorize (or pseudo-vectorize) the screen buffer?
I do have a chance to change the screen to output only one kind at a time.
Or is there a way to substitute for example XFillArc() with something that, given a screen width and scale, provides for example a linestring?
I'm working on making a new visualization of the type of binary stars I study, and I'm starting from an existing code that renders a nice view of them given some sensible physical parameters.
I would like a bit more freedom on the animation side of things, however, and my first thought was to output the models made by the program in a format that could be read in by something else (Blender?) I've read up on the (Wavefront?) .OBJ format, and while it seems straightforward, I can't seem to get it right; importing fails silently, and I suspect it's because I'm not understanding how the objects are actually stored.
The program I'm starting from is a C++ project called BinSim, and it already has a flag to output vertices to a log file for all the objects created. It seems pretty simple, just a list of indices, x, y, z, and R, G, B (sometimes A) values. An example output format I've been working with can be found here; Each object is divided up into a latitude/longitude grid of points, and this is a small snippet (full file is upwards of 180 MB for all the objects created).
I've been able to see that the objects are defined as triangle strips, but I'm confused enough by all of this that I can't see the clear path towards making this list of vertices into an .OBJ (or whatever) format. Sorry if this really belongs in another area (GameDev?), and thanks!
OpenGL is not a scene management system. It's a drawing API and starting off OpenGL data structures for model storage is tedious. As already said, OpenGL draws things. There are several drawing primitives, the triangle strip being one of them. You start with two vertices (forming a line) and each next incoming vertex extends the line of the last two specified vertices to a triangle. The Wavefront OBJ format doesn't know triangle strips, you'd have to break them down into individual triangles, emulating the way OpenGL does it.
Also don't forget that Blender is easily extensible using Python scripting and you can just write a import script for whatever data you already have without going through the hassle of using some ill suited format.
I am working on a 2d game. Imagine a XY plane and you are a character. As your character walks, the rest of the scene comes into view.
Imagine that the XY plane is quite large and there are other characters outside of your current view.
Here is my question, with opengl, if those objects aren't rendered outside of the current view, do they eat up processing time?
Also, what are some approaches to avoid having parts of the scene rendered that aren't in view. If I have a cube that is 1000 units away from my current position, I don't want that object rendered. How could I have opengl not render that.
I guess the easiest approaches is to calculate the position and then not draw that cube/object if it is too far away.
OpenGL faq on "Clipping, Culling and Visibility Testing" says this:
OpenGL provides no direct support for determining whether a given primitive will be visible in a scene for a given viewpoint. At worst, an application will need to perform these tests manually. The previous question contains information on how to do this.
Go ahead and read the rest of that link, it's all relevant.
If you've set up your scene graph correctly objects outside your field of view should be culled early on in the display pipeline. It will require a box check in your code to verify that the object is invisible, so there will be some processing overhead (but not much).
If you organise your objects into a sensible hierarchy then you could cull large sections of the scene with only one box check.
Typically your application must perform these optimisations - OpenGL is literally just the rendering part, and doesn't perform object management or anything like that. If you pass in data for something invisible it still has to transform the relevant coordinates into view space before it can determine that it's entirely off-screen or beyond one of your clip planes.
There are several ways of culling invisible objects from the pipeline. Checking if an object is behind the camera is probably the easiest and cheapest check to perform since you can reject half your data set on average with a simple calculation per object. It's not much harder to perform the same sort of test against the actual view frustrum to reject everything that isn't at all visible.
Obviously in a complex game you won't want to have to do this for every tiny object, so it's typical to group them, either hierarchically (eg. you wouldn't render a gun if you've already determined that you're not rendering the character that holds it), spatially (eg. dividing the world up into a grid/quadtree/octree and rejecting any object that you know is within a zone that you have already determined is currently invisible), or more commonly a combination of both.
"the only winning move is not to play"
Every glVertex etc is going to be a performance hit regardless of whether it ultimately gets rendered on your screen. The only way to get around that is to not draw (i.e. cull) objects which wont ever be rendered anyways.
most common method is to have a viewing frustum tied to your camera. Couple that with an octtree or quadtree depending on whether your game is 3d/2d so you dont need to check every single game object against the frustum.
The underlying driver may do some culling behind the scenes, but you can't depend on that since it's not part of the OpenGL standard. Maybe your computer's driver does it, but maybe someone else's (who might run your game) doesn't. It's best for you do to your own culling.