Showing posts with label code. Show all posts
Showing posts with label code. Show all posts

2011-04-22

Least squares fit a sphere to 3D data

I didn't find this online anywhere, and I had some data I needed a least squares fit with a sphere for.

All you have to do is define:

Error = Sum( |Position[n] - Center|^2 - Radius^2 )

Then define the squared error:

Squared Error = Sum( ( |Position[n] - Center|^2 - Radius^2 )^2 )

And solve the summation using a iterative method (like newtons, below) after pulling out the summation terms.
For example, if you do: Sum( (P.x[n] - Cx)^2 ) You get (after Expand):
Sum( P.x[n]^2 - 2*P.x[n]*Cx + Cx^2 )
And you can then split up the sum:
Sum( P.x[n]^2 ) + Sum( P.x[n] ) * -2*Cx + Cx * Nelements
Note you HAVE to ultimately divide the sums by Nelements

Note that "Center" is A,B,C (3D) and I use Rsq as Radius^2.

This method is not fast, but it converges, and the way the code is written it is independent of dataset size, but you do have to compute a number of sums and products before running the algorithm.

Note this method is used to generate the equations used to compute linear and quadratic fits instantly, given you compute some sums first. I suppose it can be extended to any shape with enough working the mathematics. The next shapes are planes, capsules, maybe torii.


//
//Least Squares Fit a sphere A,B,C with radius squared Rsq to 3D data
//
//    P is a structure that has been computed with the data earlier.
//    P.npoints is the number of elements; the length of X,Y,Z are identical.
//    P's members are logically named.
//
//    X[n] is the x component of point n
//    Y[n] is the y component of point n
//    Z[n] is the z component of point n
//
//    A is the x coordiante of the sphere
//    B is the y coordiante of the sphere
//    C is the z coordiante of the sphere
//    Rsq is the radius squared of the sphere.
//
//This method should converge; maybe 5-100 iterations or more.
//
double Xn = P.Xsum/P.npoints;        //sum( X[n] )
double Xn2 = P.Xsumsq/P.npoints;    //sum( X[n]^2 )
double Xn3 = P.Xsumcube/P.npoints;    //sum( X[n]^3 )
double Yn = P.Ysum/P.npoints;        //sum( Y[n] )
double Yn2 = P.Ysumsq/P.npoints;    //sum( Y[n]^2 )
double Yn3 = P.Ysumcube/P.npoints;    //sum( Y[n]^3 )
double Zn = P.Zsum/P.npoints;        //sum( Z[n] )
double Zn2 = P.Zsumsq/P.npoints;    //sum( Z[n]^2 )
double Zn3 = P.Zsumcube/P.npoints;    //sum( Z[n]^3 )

double XY = P.XYsum/P.npoints;        //sum( X[n] * Y[n] )
double XZ = P.XZsum/P.npoints;        //sum( X[n] * Z[n] )
double YZ = P.YZsum/P.npoints;        //sum( Y[n] * Z[n] )
double X2Y = P.X2Ysum/P.npoints;    //sum( X[n]^2 * Y[n] )
double X2Z = P.X2Zsum/P.npoints;    //sum( X[n]^2 * Z[n] )
double Y2X = P.Y2Xsum/P.npoints;    //sum( Y[n]^2 * X[n] )
double Y2Z = P.Y2Zsum/P.npoints;    //sum( Y[n]^2 * Z[n] )
double Z2X = P.Z2Xsum/P.npoints;    //sum( Z[n]^2 * X[n] )
double Z2Y = P.Z2Ysum/P.npoints;    //sum( Z[n]^2 * Y[n] )

//Reduction of multiplications
double F0 = Xn2 + Yn2 + Zn2;
double F1 = 0.5*F0;
double F2 = -8.0*(Xn3 + Y2X + Z2X);
double F3 = -8.0*(X2Y + Yn3 + Z2Y);
double F4 = -8.0*(X2Z + Y2Z + Zn3);

//Set initial conditions:
A = Xn;
B = Yn;
C = Zn;

//First iteration computation:
double A2 = A*A;
double B2 = B*B;
double C2 = C*C;
double QS = A2 + B2 + C2;
double QB = - 2*(A*Xn + B*Yn + C*Zn);

//Set initial conditions:
Rsq = F0 + QB + QS;

//First iteration computation:
double Q0 = 0.5*(QS - Rsq);
double Q1 = F1 + Q0;
double Q2 = 8*( QS - Rsq + QB + F0 );
double aA,aB,aC,nA,nB,nC,dA,dB,dC;

//Iterate N times, ignore stop condition.
int n = 0;
while( n != N ){
    n++;

    //Compute denominator:
    aA = Q2 + 16*(A2 - 2*A*Xn + Xn2);
    aB = Q2 + 16*(B2 - 2*B*Yn + Yn2);
    aC = Q2 + 16*(C2 - 2*C*Zn + Zn2);
    aA = (aA == 0) ? 1.0 : aA;
    aB = (aB == 0) ? 1.0 : aB;
    aC = (aC == 0) ? 1.0 : aC;

    //Compute next iteration
    nA = A - ((F2 + 16*( B*XY + C*XZ + Xn*(-A2 - Q0) + A*(Xn2 + Q1 - C*Zn - B*Yn) ) )/aA);
    nB = B - ((F3 + 16*( A*XY + C*YZ + Yn*(-B2 - Q0) + B*(Yn2 + Q1 - A*Xn - C*Zn) ) )/aB);
    nC = C - ((F4 + 16*( A*XZ + B*YZ + Zn*(-C2 - Q0) + C*(Zn2 + Q1 - A*Xn - B*Yn) ) )/aC);

    //Check for stop condition
    dA = (nA - A);
    dB = (nB - B);
    dC = (nC - C);
    if( (dA*dA + dB*dB + dC*dC) <= Nstop ){ break; }

    //Compute next iteration's values
    A = nA;
    B = nB;
    C = nC;
    A2 = A*A;
    B2 = B*B;
    C2 = C*C;
    QS = A2 + B2 + C2;
    QB = - 2*(A*Xn + B*Yn + C*Zn);
    Rsq = F0 + QB + QS;
    Q0 = 0.5*(QS - Rsq);
    Q1 = F1 + Q0;
    Q2 = 8*( QS - Rsq + QB + F0 );
}

2011-04-06

WebGL - Convert chars to float

 All info is derived from:
http://www.khronos.org/registry/typedarray/specs/latest/


