Models, formats, animating, and other sh*t

What do you want to see in Armagetron soon? Any new feature ideas? Let's ponder these ground breaking ideas...
Post Reply
User avatar
Lucifer
Project Developer
Posts: 8640
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Models, formats, animating, and other sh*t

Post by Lucifer »

Ok, this subject is getting some discussion again, I suspect there's a few of us anxious to get on it in some form or other. Philippe and I beat out an idea I'd been developing the other day and worked out how it fits into his world model, so this is a fairly mature idea that has 0 lines of code written.

Problems:

(Some of these are written as features, but I'm sure we all know the problem behind them, I'm just being a tad lazy)

* Animators can't program. (Later on, when we talk about scripting models, I'll dig up links that argue otherwise, but for now, this is a known problem)
* Rendering engine factoring yadayada
* Selectable/multiple moviepack support
* Can't exchange models (player customization of models, cycle trails, etc)
* Creating new game objects is damn near impossible, modeling them is a big part of the problem

So, to make it so that animators who can't program can animate models, I was wanting to tap into the ipkey thing that at least 3dsMax and Blender have in some form or other. A little discussion on how this works, or at least how it looks like it works. :) This leads directly into how we can support it (for those who think it's too complex).

So, you place your mesh in a position and mark it. Then you advance to the frame you want to advance to, reposition the model, and mark that. Those are the key frames. A standard transformation will be applied to the mesh to move it from the first frame to the second, and to do so smoothly. In Blender (and I assume others), you then go to the ipkey editor, where you see the graph of the transformation. It starts as a line with slope 1, where the first frame is the bottom left of the line and the last frame is the top right. You can edit this graph directly, and you're manipulating the underlying function that drives the transformation. So if you, say, want to oscillate a spinning wheel, you'd give it two ipkeys. One for the spin, in which case each key frame is just rotationally different. Then one for the wobble, in which case you'd make one key frame that has the wheel rotated slightly in the <insert right word> direction. (axis of rotation?) This second key you'd then go to the graph and apply a sin curve to it, which will make it oscillate. Adjust the amplitude or period to have the predictable effects on the wobble.

So I dreamed up this class, rGameObject, which doesn't exist. This class would contain everything needed to render a single game object. The game object class, gCycle for example, would tell the renderer what type of object it is, and the renderer should then search for the right class to render it. At first, and probably for the most part, all game objects would use rGameObject to render, because it'll be a pretty thick class. The renderer creates this object and tells the game object to associate itself with it.

The game object will do these things:

* Associate a state variable with an ipkey, such as velocity. It will do this as many times as needed to do this. (An alternate implementation would have rGameObject reading these associations from a file and doing it in the other direction, and the game object doesn't know about rGameObject, but this is a problematic setup. We should beat this around a bit)

* Initialize colors. These may come over the network, from user.cfg, whatever. It'll be player colors.

* Initialize player name, and optionally, team name.

* Initialize anything else rGameObject needs to know to render it that the game object owns.

rGameObject will contain, for the purposes of animating, a transformation function or three. Obviously subclasses could override these functions as needed. I'd expect that only one generic one is needed, but without cracking open Blender code and seeing what they do, I don't actually know how many transformations will be needed.

So what's in rGameObject, besides this stuff?

rGameObject will have some other things. :) It'll contain what it needs to know to render a model. In our current setup, for a cycle it would need rModels for the wheels and body from the default model, rCycleTextures for the textures, and parameters for the transformations to be done on the wheels to animate them. But what if the moviepack is selected?

I think another class is needed to manage model media to isolate rGameObject from the resource manager and file access, but I'll probably be wrong about this. In any case, this other class would provide all art assets--anything that needs to be rendered. It would also provide loaders for models, textures, and whatever other art assets are needed (not music! that's separate). So rGameObject would say "Give me the model for the cycle at this address" and this other class would get it based on the preferences of the player/server admin/remote player/script/map/whatever. So it could come from a moviepack (or grid skin or whatever you want to call it at this point), it could come over the network, or whatever. It would turn over to rGameObject the rModels, rTextures, and ipkey information.

