Both, but I was specifically referring to the stuff in this thread. I like the chunky aesthetic :cool:
Printable View
Both, but I was specifically referring to the stuff in this thread. I like the chunky aesthetic :cool:
Oh yea. I love MS for those kind of reasons. People shit on MS because they are the big bad corporation but honestly, they treat their devs so damn well. With pretty exhaustive documentation, amazing tools (VS, debugger, PIX), good cross-platform APIs (DX, XAudio, XNA, .Net) and even options for indies to develop on their proprietary console (via XNA), its is really nice developing for their platforms (especially compared to stuff like Wii or PS3 development).
Trying to reinvent the bicycle (as my Google skills fail) and getting sick of it :( - perhaps some of you have experience with it:
Basically, i need to construct a quaternion + handedness to describe the normal and tangent space per vertex. The quaternion MUST preserve the normal (so, the constructed tangent space will pretty much always differ from the surface one - plus the real / surface tangent space is usually sewed anyway).
Probably it will be enough to use the tangent space of the largest relevant triangle, but if anyone knows some fast / dirty way to average it - that would be nice too (probably too expensive tho, as i must recalculate all of it at initialization time).
I'm stuck :( ...
PS. quaternion is the wanted end result, but i do not expect there to be some optimized version for getting it directly - so, first and foremost i need to construct a 3x3 orthogonal rotation matrix for the tangent space (ie, if "quaternion" bothers you [they mostly confuse the shit out of me at least] - ignore i said it. Matrix to quaternion conversion is fairly simple anyway ... not sure how do i get the handedness out of it tho :/).
edit:bullshit
edit: Ok, let's simplify the problem a little more - how do i orthogonalize the matrix preserving the normal?
edit: At least this works (does it?) on paper, but pretty much guaranteed to be the most inefficient way of doing it:
N=normal (normalized), T=tangent (unnormalized), B=bitangent(unnormalized). Using [X] to mean normalize(X):
T' = [ B x N ] // get the tangent on normal's plane according to bitangent
B' = [ N x T ] // get the bitangent on normal's plane according to tangent
L = (B' + T') * 0.5 // half-way diagonal
T'' = [ [ L ] + [ T' - L ] ] // adjusted (basically rotating L 45 degrees towards T' on normal's plane) normalized tangent on normal's plane
B'' = N x T'' // get the accompanying normalized bitangent
... this is just horrible x_x (3 cross products & 5 invsqrt's etc ... just to get the orthogonalized rotation matrix)
edit: Actually .. new plan: calculate tangent only then apply Gram-Schmidt orthogonalization and get the bitangent via cross product.
continuing tomorrow.
For me other than level design work on Planet Digger, I've been adding in requested features for Bipolar Game. The first request was for customizable controls which I got working yesterday wasn't overly difficult really.
However when I attempted to add in the option of using controllers, that was a different story entirely. Due to the game being done in openGL / GLUT that's been a pain in the ass. It's quite odd as with SDL in comparison all it needs is a few lines of code and controllers work perfectly fine, but in GLUT it's been quite difficult. And there's no tutorials or help on it online from what I've been able to find. Very odd.
http://a8.sphotos.ak.fbcdn.net/hphot...95578203_n.jpg
The games perfectly fine without it, but would have been nice to have in. The other feature to add in is level completion times next to the level names on the level select screen. That in comparison should be a piece of cake.
uugh, ugly ugly. I always hated that part. I'm normally good at maths, but every time I work with tangets and crap I always need to re-look up tutorials. It never sticks.
Tho whenever I was calculating the tangent-space vectors, I'd always take into account the vertex tex-coords to get the proper orientation, which you don't seem to be doing? Maybe you can incorporate that somehow into your math to make it easier.
Also, I would normally pre-compute this stuff somehow if performance was an issue and store it in vertices (remember you only really need the x and y coord since you can reconstruct z in shader - you knw it will always point towards the camera since otherwise you wouldnt be rendering it!)
Hope this is somewhat useful...
I assume you mean FreeGLUT here (using GLUT today would border insanity - GLUT development was completely abandoned over 12 years ago). Unfortunately, the last time i used anything like that was over 5 years ago - so, can not really say anything helpful :/
That math is meant to reorthogonalize the rotation matrix i get by combining vertex (not surface - ie, weighted average of the relevant triangles), tangent and bitangent vectors (calculated in a previous step [plenty of tuts for that, so did not bother to write that down ... yet]).
The primary issue is actually storage space - so, most of the world geometry is generated to begin with. Going with the initialization-time re-calculation approach for now.
Vertex normal (and the other ones too) does not always point out of the screen ... you forgot smoothing ;)
Also, one quaternion (8B of data, ie. 4 * normalized unsigned short) is enough the define all three vectors. + 1 bit worth of data for handedness somewhere.
Got a bit distracted yesterday doing other stuff (and failing completely ARGH!) - giving it another go now. Will report back if i get anything i amhappyok with.
Here goes:
vec3: P, Pa, Pb - triangle vertexes CCW: P->Pa->Pb
vec2: Pt, Pta, Ptb - triangle UV coords
Pass1-per triangle:
vec3: TN = (Pa - P) x (Pb - P) // triangle normal (unnormalized).
add TN to each vertex normal (Nv) // TN is essentially normalized-triangle-normal * triangle-size * 2.
float: TA = TN * TN // ( triangle size * 2 ) ^ 2
update vertexes reference to biggest triangle (using TA) and triangle reference count to skip the triangle at Pass3
Pass2-per vertex:
vec3: Nv = normalize(Nv)
Pass3-per triangle (skip triangle if none of the vertexes have it as the biggest one):
vec3: Ea = Pa - P, Eb = Pb - P // calc edge vectors
vec2: Eta = Pta - Pt, Etb = Ptb - Pt // calc UV vectors for the edges (NB! i do not actually intend to use the x axis of thous)
float: D = Eta.y * Etb.x - Eta.x * Etb.y // calc UV coordinate triangle determinant (ie. UV-winding)
if(D > 0) it is CW, but we want CCW: Etb = -Etb, and remember that we use left-hand coordinate system
vec3: T = Ea * Etb.y - Eb * Eta.y // calc unnormalized tangent for the whole triangle. (UV axes are perpendicular, so: take Etb.y worth of Ea and adjust it by removing Eta.y worth of Eb [at least it sounds like pretty standard base change - can anyone confirm?] ... yes, it makes my head hurt and i am not 100% sure i got it right)
per-vertex (only the vertexes that are not done yet):
vec3: Tv = T - Nv * (T * Nv) // adjust the tangent to be perpendicular with the normal (ie. subdract the amount it is not perpendicular [T * Nv] in normal's direction).
Tv = normalize(Tv) // normalize tangent
vec3: Bv = Nv x Tv // calc bitangent. no need to normalize as both Nv & Tv are normalized
vec4: Q = cast the matrix (Nv, Tv, Bv) to quaternion, encode the coordinate system handedness into it afterwards (or just do not use upside down texture mapping to begin with - we are not in DirectX world! get your UV mapping right g*damn-it! would cut out the conditional and the determinant crap)
-----------------------
PS. understanding the simplifications made is strongly advised prior to usage!
PS2. did i fuck up something (0 testing, just used paper and pencil)? the coordinate system base change sounds a bit iffy, but the few test numbers i tried did give the correct results at least.
To be fair, that's pretty much exactly what I looked like when reading it. :p
I think he just wanted to, humorously, say - i don't get it (instead of: whatever / right, moving on etc).
^^^ This.
I imagine our threads would be 1/3 the size and half as interesting if we didn't have the memedrop commentary, then the commentary on the commentary and the commentary on the commentary on the commentary... :)
I know this is one of your older posts but one thing that's been missing is why you want to do this. A lot of what you're discussing depends on the context - i.e. whether you're optimising for modelling, shading or geometry culling. I appreciate you're sounding out ideas but knowing the background would help a lot.
Well ... why not unravel my thought process a bit here.
Starting point: I need to know texture tangent space per pixel - it simply is an absolute necessity for per pixel lighting with normal maps (Quite a few other non-lighting techniques also require it, but i do not intend to use any of thous currently).
-------------------------------------
So, the question becomes: Where do i get it? There are 4 options i am aware of:
Option 1: Pixel shader - using derivatives.
* Considerable per-pixel overhead for every frame.
* Assuming depth only pre-pass (which i absolutely require anyway) - the overhead is quite stable and predictable (witch is nice for real time stuff).
* No need to precompute the vectors for tangent space.
* The least amount of artifacts (ie. matches with what it should be in the 2x2 screen area).
* There might be support problems on older cards (Derivatives are required for mipmap selection and therefore one might expect them to be free as the rasterizer calculates them anyway - BUT, until relatively recently there apparently was no way for rasterizer to forward that information to fragment program and [primarily on ATIgarbageGPUs] the derivatives always just return 0 [Yes, the spec does not allow it and all of them did that anyway - for example all the noise functions on all the top-of-the-top gaming GPUs still always return 0]. Some of the cards worked around the problem by tackling on extra code to calculate the derivatives separately - which, last i tried that on an older gpu, was VERY expensive).
In short, if you have static data and you can precompute the tangent vectors - you should do it. I can precompute - so, this option is off the table.
Option 2: Geometry shader - you have the whole primitive accessible.
* No need to precompute the vectors for tangent space.
* No per-pixel overhead.
* Per primitive overhead (Much higher than getting the information from derivatives in fragment program. However, assuming relatively healthy fragment/primitive ratio - might be faster).
* Very unstable overhead and unpredictability (can bite you badly in worst case scenarios - ie, precisely at the time you least want it).
* Can badly affect stupid/older GPUs as it messes with the flow. Should not have much effect in itself as the program is strictly one-primitive-in => one-primitive-out ... but can not guarantee that the GPU has a special case for it (at least Nvidia has told that they have a special case [ie. rules you must follow to get the fast path] for quad [ie. point-sprite-like behavior] and i assume they have one for triangle too, but i have not seen any of them confirming that).
* Insufficient adjacency information - ie. expect bad quality with curved non-trivial surfaces in comparison to any of the other options.
This option is just riddled with problems, while it does have some merit - i pass.
Option 3: Vertex shader - all sorts of projections.
* No need to precompute the vectors for tangent space.
* Usually quite fast to calculate (tri-planar, planar, cylindrical - pretty much covers all i probably ever need)
* Can only be used when ... well ... possible :p.
I will use it whenever i can, obviously. So, continuing to fish for solutions for the cases where this one is not an option.
Option 4: Precomputed tangent space is given in vertex attributes.
* Well, data comes from external sources and hence we do not have to do anything (Except unpacking if needed + the standard transformation you would have to do anyway regardless of where the tangent info comes from).
Here we go then.
-------------------------------------
Now the question of tangent space data transfer (ie. option-4 continuation).
Two vectors are needed for it: Tangent and Bitangent (U and V respectively, or S and T whichever notation one prefers). That would be 2*3*4=24 bytes of extra data per vertex. My, option-3, vertex data fits nicely into 32B:
* Position, normal, texcoords (or additional misc params), two-materials for array textures (when needed) + interpolant, additional misc per pixel data.
* It fits to cache line very nicely.
* No need to have the position data in a separate buffer as the overhead is not big (in depth-only pass context) - anything that makes my life easier is welcomed. Separate buffers would be annoying to deal with (filling, separate formats, extra buffers to manage).
* 2 byes unused (Could use it for something, but no idea so far)
24 extra bytes for the option-4 stuff is very bad. It would require a strong separation of option-3 and option-4 stuff - which is bad for depth fill pass (ie. considerably more complexity for me to deal with - and my time is finite). Best solution would be to squeeze both options into one vertex format. So, what can one do with 2 extra bytes:
* Reconstruct bitangent from tangent and normal (+ handedness bit somewhere): 3 values ... that does not even get close to fitting into 2 bytes - even when using some more reasonable precision.
* Well, i already am storing the normal - add one component and i have enough for a quaternion which is enough to describe all 3 vectors with sufficient precision (+ the handedness bit somewhere of course). How much space do i need for one component ... 2 ... how much i have unused ... 2 ... YAY!
Having only one vertex format for all major occluders (world geometry primarily) and otherwise (my intent is to use quite a lot of geometry generation - uniform format is a bliss there) is a MAJOR implementation complexity simplification and just too good to pass (it probably is good for performance too, but it is not my primary concern - premature optimization is, well, premature).
-------------------------------------
And, finally, the question of calculating the data ... which i (probably) solved in the previous posts (With simplifications as precomputing it offline is probably not an option due of the generative nature of the world - should be fast enough for initialization time precomputing. + probably amortized considerably by post transform optimization step which, although has a linear complexity, has a hefty constant part).
-------------------------------------
Did some coding yesterday and got the renderer to work (well, there are still pits of duct tape hanging here-and-there - you know the drill):
* fills the vertex/index buffers with constructed data (joined per material into one patch regardless of what generators it did come out of) on a sector by sector basis when the need arises (currently, my duct-tape approach is => just do all of them).
* draw commands are automatically grouped per material per pass.
Tests "map" (well, it does come from map data structures - just that the data there is just random test-shit and none of it resembles anything one would call a map) worked nicely :)
Funnily enough, i actually do not need tangent space stuff YET - i just needed to decide my vertex formats (+ by extension: everything related to map markup) and for that i needed to know how much of a problem calculating thous are (and can i afford to squeeze it into one format).
My implementation specific terms:
* Sector: aka. localized drawing group. For example: a room with different textures used for different surfaces (+ non-static entities which are absent atm) all either drawn or not (exceptions excepted for stuff determined to be not visible).
* Material: state object that has all the GL state it needs (state object actually can describe much more than any material itself needs - ie, it is not only for materials, but for any state grouping you need) + lookup to determine the least wasteful order in relation to any other state.
* Pass: aka. order independent drawing group. Renderer is allowed to reorder any draw command within a pass to prevent state trashing - however, it must preserve order when changing it does not help (ie: stable sort !).
* Every pass is part of a queue, which itself is constructed out of order (For example - ui passes are done before the main scene although they actually end up after the main scene passes.)
We never used GFWL in our games.
True, not everyone uses GFWL, but it is terrible, and it is from Microsoft.
And thus, Microsoft is terrible too.
And so is America.
Fuck off Koki.
What? I missed you. :(
And that's what happens when you get involved in the off topic arguments that occur here often.