The basic problem, is you create a vertex buffer object (VBO) and write vertex data into it, such as vertex position, texture coordinates, normals, and weight and weight index values.
In case you have never used a "matrix palette" the basic idea is:
  • Construct a VBO with space for your weights and weight indices (4-8 floats)
  • Convert your weight values into floats, store in your array,
  • For the index values, convert to uint8 values, which refers to the shader' current matrix palette
    • This is defined as an array of uniform matrices; usually less than 28 matrices long
    • all GPU bone animation routines do this internally, ultimately.
  • Then, before you draw a group in your polygon, load the palette with the matrices needed.
  • In the shader, simply multiply with your input vertex to compute the output vertex, and multiply each stage with the weight required.
It doesn't take a of lot of inspection to see multiple problems. For one, you are limited by the number of weights applied to a vertex, and you need multiple shaders for each count, such as matrixshd1, matrixshd2, and so on. You also have to load the uniforms in for each group that changes the matrix palette. Also, depending on your shading pipeline, you have to multiply and convert the matrices before sending to the GPU.

All those problems aside, and you suddenly realize that in javascript, there IS no way to convert bytes into a float. In C, this was typecast trickery.

Here is (one way) convert arbitrary bytes into a float for your VBO data:

function utilUCharToFloat( inarray ){

//Step 1: Create a un-editable array buffer (in bytes) of size 4

var n = new ArrayBuffer(4);

//Step 2: Create a "view" of that buffer as a Uint8 view.
//This allows you to write into it as bytes.
//We choose a 0 offset, and a 4 length for explicitness

var vb = new Uint8Array( n, 0, 4 )

//Write into it with your bytes

vb[0] = inarray[0];
vb[1] = inarray[1];
vb[2] = inarray[2];
vb[3] = inarray[3];

//Create a new view as a float.
//This view uses the same data as the vb view, but is read/written to like a float.

vf = new Float32Array( n, 0, 1 );

//The first element, a 32 bit float (8*4 = 32) is returned,

return vf[0];
}

You can do the exact opposite and convert bytes to float using the same logic.

Hope this helps, it's critical to being able to use matrix palette weighting.

-Z

2010-10-20

Zoning

It has been a long time since I posted.

I've become far more proficient at modeling in blender.

Also, I've improved the DXML format to the point where it writes C/C++ code automatically, and is far more stable, fast and simple. In fact, DXML seems to be my new "does everything" format, because unlike XML or other bullshit standards, it's lexically simple and forces you to write better file formats. Which, it turns out, are directly C-struct translatable. Also, it has less possibility of confusion or errors due to it's very strict nature; and as a result, makes you far more intelligent.
The downside is slightly larger files, but when you are dealing with a text file, you want it to be comprehensible, not efficient. DXML files are built for comprehension and logical structure. They're perfect!

Also, the TED format has been getting a lot of attention and improving, I've added scripting to animations, so now attack animations can contain code (lua) so that punch animation can mean something.

Also, I embedded Lua into my programs, now I can script (safely, mind you) so extensibility is fast simple and external; allows for a lot of flexibility, and as all you truly experience programmers know, a script is only as powerful as the core that drives it. In this case, core handles a lot of things normal engines like Unity, Blender, Torque, and many others do NOT handle. No surprise; you're supposed to extend those engines in C/C++ code anyways. Most of them are also not built for magnitude/scaling either.

So, with all these improvements, the focus has been on scene management; ted files provide a vast array of graphical and animation data; they also now provide zoning information, which is used to reduce collision requirements and provide an effective scene graph that can be non-spatial (a critical requirement for adventure clone!)

Here's a rough idea of what "zones" and "zplanes" mean, in terms of blender; In text, a zone is a axis aligned bounding box (AABB) that contains a list of objects that intersect it, and a list of other zones that intersect it. A Zplane contains a reference to two Zones, and a position and matrix, used for culling.



Until next update! Maybe we'll get a video of some in-game action.

-Z

2010-06-11

GHOST, Mingl, XCore, Core, XGFX

Continually working on improving all the above components;

Here is a quick overview of what all this garbage is:

ghost - Lets you make programs for X11, Windows, Mac
mingl - Draws stuff in hardware lingo
core - Does everything you don't want to write yourself
xcore - Does things you should be doing anyways
xgfx - Makes everything look pretty + move around

In more details:

GHOST - Made primarily by the Blender.org guys; this is their generic host operating system toolkit; In other words, this is the code that allows you to receive low level input events and a OpenGL context; And the ability to create windows and draw to them/receive messages from them. I've heavily modified it to include some more game-friendly features, timing looks, multithreading and some specialized input event abstractions, joysticks support and other goodies. It's at least as good as SDL, and in many ways, far superior. Hard to find something better than code that has been attacked by many people.

Mingl - "Minimum Graphics Library"; essentially a wrapper around OpenGL; but, it's designed to specifically mimic OpenGL 3.0 specifications, and does an insanely good job of managing more annoying aspects of OpenGL programming; It makes writing graphical routines trivial, where you may spend hours trying to orient yourself in 3D space using any other toolkit (that includes you, blender. F*** your armature space conventions!). However, it's also interface abstracted just like GHOST, so it can use OpenGL, DirectX, software... it doesn't care. But it is primarily designed to expose low level hardware techniques to force you to write more efficient graphics code; and does a ton of things internally (like managing VBO/IBO/RC, states, transformations, ect...). It is still missing FBO operations, but those are trivial if you have a GL 2.0 + system (just need to sit down and do this)

XCore -  Operating system and hacking level tools. A quite extensive library I made of tools I use frequently, such as texture conversions from DXT to / from anything, mathematical algorithms, VA/IA generation algorithms, numerical methods, statistics, even some unique IK algorithms and other tools. IT also contains agressive memory management and a slew of commonly used structures.

Core - The heart of everything; Based on the std C++ library; core contains separate components that should not rely on any one other component, like vec3 vec4, matrix3x3, matrix4x4, index_array, geo, and a lot of other commonly used, but often not needed tools. Chances are if you need any one of these tools, you need all of them.

XGFX - My rendering system built ontop of using mingl as the renderer interface. IS still under construction for the resource abstraction and management of massive resources.

No good screenshots; Just the city level again after implementing multithreaded loading + mingl improvements.

2010-06-04

TED Exporting + Mingl

"Walk the Walk"

I talk a lot of smack about things that I do. It's really nice when I visit artists that I can actually pop open their files and show them how to export them so I can load them in game.