So, to get there from here, I was looking at gCycle. Specifically the model loading ad rendering. We could create rGameObject and make it capable of rendering a cycle. Then we get it tied into the resource system and adapt it pretty quickly to walls, trails, and zones. We go ahead and create it as a member of gCycle, the same way rModel and rCycleTextures are currently handled. And we'd call rGameObject::Render() from gCycle::Render(), and rGameObject::Timestep() from gCycle::Timestep(). After it's been adapted for all the game objects, we can look at how we're going to construct the scene graph and where the rGameObjects fit in. This should effectively remove all rendering code from the eGameObjects, leaving behind a skeleton to be removed when the rendering engine is brought in line with philippe's World model (which calls for a scenegraph, which we arguably have now, iirc).

I'm not too intimately familiar with the details of the renderer past whats in gCycle and gHud, so naturally feel free to throw in what you've got that's so blatantly obvious but I missed it.

So, the main thing this class would give us is lack of commitment. :) In all the numerous discussions we've had along the way, we've come up with plenty of different ways the system should look. rGameObject lets us take a step in the right direction without committing ourselves to any course of action. We can't really get around the ipkey thing, at least the transformation function with some way to specify the particulars of each transformation, whether we support ipkeys in model formats directly or not. Obviously I'd like to support them directly, but we don't even have to commit to that to write rGameObject.

The reason I mention it like this instead of just writing the damn thing is because besides having my hands full otherwise, the transformation function in particular calls for math that's still quite a ways beyond me. Maybe after this semester it won't be, but right now it is. So if it's going to get done before Christmas, someone with more math than I have will have to do at least that much. I can prototype it for you, I can do a lot of the housekeeping stuff that goes in it. I can even copy and paste large blocks of code from existing rendering into it. But I'm not far enough to finish the job.
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Z-Man
God & Project Admin
Posts: 11585
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

Good plan, only two things:
The class name. I think it should not contain Game, because a rendering does not have anyting to do with a game. Well, eGameObject should rather be eGridMover or something, I admit :) How about rVisual? It's kind of traditional.
That it should be a fat class. It should rather be a very thin abstract class, just containing the Render() method. Ok, it should HAVE a thin abstract class called rIVisual with just that single method, there certainly should be a fat implementation around. Later, we'll want the rendering to work completely without the game objects; right now, the renderer calls Render() of all the game objects who would delegate the work to the visuals, but it would be better in the long run to bypass it. Think render state changes: If every cycle has two visuals that both use different textures (say, the body and our fake shadow) and rendering is done over the cycle, it has no choice but to call Render both of the visuals in one go. If instead the game object inserts the visuals into some list held by the renderer, the renderer could then sort the visuals by material (==render state) and avoid all those costy switches.

Edit: The math stuff for animation defaults to be my job if nobody else feels like it.
User avatar
Lucifer
Project Developer
Posts: 8640
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Post by Lucifer »

Right, I was thinking there would be some master renderer that we'd just pass it the hierarchy that is the game and it would sort through it to do what it needed to do the best way it can. The thing about calling eGameObject::Render() is just on the path to that. :) Of course, maybe that's not the best approach for us specifically, I don't really know, all's I know is that the APIs I've been looking at for general purpose rendering libraries all work on some sort of scene graph concept. You guys that have been doing this longer than I have will know better than I will what to do. :)

No objections to a base class and a thick class that inherits it. My only serious point about that was that we should discourage making new subclasses as much as possible. Here's what I'm thinking on that.

If we have a whole slew of classes, one for walls, one for zones, one for cycles, one for tanks, one for recognizers, one for helicopters, etc, then we'll likely have a fair amount of code duplication that isn't needed of stuff that doesn't belong in teh base class. I see that having one thick class won't necessarily provide the flexibility we need for objects that really do differ from the norm. So we actually do need to subclass for objects that are genuinely different enough to need their own special optimizations, or even visuals that don't exist for other objects. So, if we have one thick class, and its performance can be improved in some way, then automatically performance is improved across the board. The flip side is that improving it for one object might decrease performance for others, and that's where we should consider a subclass for that one object.

