Back to Main Page

A page about the idea and development of a VectorEntity class, which is based on an exported OBJ model from 3DS Max.


The Birth of the Vector Entity - Bucket List Idea Realised

One of the things about having a mind that is constantly ticking over, despite it getting ignored 99% of the time, is that it creates ideas and keeps hold of them. Like the projects I have with the annoying quirks, there are those projects with intriguing ideas behind them... this is one of those ideas.

I have frequently utilised the DRAW_LINE native in my mods, for either diagnostic or functional purposes. As such, I have always envisioned that there is more can be done with them, especially as they are depth sorted in the world. So every now and again I put together partial mods that do basic things as an experiment and the last couple of days has seen that evolve into a functional component, the VectorEntity.

The DrawableObj

At the very heart of the entity, is the DrawableObj component and this is the part I never managed to get round to creating, until yesterday (3rd Nov 2020). The idea behind it is you create a simple model in 3DS Max and you export it as an obj format file. Obj is a fairly basic (if you export basic data), text based object file, split into various sections depending on the model you export. I only wanted basic information, so there were only three types of entry that were relevant.

1) The Vertex definition.

This is simply defined as a line prefixed with 'v' and containing three float values

v 1.3129 1.0262 -0.0856

2) The Face definition.

This is a line prefixed with 'f' and contains three or four Vertex indices. If you export as Quads, you can still get lines with just three values, because not every polygon is a quad. The benefit of exporting as Quads, is that you don't get the diagonal lines across each Quad face.

f 21 25 26 22
f 2 6 7 3

3) The model name

g Box001

So the first task is to parse all the Vertex entries into a List<Vector3>, with a Vector3.Zero added by default as Vertex indices start at one, not zero. I could have modified the data to shift all values down by one but I wanted to keep the data as intact as possible. Adding that initial entry meant I didn't have to perform any subtraction on the index values, which means less processing time. During this process, it also stores the minimum X, Y & Z and maximum X, Y & Z and uses those values to calculate the dimensions of the model... Width = Max X - Min X etc...

Once I have parsed the Vertex values, it's on to the Vertex indices. This tells the Obj which Vertex value it should be using from the Vertex Array.

The problem with exporting as an Obj, is that it defines quads and tris as a collection of points that are meant to be joined. This means that two adjacent quads share the same line. That's fine for drawing polygons but wasteful when you are just drawing lines. So as part of the parsing process, it takes each pair of Vertex indices and creates a new Point struct with the indices stored in a low, high format. These Points are stored in a List<Point> and as each Point is created, the list is checked to see if it already contains that Point and if not, it gets added.

As well as this process, any line with four values is stored as a Quad in a List<Quad> and any line with three values is stored as a Tri in a List<Tri> collection. This was an initial idea based on exporting models as either Quad based or Tri based and then drawing them as Lines or Polygons respectively. As it turned out, using DRAW_POLYGON was a mess because they are not depth sorted properly, so that side of things is going to get abandoned.

So by the time the obj is imported, I have a collection of Quads, a collection of Tris and a collection of Unique Vertex Index pairs stored as Ponts, to draw the lines from. This massively reduces the number of lines that have to be drawn, allowing for more complex models.

So that's the DrawableObj component created from the exported obj file.

The VectorEntity

The main class is called the VectorEntity and this is what controls the Position, Rotation and Scale properties, along with the Light properties. Any VectorEntity can be specified as Light Casting, meaning it will also draw a ranged-light that is based on the width and colour of the DrawableObj. This is an optional part of the class but it looks kinda cool at night because lines are self-illuminated.

There will also (if I don't lose interest) be the ability to store multiple DrawableObj objects in a VectorEntity and to be able to Blend from one to another. This would allow for interpolated animations to take place, which could look pretty cool.

This class also calls the Draw() function on the DrawableObj with the updated Position, Rotation etc... values.

Drawing the Obj

It took me a while to get my head around this section but a quick recap through some old code got me sorted again. The reason for that is there are several Matrix transformations taking place and I can never quite remember how Matrices work. This is where being able to write WinForms apps helps, because you create apps to step through and watch the output to check what is happening. So once I had checked the process in a test app, I moved that into the DrawableObj class and they can now be drawn rotated and scaled at any position.

So what I have got so far is this:


This shows various objects being created in different colours and different sizes and rotation values. There's no music or anything, so it's a boring video... it's a tech-demo video, not a "Let's grab some popcorn and watch this movie" type video. I know people hate these but they're just reference pieces for my benefit.

So it can move, it can rotate, it can scale and it can cast light... which is probably about as much as I could hope for after just a couple of days intermittent coding. Especially seeing as how my persistent drinking affects my ability to write any code of any kind. It makes my fingers feel as if they belong to someone else, which is kinda odd.

Update 19th November: This project probably seems dead and it almost was a couple of nights back. I tried to run it and it didn't work, so I opened the project and couldn't remember what I was looking at. After spending an hour making changes that I thought would make it work, I had more errors than I started with and it wouldn't even load an ONJ file. At that point I zipped it and went back a version... that didn't work either, so I gave up. Came back last night, went to almost the first version I had working and it still worked. Got myself familiar with the code again, unzipped the newest version and got that back working again too but it took writing a winforms app to diagnose the problems in the obj parsing to get it sorted.

Not only did I get it sorted but it can now handle multiple objects in a single file, whether they be Quad, Tri based or even lines will now work. So that means I can mix and match 2D lines with 3D shapes and they all work. Plus I can name the 3DS Max material to System colours and it will parse them into drawing colours when I display the obj. The problem is, I just can't think of any way to use it yet. I did think about using it in my Time Trials mod but changed my mind.

The idea behind this system though was just to satisfy a "Can I do it?" question and I did it. I do have one ace-card up my sleeve for it though. If I get that working, that might be a real "How did you do that?" moment. Early signs are promising.

Update 3rd December: Came to a conclusion last night... these work great at night and look absolutely crap during the day. I had thought of using them instead of the generic markers in Players Extended but they just don't work in daylight.