It's much easier to convince people you aren't just blowing smoke when you can show them what you are doing in real time. Hard to dispute that kind of presentation.

So, more improvements on the TED file's; the exporter is more robust, and I'm in the process of verifying the data output is correct. So far this seems to be true, I've seen textures, models, scenes, and just about everything in the file working perfectly, especially animations. It's wonderful to just be able to load in a file directly exported from blender, and import it, then see your work immediately and accurately duplicated in a realtime game.

So here are some example shots; the next long haul is building the xgfx resource management system so I can maintain a logical coherence for all of these vastly different resources + files. Resources are essentially reference counted, but are not cleared until flagged to do so. Instance objects exist physically, so once they terminate they just dump all data. Plenty of re-use optimizations, tons of weird paradigms like "resource-source-instance" ideas with meshes; But this will be demonstrated eventually.


In order from top left clockwise;

Rayne from BloodRayne on PC with a static keyframe applied,
two of my custom levels,
Charizard from Super Smash Brothers Brawl on Wii with standard_wobble applied and hacked texture
another custom level,
The first boss from Dragon Blade on Wii, with wobble, note the material colors are showing now; easily removed.
Bowser Trophy from Super Smash Brothers Brawl on Wii
Rayquaza Boss from Super Smash Brothers Brawl on Wii with wobble.

Looks like I need a damn artist.

-Z

2010-05-31

Fencing - Problem Solved

4 days of brain bashing of a very complex error to track it down and slay it.

At first, the program would crash if run outside of debug mode.

"Okay, so it must be a memory overrun, and I'm writing past the end of the array, because the debugger puts padding for detection against clobbering memory"; which looks like this:

uchar myarray[ 10 ];
myarray[ 10 ] = 60; //WHOA, myarray holds 10 ELEMENTS, so position 10 is the 11th element.

Often called a fence, I couldn't find it. What was weirder, std::string was throwing errors. std::map was having kittens. and ntdll seemed to vomit all over the floor at this party from hell.

As I burrowed into the code, seething rage ignited; was I being burned by out of date compilers? Was my code wrong? What had I done? What had THEY done wrong?

This project had it all, nested complex templates, deep inheritance heirarchies, large blocks of data and nasty C algorithms. Luckly, most of my (good) code has __debug_regression defined, so I was able to quickly rule out very large segments of code against error with a single look back at passed test dates.

But my mind was going, Dave.

I ignored the fact that if my code worked in debugging, then only the heap allocation method would cause 0xc0000005 errors thanks to ntdll 's nice memory bounding protection (mainly protects it from 0xBAADFOOD but yeah)