I've been thinking about transformation functions some more, and we really need more than that. :) I was thinking about things like having walls with a set thickness and allowing a custom model to be used. In that case, the wall has a set playing surface that cycles and the game engine expect to be flat. So we need to be able to flatten that part of the model and leave the rest alone. Obviously we need to be able to scale the models in all 3 dimensions independently, and in all at once. I realize we can dump that on OpenGL, but we'll still need to be able to do some transformations. Like wrapping a model around a corner of arbitrary angle. These are all basic operations that probably belong in the base class. :)

I only picked the name rGameObject following the convention of eGameObject. :) Of course it should have the best name possible. ;)
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
joda.bot
Match Winner
Posts: 421
Joined: Sun Jun 20, 2004 11:00 am
Location: Germany
Contact:

Post by joda.bot »

@lucifer: I guess those additional transformation functions should be put into a separate class (either tMatrix or tTransform) ...

I think it mighe be better to let the render object query the game objects, thus there is not dependency from gCycle/eCycle to rVisual. rVisual will be assigned an object which it queries before it is rendered.

I guess OpenGl state sorting will be easier if rVisual just provides access to data sets and the rRender uses a List of all rVisuals to determine visibility,
and then render rVisual's data in state sorted way. I don't know how to achive this if rendering routines are part of the rVisual class.

rVisual would thus only provide data sets which are read by rRenderer and then displayed.

(Does ArmagetronAd use any king of Culling right now ?)

If I'm talking rubbish correct me please , might be I'll learn something good for my current Java/JOGL based render implementation (for university).
User avatar
Z-Man
God & Project Admin
Posts: 11585
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

Lucifer: yes, having a fat class for convenience is nice. But it's even nicer to have a set of small convenience classes that you don't derive from, but you can make members of your implementation. Think rModel and the way it is used by gCycle.

Joda: You got it about right, but there is little problem letting each visual class manage its own rendering: You restrict the sort of rendering the visuals can do to simple polygon pushing. They can't change textures or other rendering state. The whole rendering process then gets channeled through the material: every material knows which visuals use it, and the renderer calls rMaterial::RenderAllVisuals() on it. The material then sets the rendering state and calls the rendering functions of its visuals.

Now, if we don't let the visuals push the polygons to OpenGL directly, but to some proxy object, we've got the perfect place where general transformation functions can be plugged in. Sort of software emulated vertex shaders. Or real vertex shaders where they are supported.

No culling today :)

Polling the data by the visuals from the game objects is a good idea, provided one problem is solved: If you do lazy polling (a visual only polls the game object if it is about to be rendered), someone else has to tell the visual it is about to get unculled by the renderer based on the game object's position. Well, the polling could just happen by events, right? Every time the game object changes, it sends around an event, and the visuals listen to it.
User avatar
joda.bot
Match Winner
Posts: 421
Joined: Sun Jun 20, 2004 11:00 am
Location: Germany
Contact:

Post by joda.bot »

uhm, the Renderer/Materials could only fetch data from rVisuals which are inside the frustum ?

How about an abstract "Interface" for the current Grid / Scene Datastructures ? This effort might seem wasted at first, but some day someone might come up with a different implementation there and other parts will be easier to understand with defined separations beteween main components? *just dreaming away*
User avatar
Z-Man
God & Project Admin
Posts: 11585
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

joda.bot wrote:uhm, the Renderer/Materials could only fetch data from rVisuals which are inside the frustum ?
Heh, but if the visual's position is also polled from the game object only on demand, it will start to lag behind as soon as the object gets culled away and the renderer won't consider the visual again until it is too late (maybe). But the event stuff is a good, efficient solution, I think.

Yes, and abstract interface is a good idea here. Everything that the visuals should know of the renderer is that it has some lists and structures to render visuals, and they can go and make themselves be added to these lists. How these lists look is of no interest to a visual.
User avatar
Lucifer
Project Developer
Posts: 8640
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Post by Lucifer »

Ok, thinking about the model format again, after having some some more extensive research lately.

There isn't a recent, standard, text-based model format that's supported by the two programs I care about, Blender and 3ds. There's VRML, which isn't recent, and lacks the animation stuff.

