Basically the problem is I need to render stuff at long range. It's not even Z fighting since, the transformation makes parts of convex objects like my sun, vanish at distance. Simply breaking off the projection matrix and doing things with two vector/matrix multiplications instead of one, improves things quite a bit but doesn't solve the problem completely. I think because of the range there is some numerical instability involved.
I have yet to try my non-matrix idea yet. Sure, with prefect math it shouldn't make a difference how it's done, however computers have limited precision. Changing only the exponent of Z leaves the rest of the precision bits untouched so I figure that might be a way to avoid some instability. Also I found in OpenGL there is an option to use the actual Z coordinates unchanged, but it's an NVidia option only
I had read about reversing the near and far planes but looking at the number distribution my guess it would kill the closer in stuff, given the fact I'm trying to render a planet with it's distance sun. I don't really need a lot of distribution at range. Beyond the sun, moon and possibly large asteroids, everything else such as stars will be a dot on the screen and being off even a million kilometers isn't going to mean much for a distant star. I want the starts to actually be separate objects in their correct position, and not just a fake star field so you can select them with a heads up display.
If all else fails I guess I'll have to use stenciling and do multi-pass rendering with different near and far clipping planes. Fortunately with celestial objects it's easy enough to sort them.
Edit:
Well it works, at least for my small red dwarf sized sun at out to 10 million kilometers with 1.0 unit == 1.0 meters. Theoretically it's doing something similar to the projection matrix but the numerical stability seems to be a lot better for some reason. With the projection matrix things were breaking up at about 16000 km. I have yet to see how well it works standing on planets with the shading on (although it works OK with wire frame) but I guess I'll find out. Here's the HLSL vertex code if anyone is interested:
// f4P = [tan(HeightViewAng/2) * AspectRatio, tan(HeightViewAng/2), PowerOfTwoZDiv, NearPlane]
// AspectRatio = Viewing aspect ratio width over height
// PowerOfTwoZDiv = Tested with ldexp(1,96) which should be OK up to a galaxy
// NearPlane = Near clipping plane
VSSunOutput VSMain( VSSunInput IN )
{
VSSunOutput OUT;
OUT.position = mul( mGV, float4( IN.position, 1 ) );
OUT.position.w = OUT.position.z;
OUT.position.z -= f4P.w;
OUT.position.xyz = OUT.position.xyz / f4P.xyz;
OUT.position.z *= OUT.position.w;
// For procedrual shading
OUT.meshID = IN.meshID;
OUT.world = float4(IN.world, 1.0f);
return OUT;
}