So, I eventually upgraded my compiler, my debugger, brought in the help of my custom designed memory heap manager (igtl_MMHeapSystem; I love you, I LOVE YOU! OH GOD YOU'RE SO SEXY MMMMM*codepronz*) and tracked down the offending bug. Hours of poking and prodding landed me with a really surprisingly simple conclusion.

I was off by one.

I'd been accused of being off kilter, off base, and not even on this world, but one? Off by one causes these insanely weird errors? Why did the debugger not detect the stack corruption? Why did the heap manager skip telling me I was writing one integer past my array? Why did absolutely none of the tools find this till I made my own?

Here's why:

When my array was writing past the end of it's detection, it wrote (coincidentally) over the bad food word. But, in the running of the program, that error PROPOGATED until some time later, when the error detection actually scanned memory; because no one in their right mind scans every single memory allocation (super slowness). By the time a scan actually occured, it was too late and bizzaro values had multiplied. But only in a small well contained region. That is, inside of a system dll I don;t have debug points in. Ironically, since the error affected nothing else in MY code, it really screwed up ntdll, and cause it to throw weird errors all over the place.. So, my code was just missing a +1, but the stack was being blow to pieces thanks to trying to protect itself.

Moral of the story?

Make sure to take a nice drink if you run into a hard problem. Usually, it's just something stupid. I use High Gravity Steel Reserve.

-Z

Here's some preliminary results with a nifty 3 instruction toon shader I made: (<3 Mecha Dragon)

2010-05-28

CURSES!

I've been fighting some errors for a while now with my importer code;

Eventually (2 days of brain bashing) I figured this out:

0xC0000005 errors are normal; But they're a good hint into memory over-walking.


Turns out, you can;t do this anymore (used to be able to; I'll figure out the fix):

struct myvec{ float x,y,z; } //Nicely packed struct takes up 12 byts, 3 floats in order.

float myfloats[9] = { 0, 0, 0, 10, 15, 10, -5, -10, 0 };  //Nicely packed float coordinates.

myvec somevecs[3]; //Make some vectors

memcpy( &somevecs[0].x,  &myfloats[0], sizeof(float) * 9 );  //Copy them in!


Before you scream at this; Note that this works perfectly lots of times. Apparently, there are some rare cases you can cause this to break and GDB is helpless in figuring out you just walked passed the save/writable zone in an array. It's really hard to get this kind of thing detected, especially when using pointer casts.

Basically, if you run into a situation in which you find yourself doing this; Please stop and redesign your code so you do not have to do this. Unfortunately, there is no "fast" solution without redesigning some kickass wrappers and C-style code; but if you OOP this, you run into massive overhead and ultra slowdown from all these specialized copy operations; So, what can you do.

In my testing, caching blocks of floats seems to work best, then just forcing your user to slowly copy them into their structures. Although, I don't do that, because I redesign my structure to WORK with a float * internally so this can be as fast as possible and still lexically coherent.

What a $(#@^& problem.

-Z

Here's a picture. .TED files contain a lot of information; Once I clean up this stupid problem I'll post more goodies. By the way, these are models from the PC game "I of the Dragon" because I don;t want to show my models until they look somewhat decent. Obviously, again, I'll never use these; They're only good test sets to play with.

2010-01-29

Picking, Mouse Projections, Screen to Ray

 The Problem:

When the user clicks on the 2D screen, how do we know in 3D coordinates where they actually clicked, so we can select the object they clicked on?

The Solution:

Obviously a simple geometric / linear algebra problem. It is commonly done by querying the graphics card for the projection, modelview, and viewport. I despise asking the card for anything, as it should be a one way pipe. (minus CUDA, which is still new).

Our special case is, if we know how we constructed the projection matrix, we can easily invert the process to convert a screen ray into world coordinates. Then we can make those world coordinates relative to our "camera" matrix, and you can then perform a ray to scene collision detection;

This is also called "picking", "selection", and has a variety of other names. I highly reccomend never using any method but your own geometric methods, since you can't rely on this type of functionality to be consistent, without ensuring your own code is.

In layman terms, "You can click things in 3D" / "What you see is what you get"

The orange dot is the actual 3D position of the Ray -> AABB intersection
(A Ray is defined by a point and a direction, a AABB is a axis aligned bounding box, so it has a minimum position and a maximum position, or a center and a half-size for each axis)



Here's some code snippet:

class matrix
{
    public:

    //+X = left, +Y = up, +Z = forward
    float Xx, Xy, Xz, Xw;    //Order from spec; Colum major 0..16. Have to transpose all the mathematics (internally)
    float Yx, Yy, Yz, Yw;
    float Zx, Zy, Zz, Zw;
    float x, y, z, w;

    ...


void mingl::matrix::frustum_get_ray( int umouse_x, int umouse_y, int window_w, int window_h, float distnear, float distfar, float fovangle, float & Rx, float & Ry, float & Rz, float & Rdx, float & Rdy, float & Rdz )
{

    float scrn_x =  (float)(2*umouse_x - window_w) / ((float)window_w);
    float scrn_y =  -(float)(2*umouse_y - window_h) / ((float)window_h);

    float td_dx, td_dy;

    float td_tan = tan( fovangle * (M_PI/360.0f) );

    if( window_w > window_h ){

        td_dx = td_tan * scrn_x * ((float)window_w/(float)window_h);
        td_dy = td_tan * scrn_y;
    }else{

        td_dx = td_tan * scrn_x;
        td_dy = td_tan * scrn_y * ((float)window_h/(float)window_w);
    }

    //Generate points on the projection viewport
    float p1[3] = { td_dx*distnear, td_dy*distnear, distnear };
    float p2[3] = { td_dx*distfar, td_dy*distfar, distfar };
    float dv[3] = { (p2[0] - p1[0]), (p2[1] - p1[1]), (p2[2] - p1[2]) };

    //Note this is a specialized "To Global" operation (because of the inversion on axes)
    //Ray does not start from center of camera.
    Rx = x - Zx * p1[2] + Xx * p1[0] + Yx * p1[1];
    Ry = y - Zy * p1[2] + Xy * p1[0] + Yy * p1[1];
    Rz = z - Zz * p1[2] + Xz * p1[0] + Yz * p1[1];

    //note the conversion.
    Rdx = -Zx * dv[2] + Xx * dv[0] + Yx * dv[1];
    Rdy = -Zy * dv[2] + Xy * dv[0] + Yy * dv[1];
    Rdz = -Zz * dv[2] + Xz * dv[0] + Yz * dv[1];
}
 From reading that code, you'll notice the projection matrix is defined by:

    //3D projection matrix via symmetrical frustum; the most common projection.
    float fov = 60.0;
    float aspect = 1.0;
    float unear = 0.125;
    float ufar = 1024.0;

    float top = tan(fov*0.00872664625997f) * unear;    //0.00872665f = pi / 360 = (pi / 180) * 0.5
    if( (window_h > 0) && (window_w > 0) ){

        if( window_w > window_h ){

            aspect = float(window_w)/float(window_h);
            projection.frustum( aspect * -top, aspect * top, -top, top, unear, ufar );
        }else{

            aspect = float(window_h)/float(window_w);
            projection.frustum( -top, top, aspect * -top,aspect * top, unear, ufar );
        }
    }


void mingl::matrix::frustum( float ul, float ur, float ub, float ut, float un, float uf )
{
    float dx = (ur-ul);
    float dy = (ut-ub);
    float dz = (uf-un);
    dx = (dx <= 0) ? 1.0 : dx;
    dy = (dy <= 0) ? 1.0 : dy;
    dz = (dz <= 0) ? 1.0 : dz;

    identity();

    Xx = (2.0*un)/dx;
    Yy = (2.0*un)/dy;
    Xz = (ur + ul)/dx;
    Yz = (ut + ub)/dy;
    Zz = -(uf + un)/dz;
    Zw = -1.0;
    z = -(2.0*uf*un)/dz;
    w = 0;


Works beautifully! Onward with my megaman project.

-Z

2009-11-17

mingl - progress updates

xcore / mingl is moving along quite well.

Operating on a basic create / destroy paradigm, with bind/unbind as the activation mechanism and load as the data send mechanism, it works well for abstracting graphics hardware and allowing for faster creation of intense graphics applications.

Here's a nonsense screenshot:



This is a vector field represented as moving transparent spheres that are depth sorted. The vector field is generated by 3 functions modulated together.

The shading is generated via vertex and fragment program. The meshes are using a VBO/IBO abstraction paradigm.

All is well. More later.

2009-10-31

Vertex Buffer Objects - speed testing

For drawing 32,768 meshes of 12*16*2 triangles each (1 triangle strip):

OpenGL 2.1 hardware:
VA/IA: ~230ms
VBO: ~30ms

OpenGL 1.4 hardware:
VA/IA: ~230ms
VBO: ~240ms

The note is, although your card may say it supports the VBO extension, or support VBO as per the OpenGL 1.5 specs, it doesn't.

VBO's only work in 1.5 GL's or later, due to hardware restrictions.

Remember; If you worry about optimization, you'd better have timing tests to verify that it even matters. Saving about 10% or more is useful.
Also, small frame optimizations are useless; Anyone can do those, and they generally introduce unmaintainable hacks. Worry about your high level optimizations, like using "most common failed test first" and algorithmic and design changes to maximize your logical speed.

Anyways. Here's a buncha UV spheres, as mentioned (generated using xcore + mingl):



Currently working on the texture functions in mingl. Having to write compressors/decompressors for all the DXT formats. It'll be quite useful though.

Z out. Happy Halloween.

2009-10-29

xcode, mingl, xgfx

Continuing my great adventure to construct the engine I need;
Yes Unity is now free. Who cares; What we need is a blender Synthesis program so I can use all my high def animations and levels.

xcore is moving along nicely, most data structure and memory alignment things work perfectly. Still some issues with float hacks.

mingl is quickly being put together, the abstraction of all mesh data into the VBO/IBO/VAO paradigm makes using OpenGL very very nice. In fact, learning a mingl type system is far easier than learning OpenGL fixed pipeline crap.

Vertex Buffer Objects:

They don't help unless you have OpenGL 1.5 or higher. Go figure.
And instancing doesn't really help unless you have a very specialized, small geometry item.
Here's 32,768 cubes:



If you stare too long, you begin to see a n-dimensional triangulation or worse, a shadow of a n-dimensional object.

I'll press on until I can have dancing lizard demo # 4. Or in this case, it might be a higher res female model.

Peace out.
-Z

2009-10-25

xcore, mingl, xgfx

Not much to update today; Started some new projects.

In the spirit of the IGTL::Sys classes I made (mostly copy paste from them since they're so dang useful), I am building xcore, which is responsible for:

1. OS level byte types
2. exceptions and error reporting
3. CPU identification, SSE intrinsic math and special instructions
4. Memory manager
5. Specialized templated common file structures, like index_array, carray, index_deque, string_table
6. Directory I/O and file I/O

XCore is the minimal utility toolkit that drives all of my programming. On top of XCore is an important layer called GHOST, which was coded by the blender foundation and furthur extended by me for my own projects. GHOST is a cross platform windowing toolkit that accomplishes some of these things, but not all of them. I'm using it religiously since it avoids stupid SDL licensing issues, and has support for context sharing, multiple windows, and a better event system. The nice thing is, since I use blender anyways to make all of my media, it'll be a cinch to always mention i am using code from blender, thus keeping in line with their license for distribution.

mingl is a minimum wrapper on top of OpenGL that completly abstracts it, preventing me from making any non-suppported OpenGL calls. For example, it wraps all geometry data as a vbo/ibo/vao class (read up on OpenGL 3.0 if you don't know what these are) and internally can down-support any openGL version using this system. It cannot abstract shades really well, so it looks like it will require GL 2.0+ for any shaders to even work. I'm also not sure yet if I need to write my own shader coders so that the engine can generate shaders for vertex/fragment program aas well as GLSL; This seems a little difficult at the moment so I'll defer it.

xgfx is the graphics engine that performs culling, scene management, mesh updating, keyframing, armature animations, lighting, shadowing, and all the regular crap you expect to have in a game engine.

So, with this toolchain of xcore/ mingl/ xgfx /xoal/ xnet, it should abstract all the things I need for any game, just like I did back in late 2005. Except this time, it'll be my engine with no rules and no hangups or lies to slow me down. Of other importance, it's all using C++ as much as possible, so each component should be independent as much as possible.

Z out.

2009-10-10

KDTrees and blender gui synthetics

Remember kids, if you use a synthetic oil, it's not a good idea to switch back to regular.



As far as I understand it, "KDTrees" are simply a data structure that says:

def kdtree:
def node:
x,y,w,h
split
low_node *
high_node *
parent *
direction

And, each node occupies a region of space defined by a x,y,w,h box (or x,y,z) and "splits" that box into TWO boxes, along only one of the axes (either x or y). This way, you can more efficiently partition static objects into a scene; this is like all BSP / octree scene management techniques; However, updating a KD tree is rather expensive, it really is good for storing static scenes though as it requires a far lesser node density and can expand into any other volume as needed.

So, they're used in blender's GUI; I'm getting my mockup GUI system to work slowly, and here are many panels defined by glViewports with text in them. The text system is nothing more than a badass texture font I used some free program to generate with 2 px padding and as a alpha only texture, so the memory required for those letters is quite minimal; although fonts are not conducive to mipmapping, so you must manually provide other LOD fonts for your program. Don't forget that always mipmapping is better for your hardware.



I'm also perfecting my cMesh class, which will provide a full next generation mesh including armature animation and animux system, basically equaling and exceeding the capabilities of all existing high definition games; And doing so in a manner consistent with next gen technology (VBO/Shader) while still retaining the ability to be processed via older cards, at great CPU expense.

It looks something like this:



The concept is present in all games I have hacked, and works like this:

A mesh consists of "tiles", which are separate VA/IA's that contain some amount of triangle strips/triangles/quadstrips with a consistent vertex format and ideally contiguous data. This means each tile can store different vertex parameters, the usual culprits are:

current vertex position (3)
next vertex position + weight (4) //For mesh keyframes only
texcoord 0 (2) //1st texture coordinate
texcoord 1 (2) //2nd texture coordinate (if you have seperate UV mappings, not efficient)
normal (3) //Required for any lighting
binormal (3) //can be shader generated, but space may need to exist in VA array)
matrix indicies (4) //Required to skin a mesh that has more than 1 matrix deforming it
matrix weights (4) //Required to skin a mesh properly

So, each tile can behave as a independent mesh. Above a tile is a tile state, which contains the RC (RenderCommand) array for actually issuing the stripping indicies and material changes and matrix palette updates for this mesh.

Above that is the TileTree, so you can swap/zsort/prioritize and use lod tiles as needed.

the concept of a tile is to load all mesh data into your graphic card, and then merely tell the card what to use to render via a few array binding commands. This is extremely efficient, as it supports mesh instancing to a large degree, and prevents transferring data to the card. The only drawback is you still have to transmit matrix updates to the card, but even a 270 bone character (like Valgirt) this is still far less information that a small VA.

So, once you have tiles setup, we have a generic bone/matrix animation system, with a matrix class (yes, I like quat's too, but matrices require less conversions in a game setting; these matricies can be changed to be only state driven mind you.).

The heart of this system is the base animation classes, which consist of "Keys" which are blocks of static data to interpolate between, "Channels" which are a list of keys and times, and "Animations" which combine channels together to form complete animations.

The Animux is a animation multiplexer, which combines any number of animations together, so that you can use multiple types of animations together, for instance "Run_legs" and "Shoot_Torso" like Quake, or "Face_Phoneme_ma" and "Run". This allows you to make characters that can walk, talk, and run + shoot at the same time, and even use IK calculations as you want.

I've probably done this thrice before, but THIS time, I've got it nailed, and have massive amounts of evidence and experience with the new GLSL to support this type of design. Hopefully, I can get AniStar up and running so I can actually have a program that can make animations for given characters.

Z out.

2009-10-01

Graphical 'Lag' Problem resolved

Here's the problem:

You code up a nice 3D game, and find that every time you call 'swapBuffers' your program is blocked from execution. You've tried threads, weird API's, and even low level OS hacking tricks; And nothing fixes it! Your game will still be forced to run at 60 FPS, no matter what, and every buffer swap lags your code at least 15 ms! Which is total burned CPU! And tons of dropped packets! And messages!

If you happen to have a graphics card, and specifically a NVidia one, here is the problem:

Go to start->Control Panel-> NVidia Control Panel(Display; Move to the display tab, advanced... Open the Nvidia Control Panel)

Make sure this is off:



What is happening, is it is making a crit section/thread safe block for buffer swaps, which if you write high performance games, this kills your testing phase since your game is force-lagged out.

This easily pushed my FPS and IFPS from 60 to well in the hundreds. In fact, in my GHOST test, I went from 15 RFms with 1 dropped frame to 10 RFms with 0 dropped frames. This translates to 0 dropped frames per second from 60 dropped frames per second.

I have fought this problem for a while; glad it wasn't my problem. The moral of the story? Sometimes you just have to step back and learn something new.

- Imaginary Z

2009-08-15

Hacking Success; Dragon Quest Swords broken!

Add:

Godzilla: Unleashed
Rampage: Total Destruction
Dragon Quest Swords
Monster Hunter G
Monster Hunter Tri
Super Smash Bros. Brawl
Carnival Games *
Super Mario Galaxy
NiGHTS
ect...

to the list of games I can extract models from.

I wish I knew who to give credit to, but all I needed was this little function here to finally break apart the .fpk / Dragon Quest Swords compression format (I was really close too, ironically)


typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;


int endian=1;

u32 BE32(u32 data)
{
if(endian)
return ( (data<<24) | ((data<<8)&0x00ff0000) |
((data>>8)&0x0000ff00) | (data>>24) );
else
return data;
}

int blen;
int fbuf;

/* PRS get bit form lsb to msb, FPK get it form msb to lsb */
int get_bits(int n, char *sbuf, int *sptr)
{
int retv;

retv = 0;
while(n){
retv <<= 1;
if(blen==0){
fbuf = sbuf[*sptr];
//if(*sptr<256)
//{ printf("[%02x] ", fbuf&0xff); fflush(0); }
(*sptr)++;
blen = 8;
}

if(fbuf&0x80)
retv |= 1;

fbuf <<= 1;
blen --;
n --;
}

return retv;
}

int uncomp(char *dbuf, int dlen, char *sbuf, int slen)
{
int sptr;
int dptr;
int i, flag, len, pos;

blen = 0;

sptr = 0;
dptr = 0;
while(sptr < slen){
flag = get_bits(1, sbuf, &sptr);
if(flag==1){
//if(sptr<256)
//{ printf("%02x ", (u8)sbuf[sptr]); fflush(0); }
if(dptr < dlen)
dbuf[dptr++] = sbuf[sptr++];
}else{
flag = get_bits(1, sbuf, &sptr);
if(flag==0){
len = get_bits(2, sbuf, &sptr)+2;
pos = sbuf[sptr++]|0xffffff00;
}else{
pos = (sbuf[sptr++]<<8)|0xffff0000;
pos |= sbuf[sptr++]&0xff;
len = pos&0x07;
pos >>= 3;
if(len==0){
len = (sbuf[sptr++]&0xff)+1;
}else{
len += 2;
}
}
//if(sptr < 256)
//{ printf("< %08x(%08x): %08x %d> \n", dptr, dlen, pos, len); fflush(0); }
pos += dptr;
for(i=0; i< len; i++){
if(dptr < dlen)
dbuf[dptr++] = dbuf[pos++];
}
}
}

return dptr;
}



Thanks to that mess, I could use my own BRRESToOBM and the Pipeworks1.4ToOBM converters to completely extract the models and import them into blender.

Why do this, you ask?

Simple! Since NOT A SINGLE DAMN PERSON here is competent enough to help me, my only method of QA/QOS/QMS/verification is checking my work against commercial products. It's a very useful method as you often get to see techniques for animation, texturing and shading that are well known to industry but not well documented, or just plain hard to find.

Some of the cool things I've learned:

*Use additional bones inside of the arm joints on your characters; This allows you to retwist the arm visually while still keeping the IK chain unbroken. This is a classic character animation technique that I never had seen in practice.

*Use lots of matrices and bleed the weights out as much as possible, trying not to exceed 4 weights per vertex; Don't just use 0.5/0.5 blending factors (Valgirt has 272 bones...)

*If you are applying a bump/normal map to a character, use the I8A8 texture format and simply calculate the z component in the shader; This costs no additional instructions AND guarantees a normalized z component which you would have to do anyways.

*Use well painted textures, and don;t be afraid to use non-contiguous models (fins, talons, tongues, even neck/finger joints do not always have to be connected to the base mesh!

*Make sure you add in additional transform bones to characters, such as a Root Node and X/Y rotation nodes.

*for mesh modeling, targeting 3k verticies isn't really an issue.

*Always sort your meshes by: Material, Matrix Deformation Pool, Index array type.

*Always convert your final mesh pools into triangle strips if you can; Avoid quads and triangles. If you must use triangles, sort them in a indexed triangle list so that each next triangle shares adjacent verticies. Note that on file loading, you can always convert strips back to triangles; but not the other way around.

*Matrix deformation systems allow you to do things you could never do with bone animation systems; Since you just get a 3x4 float matrix per 'bone', you can apply translation, rotation, scale, and shear transformations. Since the hardware is unaffected by the values you put in those matrices (same number of ops) you're allowed to really have fun animating and be guaranteed consistent results anywhere.

*Mesh keyframes are A-OK and should be combined into your matrix mesh; for example facial poses and stuff. Simply apply those before running your mesh through the shader; You can get very awesome character animations this way.

*Try and avoid making your matricies match a 'skeleton' of you character; This often results in hard mechanical animation that looks not fun. It also makes your artists have to work harder, because a 'bone' does not behave like a matrix. Usually, with matrix deformations, you want the matrix to be at the 'ring center' of the mesh data, so that scaling and transforms will behave as you expect. Interestingly, since matrices have no constraints, you can always make this look like the hard mechanical, but you can't do that the other way around.

*Add additional target matricies; It only costs a small amount of CPU and gives your models flexibility for grapple animations, picking up objects, and easier cinematic animations

*I've seen 11,000 vertex models fully shaded on the Wii. No kidding. With 200 + bones. Think about that for a second. Think about how much more powerful your PC is than that.

*Most importantly, animate/design for fun. Don't make things realistic; It's a waste of your time because commercial studios can always do that better than you can. And who wants to play a realistic game anyways?

I'll post pics later, today I have more beer to acquire!

-Z

2009-07-04

Technically Competent Flash Game Engine

After playing with flash enough (Flash Professional 8)
I've reached a conclusion about how to build powerful, dynamic flash games.

I've worked with flash off and on for years, C/C++ and OpenGL are much cooler, but it has become difficult to manage my pipeline without additional tools that do not exist; So I am taking a break from that for a bit.

In order to properly make a flash game, you must first understand what a 'video game' is and how it works internally; They are full of interesting technical challenges as well as evil hacks; Because a game tends to be a simulator or emulation of some system, that means we'll never be able to truly make exactly what we want, either due to time or power constraints.

With that in mind, let's build up a 'megaman' example game.

We know from playing the megaman series on the NES that megaman is a little robot dude that can shoot other robots, some of which can move around and shoot back! And, if he enters a boss room, he can shoot a special enemy that can give him additional weapons!

Not much else too the game, really! Let's generalize it.

What kinds of things are there in the game?
-Sprites (2D Pictures)
-Sounds (Sound effects)
-Music (Longer strings of sounds! .nsf or some other mod format)

Well, that's kind of an aesthetic look. The actual game however, isn't quite as simple, as there are a variety of object types, like each type of enemy, each type of bullet, and so on.

When we look at a game from the programmers perspective, we can group all the things that work that same, and build a hierarchy:

Object
-Sprite
-Moving Object
--Bullet
--Controlled Moving Object
---Enemies
---Megaman

So, for each level down we go, we have to add more special code; There still is no magical way to code each type, that will ultimately have to be done. However, we can reduce the amount of work signifigantly by providing generic utilities for moving and updating those objects;

For example, we can have "MoveAsPlatformingCharacter" "MoveAsFlyingThing" "MoveAsBullet".

And, the ironic thing, is the game is still just moving pictures that can add and remove pictures and sometimes play sounds. There isn't anything more to it than that.


So, stepping back a bit, let's look at what flash can do for us:

-Automatic Heirarchy
-Display sprites, images, movies...
-AND can move, rotate and scale them!
-AND can colorize, shade, ect...
-AND can dynamically draw shapes!
-Automatic Sound playing
-Streaming music palying
-Input handling

So flash can do everything we need! But, flash is not assembly code, it is a SCRIPT LANGUAGE. That means that you cannot apply the same logic you use in C to flash; Script languages are not C, and C is not a script language and vice versa.

So in flash terms, we will have 1 movie clip called 'game' that has everything we need in it, as well as having ALL the functions we will use in it, so that you can do this:

game.moveObject( obj, 4, 0 ); //Move object obj right by 4 units

Inside of the game movie clip, we must have all the clips we want to duplicate in real time. Usually this is accomplised by:

game.dup_character;
game.dup_bullet;
ect...

Where, inside each of those dup_character, you have a lot of named frames for that specific character type, like "Heatman", "Iceman", "Megaman", and in each of those frames, you put down the instance of the clip you want to animate; you do not do the animations in the duplicate clip, you make a seperate layer;
This way, you can name each clip inside of the duplicate clip the SAME THING, ergo: "mc", so that the game can reference the mc identically for each instance, AND separate scaling and other properties from it.

[MovieClip: dup_robot]
[FrameName : "Megaman"]
mc [Instance of "Megaman" movie clip, which has all his named animations, like "run", "jump", ect...]
[FrameName : "Heatman"]
mc [Instance of "Heatman" movie clip, which has all HIS animations ]

so your 'game' clip now has this:

[game : Game clip]
dup_robot [Instance of "dup_robot" movie clip, which has all the possible robot types each in a specially named frame]
dup_bullet [Instance of "dup_bullet" movie clip, which has all possible bullet types each in a named frame]
ect...

Using this method, you can simply duplicate a dup_clip, then set it's frame, then once you do that, you can set the mc inside of it's frame, thus instantly allowing your game to be very flexible to add extra things later!

So this is all fine and dandy' Now in flash you can duplicate any clip that graphically represents what your game is, but, what about the actual game?

Here's where it get's difficult; If you trust flash's 1 collision function (hitTest) then you might know that it DOES NOT WORK on and point test that is NOT on the stage (any non-rendered pixel CANNOT be hit-tested against. SO DONT USE IT!)

That means yes, you have to make up your own collision scheme, and make up your own collision math, and your own physics system for motion.

Basically, that means that every object should have a .x, .y, .vx, .vy in it, so you can perform basic rectilinear motion. As for updating your objects, so long as you make a working rectilinear motion function, you can add any complex types of motion you want later.

This will be covered later, but the easiest solution is to add another dup_clip that creates boxes and ramps, which are very basic and mathematically simple collision primitives that you CAN make a game out of quickly.


But all this high level talk isn't much use; Because when you get started, you'll find you need a couple of basic tools:

Something to store this data,
A Map (dict for those python kidz)
A SpaceHashing/Broadphase test

Map is actually simple in flash,

var mymap = new Object();
mymap[ "any key as a string" ] = data;

So you can abuse flash's quick Log2(n) internal string search for object properties as a map. It's as fast as it get's folks.

A Spacehash is up to you, I prefer using a single axis sort and doing a map/array of bins, which have maps of catergories, each which stores an object UID

Yes, every object you make should have a non-repeating Unique ID. Don;t rely on the movieclip as one, you never know when depth levels can change or clips for that matter. Use a Number and just increment it, or make a map and reuse unused keys.

Blargh; What a mess. Too much information to disgorge for ya'll.

I'll post the flash engine later. Then you can just %#@*(& use it!

Happy fourth!

-Z

2009-03-05

Quick Post

Alright.

Quadtrees using proxy indicies are too slow (because if you don;t define them carefully, AKA if you don;t enforce data always being in the leaves, well, it goes to hell. Draw it out to see what happens.)

Quadtrees using leaved index lists seem to do OK, however, their performance is not that good. It certainly costs a lot of memory and speed to handle space, and they are conformal space limiting.

Thus, we are required to develop a better, more efficient structure. In this case, I choose a interval list. However, you immediately scream "O(n)!" and to that, I say "Balanced Binary Tree"

Of course, you mutter about "2 log2(n)" but you;d be right for deletions. Additions are worst case log2(n).

Actually, if you think about it, given a random set of any data, the absolute fastest way to sort and store that list IS clamped at a maximum of log2(n). You might think that hashtables can beat it, but come on peoples, hashtables are application specific optimization. Sure, if you know your inputs are bounded you can hashup your memory and get a hashlist of B-Trees, but is that step actually going to save much? And besides, looks like you still HAVE TO MAKE THE GODDAMN TREE!

In summary, this is the current problem. If you think you are smart, solve this problem. When you find out you're an idiot, don't complain to me:

Given a random set of intervals (minimum (float32) and size (float32), create a data structure that can store these intervals sorted by the minimum value, and be able to quickly determine interval queries, AKA stabbing queries. The structure should have as minimum a memory footprint as possible, and you can assume you have Alloc, Realloc, Free working properly. Also, the structure cannot use hidden operations internally (No OOP or C++ tricksies internally), however externally it may operate as a class interface. It must support insert( proxy ), remove( proxy ), and get( float min, float size. ProxyList & ). A proxy contains at least unsigned int user, which contains the user data for what the proxy is in user memory. It cannot leak memory. It must work in practice and be implemented.

Practical application? Pretend you are building a 2D game that uses edges for level collisions, which can be added and removed every frame, on the fly. (in the editor) Once the user is happy with their setup, obviously we use a static BVH for static data.

Good Luck!

-Z

2009-02-20

Hey look, a quadtree


So what's so special? This is a common data structure that everyone one of you should be able to do from memory. It's extremely simple, and uses recursion. Simply make a tree with each node linking to 4 child nodes that evenly divide space, and let each node store a list of pointers or the data itself.

The special part, is this is a generic quadtree, so, instead of 'storing' objects, it stores XData::Quadtree::Proxy object POINTERS to a XData::List, which means that Proxy lifecycle is left to the user (working on making it pointeriffic and more auto-delete) but that also means that every node stores a list of those proxy pointers, so that your game object:

class MyGameObject : public Game::BaseObject {
private:
XData::Quadtree::Proxy m_proxy;
}

Can simply access the quadtree as such:

qtree.insert( obj.m_proxy );
qtree.remove( obj.m_proxy );
m_proxy.IsValid();
qtree.get( XData::Array &, fptr_to_Collision_Function, collision_function_data );

So what this means, is in the above picture you can draw arbitrary edges for a odin-sphere style level, which get their proxies put into the quadtree. This is dangerous only if you forget to remove the proxy before deleting the object. But it means that you can query arbitrary shapes against the quadtree and get a quick enough broadphase test for intersection. Insertion is always better than O(log(n)), deletion/update is best case O(1), worst case O(log(n) + 1). Access is linked list, so fast iteration is possible.

Quadtree's are good for dynamic data, that is if everything is changing quickly. There are other methods for static data that are far superior, like KDTrees or Spaceblocks or even AxisSweeps, but quadtrees are a general good purpose solution that's still good in performance to be viable for many applications. In fact, you probably won't need much more than this, unless you have severe restrictions that force you to use sorted space blocks.

If you are making a 2D game, please do not use tiles. I will hate you, and you should be competent enough to make a quadtree (think Game Maker) that can handle arbitrary shapes and so forth.

Go look at this game to see one of these methods in action

-Z

2008-10-15

Busy stuff; Mental Agony; And booze to death

Been a while; Been to busy with my Game Co. to do much else; Lots to do, lots that needs to be done; And there are literally thousands of options available for usage;

I looked hard, very hard at some 'game engines'. Those of you who know me well know I hate them with a passion; There should never be a 'Game engine' there should only be a component based toolkit (define your interface before coding, idiots!) that can tackle the basic repetitive problems in games. It should also be documented, and very clean to work with and read. IGTL is slowly putting itself together more and more; More tools and abilities crop up all the time, and I wonder how to recruit more coders.

It comes to my attention that the complexity of building an engine isn't really so much in doing so; It's actually derived from two specific things, 1 being platform compatibility, the other mathematics. Trying to make things work on windows and mac and linux is magnitudes easier than it used to be, things are more standard. But in the REAL world, you end up still doing #define out the ass in order to make your cute little interface work per compiler per platform. I hate it, but there is no other way to get around it, unless you wrote code to write the code itself like I did. So far as tackling the huge collection of advanced mathematical problems in a 3D environment, most people wimp out and curl up and die when they see something hard. Instead of just thinking it through, they say 'I'll let someone else do it'. This is generally accepted for people on a budget and time constraint; I feel sorry for the people that have to 'just make it work'. On the other side of that, all of this math was ALREADY DONE in the 1930's, and has been forever repeated due to lack of documentation and academic jacking.
For example, when some jackoff starts writing articles about quaternions and rotations, they start talking about affine transformations, linear algebra, matrix blah de blah... and neglect to mention the ACTUAL PRACTICAL APPLICATION which means X forward, Y left, Z up, which is also called 'right hand coordinate system'. They also don't name functions that make sense; overloading operators, lacking any sort of conversion sense...

I really, really hate programmers. And programming. It's a horrible, stupid thing that we all have to re-do so many stupid problems because of industry incompatibility; I understand WHY we have to, but it still seems so wrong. Defeats the purpose of being sentient, almost. That's okay, because the promise of money is soon to fall, and everything will literally go to hell. Regardless of which way you vote (Obama rules!) you're still going to die.


....aaaanyways, enough of me bitching out code. Let's talk bidness. Logically speaking, I would much prefer to use a decent rendering system; OGRE kinda worked, but ended up being clunky, and bloated, and didn't work. G3D and most other engines relied on the MS compiler series; fine for them, shitty for me. OpenGL & GLSL is still the driving force behind all the pretty, and that works everywhere. So long as you write code to read Khronos groups' glext.h and create your own cross-platform glextplus.h so you can load extensions via macros for any platform (yeah yeah yeah, "glew did that already!". Have you TRIED using it? a$$.). Always, always ALWAYS use some sort of premade wrapper per OS. (SDL is good, wxWidgets is great, but not so much for games. Actually, in speed tests, SDL is slightly faster, but wxWidgets does NOT have correct joystick or media support. So use SDL for the game, console for the server, and wxWidgets for the dev tools. Simple as that.) Try using a 3rd party rendering system. If you have to roll your own, DESIGN THE GAME FIRST so you don;t blow your brains out trying to figure out 'oh emm gee, my occlusion culling super material shader proxy instancing node tree up my ass is broken!'.
Work with your team. Find out what they can do, and what data they are comfortable making. Use this information to build or select a uniform media type THAT HAS A FUCKING OPEN SPECIFICATION, dammit. And make absolutely sure it fits within the constraints of your game (for example, if you want IK, don't use a MD2, dipshit)

GAAARRGGHHHH!! I need more coders to help me. One guy can do it, but not without losing his sanity.

Here's a collage of old school demo stuff I played with. Since all the art (minus that green dragon) is mine, it doesn;t look good. Pretend I hired a 5th grader to make it for me.


This week I will be partying with my brothers in blood;
Tomorrow, WE DRINK IN HELLLLL!!!