So here's what I've got in mind now. Two possibilities.

1. Separate models for each component. The artist could use a single master file for his program (.blend for blender, .3ds for 3dsmax), but he needs to export separate VRML files for each component that he wants animated separately.

2. One file, but the author has to name each component that's animated independently.

In both cases, we use a callback system similar to what wrtlprnft put together for the hud. In fact, we'd probably use the exact same callback system and just add more callbacks that the renderer needs. Then we associate each sub-part of the model that's animated separately with game data identified by the callback name (just like it's done in the cockpit), and rVisual knows what to do. These tags would look something like this:

Code: Select all

<Animate id="front_wheel" type="rotate" axes="x,y" state_var="cycle_speed" />
Contrived stuff to just show the idea. In that particular example, the front wheel would be rotated on both the x and y axis using cycle_speed. Here's an alternate format for the first case:

Code: Select all

<Model>
<File id="front_wheel">
<Location x="0.4" y="2.0" z="0.2" />
<Animate type="rotate" axes="z" state_var="cycle_speed" />
</File>
<file>
...
</File>
</Model>
Same thing, but for different files used for each piece. Animation types could be callbacks, in which case we could provide some extensibility for object transformations and stuff. That would be neat.

This xml stuff would be in the xml resource file that we create. So you'd make the model in Blender, export it to VRML, then write your own .aamodel.xml file to tie it all together complete with animation information.

VRML picked because it's supported by both programs (afaik), and it's xml-based, so we can use tXmlParser to parse it. :)
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
joda.bot
Match Winner
Posts: 421
Joined: Sun Jun 20, 2004 11:00 am
Location: Germany
Contact:

Post by joda.bot »

before we start to use VRML we should really consider X3D which is the official next thing after VRML.

Advantages of X3D over VRML:
- Supports Animation and even Hierachical Animation
- Supports Profiles (e.g. just basic Polygons or more advanced features)
- Binary encoding standard for X3D

Problems might be the missing support for X3D.

Blender und 3D-S 5,6 und 7 Export Plugin:
http://www.web3d.org/applications/tools ... anslators/

BS Exporter for Blender seems to be exspecially feature rich. The exporter might rely on commerial extentions to X3D for the BS client? (The exporter is free AFAIK, atleast for non commerical use).

Wikipedia also has quite atleast 2 links to libraries in C++ for X3D.

http://en.wikipedia.org/wiki/X3D

We might also use a simpler format.

Demands on our 3D models:
- basic animation information (frame based)
- simple triangle geometry, with normals, (multiple) texture coordinates
- materials (multiple textures, bump maps?)
For single file support:
- named groups of triangles, with pivots points
- (hierarchical groups)

That's all I can think of right now...

A multi file solution might be:
- XML file to combine multiple (3D model files + Animation Data)
- Wavefront OBJ files for each animation component (Front Wheel, Back Wheel, Body)
- Texture files and perhaps MTL files

Wavefront OBJ is a basic text format with line based instructions.
- only 1 pivot
- one texture coordinate
- smoothing groups for normals
- vertices, normals, n-gons (but we should restrict at most triangles &quads)

for OBJ Spec see here:
http://netghost.narod.ru/gff/vendspec/w ... j_spec.txt

(very slow loading)
User avatar
Lucifer
Project Developer
Posts: 8640
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Post by Lucifer »

Um, last time we talked about X3D, we didn't find any libraries that were open source and recently maintained. Is that still the case? I suppose if it's xml-based it's not that big a deal, we can use a tXmlParser-based parser of our own.

I'm particularly concerned about making sure everyone can export to it, and will be able to do so consistently in the future. VRML export is supported by the Blender team directly, afaik, and will always be supported, at least reliably for our purposes. Can we expect that same attention with X3D?
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
joda.bot
Match Winner
Posts: 421
Joined: Sun Jun 20, 2004 11:00 am
Location: Germany
Contact:

Post by joda.bot »

