Sign in to follow this  
dopplex

Vector length - measured in screen-space coords?

Recommended Posts

dopplex    164
Hi all, I'm generating a vector in a vertex shader I'm writing, and I'm having trouble figuring out how to calculate the length of that vector in screen-coordinates from the WorldViewProjection transformed vector components. Can anyone give me a quick pointer here? I had thought that the x,y components after the projection transform would directly correspond to screen space, but it's seeming that that isn't the case. Thanks, Dan

Share this post


Link to post
Share on other sites
dopplex    164
Here's the shader code. I apologize for the extreme lack of prettiness. The important bit is down near the end - it's the one thing that's actually commented!

It *almost* works as written - it's giving results that seem close to accurate - but it's almost as if another minor transformation is applied between the vertex shader and arriving at the screen.

(The AddScale multiplication is reversed in the pixel shader - it's in there to force pixels to rasterize that might not otherwise, so that I can antialias properly.)


struct VS_INPUT {
float4 Position : POSITION0;
float4 Normal : NORMAL0;
float4 Tri1Normal : NORMAL1;
float4 Tri2Normal : NORMAL2;
float4 V1Normal : NORMAL3;
float4 V2Normal : NORMAL4;
float2 Tex : TEXCOORD3;
float4 V1Position : TEXCOORD4;
float4 V2Position : TEXCOORD5;
float4 Flags : TEXCOORD6;
};

struct VS_OUTPUT {

float4 Position : POSITION0;
float2 Tex : TEXCOORD0;
float4 Normal : TEXCOORD1;
float4 ViewDirection : TEXCOORD2;
float2 ScaleFactor : TEXCOORD3;
float4 Debug : TEXCOORD4;
};



VS_OUTPUT Transform2(VS_INPUT Input) {


VS_OUTPUT Output;
float4x4 WorldViewProject = mul(mul(World, View), Project);
float4 ObjectPosition = mul(Input.Position, World);
float4 ViewVec = EyePosition - ObjectPosition;
float4 ViewVec2 = mul(mul(EyePosition - ObjectPosition, View), Project);

float4 OutputPosition = mul(Input.Position, WorldViewProject);
float2 ScaleFactor = float2(0.0f, 0.0f);
float4 Debug = (float4)0.0f;

Output.Normal = mul(Input.Normal, World);
Output.ViewDirection = EyePosition - ObjectPosition;
Output.Tex = Input.Tex;
if (Input.Flags.w >= 0)
{
float4 Tri1Normal = normalize(mul(Input.Tri1Normal, World));
float4 Tri2Normal = normalize(mul(Input.Tri2Normal, World));
float Tri1DotV = dot(Tri1Normal, ViewVec);
float Tri2DotV = dot(Tri2Normal, ViewVec);

float Det = Tri1DotV * Tri2DotV;
OutputPosition = mul(Input.V1Position, WorldViewProject);


float Det2 = dot(Tri1Normal, Tri2Normal);
if (Det2 < 0.9f) Det = -1.0f;
if (Det < 0 )
{
float4 ExtrudeVec = float4(0.0f, 0.0f, 0.0f, 0.0f);

if (Input.Flags.x==0)
{
ExtrudeVec = mul(normalize(Input.V1Normal),WorldViewProject);
OutputPosition = mul(Input.V1Position, WorldViewProject);
}
if (Input.Flags.x>0)
{
ExtrudeVec = mul(normalize(Input.V2Normal),WorldViewProject);
OutputPosition = mul(Input.V2Position, WorldViewProject);
}
ExtrudeVec = gLineThickness*ExtrudeVec;

//if (ExtrudeVec.x * ScreenSize.x < 1)
ScaleFactor.y = (ExtrudeVec.y * ScreenSize.y); //how long is our extrusion in pixels
ScaleFactor.x = (ExtrudeVec.x * ScreenSize.x);
//ExtrudeVec.xy = ExtrudeVec.xy;
OutputPosition += AddScale * ExtrudeVec;
}


}
Output.Debug = Debug;
Output.ScaleFactor = ScaleFactor;

Output.Position = OutputPosition;




return Output;
}

Share this post


Link to post
Share on other sites
dopplex    164
The big reason I think I'm missing something here:

If I set the output of my "special case" vertices to always be postion.y = 1.0f, this is *not* always corresponding to the same point on my screen. Depending on how I move my camera around, the vertical position in pixels shifts somewhat.

This doesn't make much sense to me, as I thought that I was already past the point where my camera and viewport could affect the rendering - since the view and projection matrices had already been applied.

Share this post


Link to post
Share on other sites
Is there any particular reason why you are extruding the vertex in screen space as opposed to world space or view space?

Also in this line:

//if (ExtrudeVec.x * ScreenSize.x < 1)

What is the value of the vector ScreenSize? If it is in pixels, then I don't think that test is going to pass very often, unless ExtrudeVec is very small.

Share this post


Link to post
Share on other sites
dopplex    164
Quote:
Original post by Chaotic_Attractor
Is there any particular reason why you are extruding the vertex in screen space as opposed to world space or view space?

Also in this line:

//if (ExtrudeVec.x * ScreenSize.x < 1)

What is the value of the vector ScreenSize? If it is in pixels, then I don't think that test is going to pass very often, unless ExtrudeVec is very small.



I don't suppose there's a reason for extruding in screen space as opposed to world or view and then transforming - but would it make a difference? I was probably just thinking in terms of screen space at that point in time... Although - it's probably because I wanted to measure the screenspace length. If I had added the extrusion to the base position, and then transformed, I'd have had to then transform the base position and subtract it from the transformed position - which seems more complicated than just transforming the extrusion vector to screen space and then measuring it before adding it to the base position.

Er.. Well that test wasn't really passing. I think I had commented it out with the intention of deleting it after I was *sure* it was worthless. The purpose of that line, though, was to identify and manipulate geometry output that was going to be thinner than a pixel, because it seemed like the very thin lines weren't rasterizing at all. ScreenSize was size of screen in pixels - float2(800.0f,600.0f) in this case.

Share this post


Link to post
Share on other sites
MJP    19790
It's like this:

When you first project your coordinate, your coordinate is now in clip-space. When you then divide the coordinate by homogeneous w, you get normalized device coordinates. These are in the range [-1,1] where y = 1 is the top, y = -1 is the bottom, and so forth. If you multiply by 0.5 and add 0.5, then multiply by the size of your viewport, you get screen coordinates (optionally you can flip y so that y = 0 is the top of the screen).

Now you seem to be doing some weird stuff to calculate your extrusion length...you have to be very careful with post-projection coordinates and directions. Usually they can't be directly used in calculations, since they're not in linear space anymore. In most cases, you have to alter your vertices or do any other calculations you have to do them in object, view, or world space first. For example, I think this is really what you want if you're trying to find the length of your extrusion in screen space...


float4 extrusionPointOS = IN.V1Position + normalize(IN.V1Normal) * gLineThickness;
float4 extrusionPointCS = mul(extrusionPointOS, WorldViewProj);
OutputPosition = mul(Input.V1Position, WorldViewProject);

...

float2 extrusionVecSS = extrusionPointOS.xy/extrusionPointOS.w - OutputPosition .xy / OutputPosition.w;
extrusionVecSS = (extrusionVecSS * 0.5 + 0.5) * ScreenSize;
ScaleFactor.xy = float2(extrusionVecSS.x * extrusionVecSS.x, extrusionVecSS.y * extrusionVecSS.y);

OutputPosition = extrusionPointCS;

Share this post


Link to post
Share on other sites
dopplex    164
Ugh, somehow I knew that homogeneous coordinates were likely to blame. I still don't entirely have the hang of them - working on it, though.

Seeing if I understand the code you posted...

pseudocode:
Calculate location of extrusion point in object space
Transform it to clip space
Transform base point to clip space too.

then...

Subtract the clip space coordinates of the original point (divided by their w) from the object space coordinates of the extruded point (divided by their w)

I'm not sure I get it. Firstly, I don't understand exactly what we're doing - geometry wise - by dividing by w. Secondly, wouldn't this be mixing object space and clip space? from what you said, I see that the intent of the line is to put the extrusion vector into normalized device coordinates - I just don't understand why this gets us there?

The last line I think I understand - though I'm not entirely sure why we're squaring the components.

Thanks!

Share this post


Link to post
Share on other sites
MJP    19790
Nah what I did (or at least tried to show) was

-in object space, make the normal length == to gLineThickness
-determine the location of the extruded point in object space by adding lengthened normal to the position of the vertex you've "selected"
-find clip-space and screen-space positions of the vertex and the point to which the normal extrudes
-find the distance in screen space, which is the number of pixels between the vertex and the to extrusion point

Share this post


Link to post
Share on other sites
dopplex    164
Thanks! I think I mostly understand now.

The only line that is confusing is the following:

float2 extrusionVecSS = extrusionPointOS.xy/extrusionPointOS.w - OutputPosition .xy / OutputPosition.w;


At this point, extrustionPointOS in in Object Space, whereas OutputPosition is in Clip Space. It would seem to make more sense to me to subtract from the Clip Space extrusion point. (Of course, if that's the case, that's likely what you meant and the OS was just a typo)


(BTW, thanks for all the answers, MJP - somehow you always seem to be the one who ends up answering my stupid questions! I owe you a drink sometime if I ever run into you, I think)

Share this post


Link to post
Share on other sites
MJP    19790
Quote:
Original post by dopplex
Thanks! I think I mostly understand now.

The only line that is confusing is the following:

float2 extrusionVecSS = extrusionPointOS.xy/extrusionPointOS.w - OutputPosition .xy / OutputPosition.w;


At this point, extrustionPointOS in in Object Space, whereas OutputPosition is in Clip Space. It would seem to make more sense to me to subtract from the Clip Space extrusion point. (Of course, if that's the case, that's likely what you meant and the OS was just a typo)


(BTW, thanks for all the answers, MJP - somehow you always seem to be the one who ends up answering my stupid questions! I owe you a drink sometime if I ever run into you, I think)


Bah, that was a typo and I just didn't see it (even when you pointed it out the first time!). It should be "extrusionPointCS", sorry about that.

And I like Bass Ale, for your future reference. [smile]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this