Try it now!
Current test as a local zip:
http://www.gocaco.com/webgl/test1/Test.zip
Current TED exporter:
http://www.gocaco.com/webgl/igtl_export_ted.py
Added some bugfixes for animations;
Added the ability to configure "setups" which can assign positions, rotations, animations to objects in a scene.
Eventually, I'll replace this system with more game-level functionality, as well as update the method data is loaded in favor of "precompiled" models with external texture references. It will take a while to get a Blender 2.57 exporter for this; but I'll keep trying.
First project I need to try is a robotron clone since it doesn't require advanced collisions.
Here is an example use (Farina II rough level), you can correct file export errors with a setup for proper viewing/interacting.
However, it is obvious the terrain shader was not loaded because it isn't exported yet; Nor is the glowing gem in the cage. These are serious problems with the pipeline of data exported from blender, but are fixable. The only question is whether to focus on 2.57b+ or 2.49b-. I'll probably stick with 2.5X.
-Z
Miscellaneous banter, Useful mathematics, game programming tools and the occasional kink or two.
2011-04-27
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.
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 );
}
Labels:
algorithm,
code,
math,
statistics
2011-04-16
WebGL - Preview local TED files
Try it now!
Current test as a local zip:
http://www.gocaco.com/webgl/test1/Test.zip
Current TED exporter:
http://www.gocaco.com/webgl/igtl_export_ted.py
If you have any local files, you can now browse for and load them.
You can also drag them over into the 3D area, and it will load them automagically.
Some interesting notes about this.
Security wise, I would rather have a notification come up if a javascript script was attempting to "read" any local files. I DO want this to occur, but let me either block ALL of them, or choose as they are requested to be loaded.Firefox understands this, but I cannot find it's setting to make it warn you when a script reads a local file. Apparently the act of dragging and dropping or using the file open dialog is confirmation enough, and that's OK.
Chrome however, is dumb, and will not read any local files unless you add the additional command like switch "--allow-file-access-from-files" switch to it. DO NOT DO THIS if you are online, only do this while developing or playing locally. Because chrome is kinda insecure like that, might as well not use it until they fix this extremely annoying bug. Get Chromium instead.
Examples of chrome stupidness: "There is nothing Gmail can do to defend itself from this attack." "In the future, we hope to further restrict the privileges of local web pages." "Ultimately, we'd like to see all the browser vendors converge on a uniform, secure policy for local web pages." Seriously? Are these dumbassess tripping? Give us control of some of those flags, and then configure the flags to make your "security" work. Don't generalize and call that good, that's what mac does and why it is so much fail. Give control to advanced uses, set the defaults for your pseudosecurity model, everyone wins. Like firefox.
The option for "Only allow local access with user permission" would be nice, and it could pop up a modal dialogue with timing/input security. Not failproof (did you know you can write code to make fake human input? lol ur h4xed), but it's better than a blanket policy.
An old BomberFan level, made for BGE. Since it was an old blender, blender materials were ignored in favor of face textures, which is why nothing looks right.
-Z
Current test as a local zip:
http://www.gocaco.com/webgl/test1/Test.zip
Current TED exporter:
http://www.gocaco.com/webgl/igtl_export_ted.py
If you have any local files, you can now browse for and load them.
You can also drag them over into the 3D area, and it will load them automagically.
Some interesting notes about this.
Security wise, I would rather have a notification come up if a javascript script was attempting to "read" any local files. I DO want this to occur, but let me either block ALL of them, or choose as they are requested to be loaded.Firefox understands this, but I cannot find it's setting to make it warn you when a script reads a local file. Apparently the act of dragging and dropping or using the file open dialog is confirmation enough, and that's OK.
Chrome however, is dumb, and will not read any local files unless you add the additional command like switch "--allow-file-access-from-files" switch to it. DO NOT DO THIS if you are online, only do this while developing or playing locally. Because chrome is kinda insecure like that, might as well not use it until they fix this extremely annoying bug. Get Chromium instead.
Examples of chrome stupidness: "There is nothing Gmail can do to defend itself from this attack." "In the future, we hope to further restrict the privileges of local web pages." "Ultimately, we'd like to see all the browser vendors converge on a uniform, secure policy for local web pages." Seriously? Are these dumbassess tripping? Give us control of some of those flags, and then configure the flags to make your "security" work. Don't generalize and call that good, that's what mac does and why it is so much fail. Give control to advanced uses, set the defaults for your pseudosecurity model, everyone wins. Like firefox.
The option for "Only allow local access with user permission" would be nice, and it could pop up a modal dialogue with timing/input security. Not failproof (did you know you can write code to make fake human input? lol ur h4xed), but it's better than a blanket policy.
An old BomberFan level, made for BGE. Since it was an old blender, blender materials were ignored in favor of face textures, which is why nothing looks right.
-Z
Labels:
webgl
2011-04-11
WebGL - I hate chrome
Try out webgl: (you should click the "load" button, and see "Blender", a blue sphere, a red pyramid, in a room.)
Try it now!
Current test as a local zip:
http://www.gocaco.com/webgl/test1/Test.zip
Current TED exporter:
http://www.gocaco.com/webgl/igtl_export_ted.py
I attempted to test it on Chrome, and after instantly hating chrome, which is severely lacking in features, performance, and stability (as advertised. huh.); It's also missing most all my usual tools that are cleanly implemented in firefox. Chrome is no competition, minus it's nifty threading of scripts. Seems like good ole' google is becoming exactly like microsoft, pointing to the ultimate downfall of all software based empires. It's simply evolutionary that we continually kill off good products with lawsuits, antitrust and other money sucking schemes which hurts everyone because they then have to side with more evil tactics (like online installation, automatic updates, spyware, ads, ect...) just to survive. So long as money is required for software, this will occur.
Anyways, to get chrome to even work, I had to add these three lines to the command console, which I highly recommend NOT adding the last one, the "--allow-file-access-from-files" because that one should only be true for offline files.
"--ignore-gpu-blacklist --enable-webgl --allow-file-access-from-files"
Interesting note, firefox understands that a local file has a local domain of "./" and can pull things from it. It has no problem. Chrome says this is a cross domain error, when it clearly pulled the file from "./" and then decides it's cross domain because it has a "file://" prefix? No sense there. How about asking me you stupid %@(& browser? And I'll say "get as pure text only." and I'll force a MIME type of text/xml. Then everyone wins right?
Ugh. whatever. Fuck chrome. Though, I suppose getting firefox to use webgl is hard too.
-Z
Try it now!
Current test as a local zip:
http://www.gocaco.com/webgl/test1/Test.zip
Current TED exporter:
http://www.gocaco.com/webgl/igtl_export_ted.py
I attempted to test it on Chrome, and after instantly hating chrome, which is severely lacking in features, performance, and stability (as advertised. huh.); It's also missing most all my usual tools that are cleanly implemented in firefox. Chrome is no competition, minus it's nifty threading of scripts. Seems like good ole' google is becoming exactly like microsoft, pointing to the ultimate downfall of all software based empires. It's simply evolutionary that we continually kill off good products with lawsuits, antitrust and other money sucking schemes which hurts everyone because they then have to side with more evil tactics (like online installation, automatic updates, spyware, ads, ect...) just to survive. So long as money is required for software, this will occur.
Anyways, to get chrome to even work, I had to add these three lines to the command console, which I highly recommend NOT adding the last one, the "--allow-file-access-from-files" because that one should only be true for offline files.
"--ignore-gpu-blacklist --enable-webgl --allow-file-access-from-files"
Interesting note, firefox understands that a local file has a local domain of "./" and can pull things from it. It has no problem. Chrome says this is a cross domain error, when it clearly pulled the file from "./" and then decides it's cross domain because it has a "file://" prefix? No sense there. How about asking me you stupid %@(& browser? And I'll say "get as pure text only." and I'll force a MIME type of text/xml. Then everyone wins right?
Ugh. whatever. Fuck chrome. Though, I suppose getting firefox to use webgl is hard too.
-Z
2011-04-10
WebGL - TED DXML importer animation test
Animations and animation playback added. Posing is better, glitch with animation frame fixed, Objects retain independent armature state, small speedup.
Current Test:
Test it right now!
http://www.gocaco.com/webgl/test1/Test.zip
Current Exporter:
http://www.gocaco.com/webgl/igtl_export_ted.py
This pretty much has everything that's in a TED file, which, for your reference, contains:
Mesh data (coords, texcoords, normals, tangents, matrix palette weights, colors, params)
Textures (including texture data if you want)
Materials (some parameters, illy defined for now.)
Armatures (Includes bones, IK chains, armature splines, lots of data)
Animations (Includes channel blending animations, so channels are seperate and integrated. Includes scripts.)
Scenes (all objects and their properties)
Though there are still more things, this is the basics to get started cleaning this mess up and making it easier to work with. I don;t need the BGE if I can load this stuff into WebGL. That's what's really nice.
Although, it has some really painful disadvantages, mainly input problems, no joystick support, bad keyboard input events, no locking the mouse so no FPS possible... and so on.
Here's 9 marios independently running (bad running animation, I know. took me a minute ok??)
And 25 marios...
Most of the speed is CPU <-> GPU delays. Just remember that 1 gpu "talk" takes 6~100's of CPU cycles because of the bus communication. So, this is a "absolute worse case" naive way to do this, and I still get 15 FPS with 100k fully shaded armatured polygons. As a side note, an average frame of Oblivion as ~200k polygons, but most all of them were static (75% static to 25% dynamic).
-Z
Current Test:
Test it right now!
http://www.gocaco.com/webgl/test1/Test.zip
Current Exporter:
http://www.gocaco.com/webgl/igtl_export_ted.py
This pretty much has everything that's in a TED file, which, for your reference, contains:
Mesh data (coords, texcoords, normals, tangents, matrix palette weights, colors, params)
Textures (including texture data if you want)
Materials (some parameters, illy defined for now.)
Armatures (Includes bones, IK chains, armature splines, lots of data)
Animations (Includes channel blending animations, so channels are seperate and integrated. Includes scripts.)
Scenes (all objects and their properties)
Though there are still more things, this is the basics to get started cleaning this mess up and making it easier to work with. I don;t need the BGE if I can load this stuff into WebGL. That's what's really nice.
Although, it has some really painful disadvantages, mainly input problems, no joystick support, bad keyboard input events, no locking the mouse so no FPS possible... and so on.
Here's 9 marios independently running (bad running animation, I know. took me a minute ok??)
And 25 marios...
Most of the speed is CPU <-> GPU delays. Just remember that 1 gpu "talk" takes 6~100's of CPU cycles because of the bus communication. So, this is a "absolute worse case" naive way to do this, and I still get 15 FPS with 100k fully shaded armatured polygons. As a side note, an average frame of Oblivion as ~200k polygons, but most all of them were static (75% static to 25% dynamic).
-Z
2011-04-08
WebGL - TED DXML importer with armatures; animations needed
Yet another update. Now you can mess with the bones of whatever you imported, albeit unoptimized and rather slow, in comparison to the identical C++ program.
Current Test:
http://www.gocaco.com/webgl/test1/Test.zip
Current Exporter:
http://www.gocaco.com/webgl/igtl_export_ted.py
Next up is probably cleaning or testing animations. It is obvious that speed optimization is needed badly, but the math does not really change much; Javascript seems to be missing access to SSE type data. As well as mouse input not based on pixels, and joysticks, and a audio API, ect...
In a less complete sense, I modified the matrix conversion function to be smaller; though it's not computationally faster. The object with matrix animation/ armature animation is as follows:
Parent Armature Space Matrix * Default From Parent Matrix * Current Local Transform = Current Armature Space Matrix
Parent Armature Space Matrix => The transform of the parent, as calculated with current animation data.
Default From Parent Matrix => Upon loading an armature, calculate this by Parent^-1 * Current. This represents the initial rotational and positional offset from the initial bone positions to eachother, which allows your animation local data to be relative to that starting point.
Current Local Transform => The offsets, like position, rotation, scale. Depending on how you want to apply scale this can be tricky.
Current Armature Space Matrix => The final transformed position; send t his to the 'convertforshader' algorithm.
And, in effect, animating is only changing the set of local deformations over time, and possibly adjusting them with things like IK or mouselooks. And all that is best done with SSE operators.
I bent up this Chameleon Boss from Metroid: Other M.
-Z
Current Test:
http://www.gocaco.com/webgl/test1/Test.zip
Current Exporter:
http://www.gocaco.com/webgl/igtl_export_ted.py
Next up is probably cleaning or testing animations. It is obvious that speed optimization is needed badly, but the math does not really change much; Javascript seems to be missing access to SSE type data. As well as mouse input not based on pixels, and joysticks, and a audio API, ect...
In a less complete sense, I modified the matrix conversion function to be smaller; though it's not computationally faster. The object with matrix animation/ armature animation is as follows:
Parent Armature Space Matrix * Default From Parent Matrix * Current Local Transform = Current Armature Space Matrix
Parent Armature Space Matrix => The transform of the parent, as calculated with current animation data.
Default From Parent Matrix => Upon loading an armature, calculate this by Parent^-1 * Current. This represents the initial rotational and positional offset from the initial bone positions to eachother, which allows your animation local data to be relative to that starting point.
Current Local Transform => The offsets, like position, rotation, scale. Depending on how you want to apply scale this can be tricky.
Current Armature Space Matrix => The final transformed position; send t his to the 'convertforshader' algorithm.
And, in effect, animating is only changing the set of local deformations over time, and possibly adjusting them with things like IK or mouselooks. And all that is best done with SSE operators.
I bent up this Chameleon Boss from Metroid: Other M.
-Z
Labels:
webgl
2011-04-07
WebGL - TED DXML importer bones work; needs animations
I got the bones working using some prior work from xcore/mingl.
Unfortunately, it's difficult to show this without a logically consistent animation; However, if you play with the matrix values you can see it works perfectly.
Current Test:
http://www.gocaco.com/webgl/test1/Test.zip
Current Exporter:
http://www.gocaco.com/webgl/igtl_export_ted.py
You probably have wondered how skinning works; Skinning is a procedure where static mesh data is deformed by adjusting the position, rotation, and scale of a transformation matrix. Usually these transform matrices are 4x4 matrices, but 3x4 work just as well.
To achieve a less blocky look, you can apply two or more different matrices to the same vertex; which results in a blending of the motion, controlling the weight of each blend is an art in and of itself. It can take many hours of time to get weights that work for a particular task, elbows and other sharply bending joints being key offenders.
Here is the current unoptimized method I use for matrix palette skinning:
Here's a picture of Lara, imported.
Here's the same Gigginox from before, with slight wobble applied via matrix palette. Note this is the exact same file, I am just changing the import into javascript. TED files contain a lot of information.
Animation data is next.
-Z
Unfortunately, it's difficult to show this without a logically consistent animation; However, if you play with the matrix values you can see it works perfectly.
Current Test:
http://www.gocaco.com/webgl/test1/Test.zip
Current Exporter:
http://www.gocaco.com/webgl/igtl_export_ted.py
You probably have wondered how skinning works; Skinning is a procedure where static mesh data is deformed by adjusting the position, rotation, and scale of a transformation matrix. Usually these transform matrices are 4x4 matrices, but 3x4 work just as well.
To achieve a less blocky look, you can apply two or more different matrices to the same vertex; which results in a blending of the motion, controlling the weight of each blend is an art in and of itself. It can take many hours of time to get weights that work for a particular task, elbows and other sharply bending joints being key offenders.
Here is the current unoptimized method I use for matrix palette skinning:
//This procedure works for any input matrix, and converts it for shader use.
var stupid = mat4.create(); //Replace stupid with your armature-space bone matrix.
//Normally, stupid has translate * scale and rotation applied, and scale is applied last.
//You can pass in any matrix you like, just be aware how your modeling program transforms.
//Create some space
sseB = new Float32Array(16);
sseM = new Float32Array(16);
resM = new Float32Array(16);
//Local armaturespace matrix transposed:
sseB[0] = stupid[0];
sseB[1] = stupid[4];
sseB[2] = stupid[8];
sseB[3] = stupid[1];
sseB[4] = stupid[5];
sseB[5] = stupid[9];
sseB[6] = stupid[2];
sseB[7] = stupid[6];
sseB[8] = stupid[10];
//Original armaturespace matrix transposed:
sseM[0] = BAOrigMatrix[0];
sseM[1] = BAOrigMatrix[3];
sseM[2] = BAOrigMatrix[6];
sseM[3] = BAOrigMatrix[1];
sseM[4] = BAOrigMatrix[4];
sseM[5] = BAOrigMatrix[7];
sseM[6] = BAOrigMatrix[2];
sseM[7] = BAOrigMatrix[5];
sseM[8] = BAOrigMatrix[8];
//Multiplication; Transpose result //012 345 678 => 036 147 258
resM[0] = sseB[0]*sseM[0] + sseB[1]*sseM[1] + sseB[2]*sseM[2];
resM[3] = sseB[0]*sseM[3] + sseB[1]*sseM[4] + sseB[2]*sseM[5];
resM[6] = sseB[0]*sseM[6] + sseB[1]*sseM[7] + sseB[2]*sseM[8];
resM[1] = sseB[3]*sseM[0] + sseB[4]*sseM[1] + sseB[5]*sseM[2];
resM[4] = sseB[3]*sseM[3] + sseB[4]*sseM[4] + sseB[5]*sseM[5];
resM[7] = sseB[3]*sseM[6] + sseB[4]*sseM[7] + sseB[5]*sseM[8];
resM[2] = sseB[6]*sseM[0] + sseB[7]*sseM[1] + sseB[8]*sseM[2];
resM[5] = sseB[6]*sseM[3] + sseB[7]*sseM[4] + sseB[8]*sseM[5];
resM[8] = sseB[6]*sseM[6] + sseB[7]*sseM[7] + sseB[8]*sseM[8];
//Load and transpose it, then multiply by inverse original position
resM[12] = stupid[12] - (resM[0]*BAOrigPosition[0] + resM[3]*BAOrigPosition[1] + resM[6]*BAOrigPosition[2]);
resM[13] = stupid[13] - (resM[1]*BAOrigPosition[0] + resM[4]*BAOrigPosition[1] + resM[7]*BAOrigPosition[2]);
resM[14] = stupid[14] - (resM[2]*BAOrigPosition[0] + resM[5]*BAOrigPosition[1] + resM[8]*BAOrigPosition[2]);
//Replace myPaletteIndex with the bone index (for the matrix palette) you want to upload to.
//Remember that armature bones are mapped to the matrix palette, which is often small (28 max bones).
var locpos = 3*myPaletteIndex;
//Get the location of your uniforms
var uploc0 = myshader.pMatrixPaletteUniforms[ locpos ];
var uploc1 = myshader.pMatrixPaletteUniforms[ locpos + 1 ];
var uploc2 = myshader.pMatrixPaletteUniforms[ locpos + 2 ];
//Upload your converted matrix vec4's:
gl.uniform4fv( uploc0, [resM[0], resM[3], resM[6], resM[12]] );
gl.uniform4fv( uploc1, [resM[1], resM[4], resM[7], resM[13]] );
gl.uniform4fv( uploc2, [resM[2], resM[5], resM[8], resM[14]] );
...in your shader, you can now:
//Input vertex position (model space/armature space initial undeformed)
inpos = vec4( vattribPosition.xyz, 1.0 );
if( vattribWeights.x > 0.0 ){
//Use index cumulation (because we cannot upload integers); ie:
//
// w0,w1,w2 => (w0 + 64*w1 + 64*64*w2); floats have perfect 23 bit accuracy for ints.
//
int idex0 = 3*int(mod( vattribWeightIndex.z, 64.0 ));
//Matrix (used?)
rescur.x = vattribWeights.x * dot( inpos, MatrixPalette[ idex0 ] );
rescur.y = vattribWeights.x * dot( inpos, MatrixPalette[ idex0 + 1 ] );
rescur.z = vattribWeights.x * dot( inpos, MatrixPalette[ idex0 + 2 ] );
poscur = rescur;
if( vattribWeights.y > 0.0 ){
int idex1 = 3*int(mod( vattribWeightIndex.z/64.0, 64.0 ));
rescur.x = vattribWeights.y * dot( inpos, MatrixPalette[idex1] );
rescur.y = vattribWeights.y * dot( inpos, MatrixPalette[idex1 + 1] );
rescur.z = vattribWeights.y * dot( inpos, MatrixPalette[idex1 + 2] );
poscur += rescur;
if( vattribWeights.z > 0.0 ){
int idex2 = 3*int(mod( vattribWeightIndex.z/(4096.0), 64.0 ));
rescur.x = vattribWeights.z * dot( inpos, MatrixPalette[idex2] );
rescur.y = vattribWeights.z * dot( inpos, MatrixPalette[idex2 + 1] );
rescur.z = vattribWeights.z * dot( inpos, MatrixPalette[idex2 + 2] );
poscur += rescur;
...ect
}
}
}
//Apply object transform to final position:
gl_Position = uPMatrix * uMVMatrix * vec4(poscur.xyz, 1.0);
Here's a picture of Lara, imported.
Here's the same Gigginox from before, with slight wobble applied via matrix palette. Note this is the exact same file, I am just changing the import into javascript. TED files contain a lot of information.
Animation data is next.
-Z
WebGL - TED DXML importer preliminary bones
Importer reads armature data and assigns armatures to meshes.
Next step is fixing the matrix palette shader, and the way armature instances are updated so that the animations will play properly.
Lucky for me I've already done all the hard work in other C/C++ programs, so it's just a port really.
Just as a note, it is fairly annoying to both apply animations, save the global game transform, then before drawing convert each global transform into shader ready data by a set of matrix multiplications (read matrix palette skinning articles). But it does work, and it'll have to do until I find better solutions.
Need animations...
-Z
Next step is fixing the matrix palette shader, and the way armature instances are updated so that the animations will play properly.
Lucky for me I've already done all the hard work in other C/C++ programs, so it's just a port really.
Just as a note, it is fairly annoying to both apply animations, save the global game transform, then before drawing convert each global transform into shader ready data by a set of matrix multiplications (read matrix palette skinning articles). But it does work, and it'll have to do until I find better solutions.
Need animations...
-Z
Labels:
webgl
Subscribe to:
Posts (Atom)