X3D is from the same organisation as VRML, and is the direct successor of VRML (also supposed to fix it's short comings). I guess the only reason not to use X3D is, if our development effort is too high or the standard is not yet widely supported. But then I'd also adwise against vrml, because it should be replaced by X3D soon (AFAIK).
User avatar
Lucifer
Project Developer
Posts: 8640
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas
Contact:

Post by Lucifer »

Well, I don't care either way. Here's what I really deep down inside care about:

At implementation time, whatever loader is committed to cvs should have an exporter for both Blender and 3dsMax. That lets us test it.

At the time we decide to standardize on it and get rid of all other test loaders (since we agreed to have only one loader other than supporting old moviepacks with the two old loaders we have), the format must be well supported by Blender and 3dsMax.

THe time from implementation to standardization needs to not contain even a development release, if possible. So if you implement x3d after 0.3.3, we can't release 0.3.4 without determining x3d is good enough for us. (That's not entirely true, we can still release 0.3.4 and say "don't make any models in this format yet, we don't know if we'll keep it", and realistically we might hve to do that to get other people to test the format and its exporters for us)

That means two things. :) First, I don't care about using the next stable release to mark which format we use. And second, I do care that we use stuff that already exists in a form thats usable by users, basically right now. I realize that we won't actually find out how well-supported x3d is until it's stuck in the code and used, unless you can show us some applications that use it in a way that we can build some of our own models and see for ourselves.
Image

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
jessethemidget
On Lightcycle Grid
Posts: 36
Joined: Sun Apr 01, 2007 10:49 pm

Post by jessethemidget »

how about using your own format?
both blender and 3dsmax have fairly powerful scripting language support, anyone with even a tiny knowledge of python could create import/export scripts for blender for any text-based format.

I'd be willing to make and maintain python scripts for blender for import/export that could be packaged with armagetron, and I'll look into 3dsmax... In my opinion, both vrml and x3d have many elements you would most likely not use. If you created you own it'd be simpler.

about transformations:
you'd need two main transformations: location (x,y,z transform... easy) and a matrix transform (3X3matrix for size/rotation) with maybe a function to convert xyz rotations to matrix rotations (for us math-challenged individuals)
these two would allow rotation,scale,location transforms in any dir/shape/size/etc../whatever.

I'd say use .obj and .mtl files because .mod is almost exactly the same as .obj, it'd be really simple to change over.
then use an xml to tie together with a script for animation (also xml)

I'd say animation could be something like this:

Code: Select all

<Model>
<File id="piston">
<Animate type="move" state_var="cycle_speed>
<state time="0.0">0.4,2.0,0.2</state>
<state time="1.2">0.4,2.0,0.5</state>
<state time="3.0">0.4,2.0,0.2</state>
</Animate>
</File>

<File id="wheel_front">
<Animate type="matrix" state_var="cycle_speed">
<state time="0.0">some matrix</state>
<state time="1.0">some matrix</state>
<state time="2.0">some matrix</state>
</Animate>
<Animate type="constant">
<state>0.0,0.0,0.73</state>
</File>

<File id="rwheel">
<Animate type="rotation" state_var="cycle_speed">
<state time="0.0">0,360,0</state>
</Animate>
<Animate type="constant">
<state>1.2,0.0,0.43</state>
</File>

<File id="body">
<Animate type="constant">
<state>0.0,0.2,0.3</state>
<state>[[0.0,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,0.0]]</state>
</animate>
</File>

the first file would be a piston, using three time stamps its z location goes up and down
the second would be a rotating wheel, using matrices for a more complex rotation + wobble & scale etc... with a constant location (second set of tags)

the third would be a standard rotating wheel that's rotated 360 on the y axes per game unit traveled(this could be changed)

the fourth would be the body, constant, no change. the state would still be in animate tags? I don't know what do you guys think?


anyway, sorry for bumping an old topic, but now you have the perspective of an animator who also can program a little...

edit: new idea
what if the translations were just modifiers. The model, initial location, animation data, and time/speed etc.. would be passed to a modifier function,that than changed location/rotation/scale and passed them on to the renderer as static elements. then it could keep the renderer from being bloated and keep animation separate with it as a bridge... just a thought.
Post Reply