Jump to content

intercept a direction


bfx

Recommended Posts

Hello

trying some VOP i do something like that

vector3 D (a direction)

vector3 S (a source position)

P and Eye in object space

if dot(normalize(cross(S-P, S-Eye)),normalize(D)) = 0 then i'm happy.

but,

if D=1,0,0 or D =-1,0,0 i may be happy the same way... and i don't

How can i know if ,Eye P, is intercepting D issue from S ?

what is the way to solve that :blink:

thanks

fran

Link to comment
Share on other sites

if dot(normalize(cross(S-P, S-Eye)),normalize(D)) = 0 then i'm happy.

but,

if D=1,0,0 or D =-1,0,0 i may be happy the same way... and i don't

Hi Francois,

I'm having a little trouble following what it is you're trying to do here; so here are a few questions... maybe they'll trigger something.

You don't say which context you're writing this for. But P and Eye (if they are the globals by those names) only exist in shading contexts, so I'm guessing it's one of those, yes?

You mention that P and Eye are in "object" space, so I take it you forcibly put them there and they are not in their natural state, which would be "world" space. And that you've made sure that D and S are in the same space as P and Eye (which you claim to be "object" space).

So if P, Eye, S, and D are indeed in the same space, then your expression is comparing the normal to the plane {P,S,Eye}, to the arbitrary vector D, and checking whether they are perpendicular to each other. Is this correct?

You seem to imply that you would expect to get identical results with D={1,0,0}, or D={-1,0,0}, and you aren't. But if the setup is as I describe above, then there's no reason why D={1,0,0} *should* give the same result as D={-1,0,0} -- i.e: more likely than not, they each point to different sides of the {P,S,Eye} plane.

How can i know if ,Eye P, is intercepting D issue from S  ?

Why is D suddenly "issuing" from S. You mean that these two are meant to describe a line going through S and S+D ?

Or is D really a ray as in S+D*t, and we're looking for the t where we intersect something?

Are we looking for an intersection between two lines? ( [Eye,P] and [s,S+D] ), or a ray->plane intersection?

Sorry... no answers. :(

Link to comment
Share on other sites

Hello

I'm in shading context, fog.

I try to have a ray of fog coming from an arbitrary point.

To know if i add fog or not i need to know if the ray of fog is passing between my eyes and the point i'm looking. Seems to be correct untils now ?

To know that i use the normal of the the plan created by "my eye, the point i'm looking, the point from where the ray is coming". If the resulting normal is perpendicular to the ray of fog, the ray is include in the plane, "my eye, the point i'm looking, the ray source" and then the ray come between my eye and the point i'm looking. But this true for a ray of fog coming from a point in one direction and the reverse direction <--.-->

This is where i'm stuck !

I use the globale Eye and P and use two parameterVOP set to 3 float(vector).

vector3 S, D

-- change the space to object for eye and P

oeye=wo_space(eye)

op=wo_space(P)

-- change space to be in S space

seye=S-oeye

sp=S-op

-- the normal to eye, p, source

u=cross(seye,sp)

-- check if ray is in the plane

arccosine(dot(normalize(u),normalise(D)))=0 true or false

with more tolerance to the boolean and it's two nice ray of fog coming from the source point, ougch!, but, i want this ray to be alone, single, ALONE....sorry

Is that more clear ? Is that the way to achieve this foggy problems ?

thanks

francois

Link to comment
Share on other sites

Hey Francois,

(sorry; I got crazy-busy there for a while) <_<

Right. I *think* I know what's going on now...

We basically want to know if the ray D (originating from {0,0,0} since everything is expressed in S-space), intersects the line [seye,sp]. And you're testing this by finding whether D is on the plane [s,sp,seye]. But of course, there's a whole 180-degrees worth of D's that will pass the test and be wrong (ie. not be directed toward [seye,sp]), not just -D.

So this is not a very good test ;)

OK. First thing is to straighten out your space a little.

-- change space to be in S space

seye=S-oeye

sp=S-op

For oeye and op to be in S-space, we need to make S the origin, so that should be changed to:

-- change space to be in S space
seye=oeye-S;
sp=op-S;

...and the rest of the calculations assume that D is given in S-space.

Now we need a way to tell in which direction does the line [sp,seye] lie relative to S, so we may discard the "back-facing" hemisphere. One way that comes to mind would be to get the perpendicular vector component of the projection of A = S-seye = -seye onto B = sp-seye. This would give you the "normal" at S, perpendicular to the line [sp,seye] (and obviously on the plane [s,sp,seye]).

Then we would simply discard any D whose dot product with this normal was <0.

The projection of vector A onto B is given by AprojB = B A.B / B.B.And the perpendicular vector component is just A-AprojB. So putting it all together, we have:

vector DN = normalize(D);

// Check if D is on plane

if(abs(dot(normalize(u),DN))<TOLERANCE) {

Link to comment
Share on other sites

Hello Mario

This work like a charme, for the first test i've made.

Can you tell me if i'm wrong on this

Vector sI is A in the definition ?

Vector sN is the perpendicular vector in S to the projection of A to B ?

What is the difference between the A to B projection and the plan [s,sp,seye], and, the difference between the cross product use previously and the sN, the s origin... ?

Is it simple to separate in your formula to compute sN, the projection of A to B, and, the perpendicular computation to that projection ?

I try to find a way to understand what happen.:unsure:

Anyway, thank you very much.

francois

Link to comment
Share on other sites

Hi Francois,

Well; I'm glad it's working for you :) , but I'm curious if you got a chance to try the ray->line intersection reference that I mentioned. I think it would be a much more robust solution for you. If you're having trouble following it, let me know, and I can convert it to VEX for you using your setup.

OK; now to your questions...

Vector sI is A in the definition ?

No; sI is B in the definition -- i.e: "the vector we're projecting onto".

To compare them better, here they are next to each other:

B A.B / B.B

sI * dot(-seye,sI) / dot(sI,sI)

So A = -seye, and B = sI = sp-seye

Vector sN is the perpendicular vector in S to the projection of A to B ?

Yes. You can visualize it as pointing from the head of the vector -seye (or 'A') to the head of it's own projection onto the vector sp-seye (or 'B', or 'sI'). So, naturally, it's perpendicular to its own projection, which is the same as saying that it is perpendicular to the line [sp,seye], which is what we're after.

What is the difference between the A to B projection and the plan [s,sp,seye], and, the difference between the cross product use previously and the sN, the s origin... ?

The difference between the projection and the plane is simply that the projection is really just B with a length equal to the scalar component of A along the B direction. And the plane is, well, a plane (described by three points as opposed to a normal, which is how the result of you cross-product describes the plane).

And the difference between the normal-to-the-plane (computed by the cross product), and what I very loosely called a "normal-at-S" (which isn't really a normal to anything, it's just a vector), is that sN is perpendicular to both the line [sp,seye] and the normal-to-the-plane.

Is it simple to separate in your formula to compute sN, the projection of A to B, and, the perpendicular computation to that projection ?

They are already separate: one is an operation on the other:

projection = B A.B / B.B

perpendicular = A - B A.B / B.B

Unless you're asking whether the perpendicular can be somehow expressed without reference to the projection?

Cheers!

Link to comment
Share on other sites

Hello Mario,

Unfortunatly it don't seems to be a bullet proof way to do (attached JPG). The cut ray are from the "OneWayOnly" bolean. Curently i didn't know why. I'm still at school with my trigo and your help ;)

I've got maybe another way to do, similar, maybe faster, in using only basic function.

It's not totaly clear for me right know but, lets go :

_once it is known the plane (Eye, Point, Source) include the direction line D

_I only need a 2D projection (X,Y) of the plan to know wich part of the line i'm looking at (it's a line)

_I can use two equation :

Every point I(Xi,Yi) include in a line coming from S to D verify

I = S+h(D-S)

I and If is include in (Eye,P) then

I = LP+(1-L)Eye, with 0<L<1

_ so

I = S+h(D-S) = LP + (1-L)Eye

In a 2D space give 2 equations

h(Xd - Xs) + L(Xe - Xp) = Xe -Xs

h(Yd - Ys) + L(Ye - Yp) = Ye - Ys

that i can resolve this way

L = [ ((Xe-Xs)*(Ye-Ys)) / ((Xd-Xs)*(Yd-Yp)) ] / [ ((Xe-Xp)*((Ye-Yp)) / ((Xd-Xs)*(Yd-Ys)) ]

and then

if 0 < L < 1 it 's done,

That will be a little mess to translate this in VEX ...

I need to have a look also in the documentation you send to me.

Definitly when i start this shader i don't think i will go in so much complication. Fortunatly i like to learn some Math trick that i can use to animate or ....

It seems unbelivable to me that king of function didn't exist in one form or another in VEX. This is a very basic cone-light-fog-like shader, i want to do :huh:

thanks

fran

post-9-1080902279.jpg

Link to comment
Share on other sites

Hey Francois,

I won't have time to look at it today, but in the meantime, I had another look at my earlier post and found a couple of mistakes:

1. The perpendicular is backwards.

The part that reads:
 vector sN = normalize( -seye - ( sI * dot(-seye,sI) / dot(sI,sI) ) );

Should actually read:
 vector sN = normalize( ( sI * dot(-seye,sI) / dot(sI,sI) )  + seye );

...because we want the reverse of the "usual" result in this case....

2. The comparison should be if(dot(sN,DN)>0) {..., instead of what I wrote originally, which was if(dot(sN,DN)>=0) {....

See? there were a couple of "brain farts" in there! :)

However; I suspect that neither of these things will solve your problem, which I think has to do with the fact that, as I mentioned originally, this test is not restricted to the segment Eye->P -- it rather tests against the infinite line that passes through those two points.

In any case; now that I finally see the result you're after, I can help you out. But I won't be able to do it today, sorry :(

later,

-- mario.

Link to comment
Share on other sites

Hey Francois,

I finally sat down with pen and paper infront of me -- nothing like "good old low-tech"! :)

So, after turning it around a few times, it started becoming clear that any solution based on a pure ray->line intersection (which is what you started to derive above) will have one major drawback: it will be very hard to antialias properly. And any shader that is not antialiased is, for all practical purposes, useless - so that's a deal breaker in my books. You start getting into the "tolerance" hack, which is fine, except it's angular (not linear). Which means you then have to deal with two cosine distributions - one from the tolerance, and another from the perspective projection from the line [Eye,P] to the point S - eek! ... get out your aspirin now; you'll need it! :)

What we need is a solution in the form of a distance to the closest point of approach between the two lines. And if it can be expressed in a nice orthogonal space, then antialiasing is trivial - life is good again :)

After redrawing the geometry a few times, I found that to get the result in this form, we need to reverse everything from the way you had it - we trace from Eye instead of S. It goes like this:

1. Construct an orthonormal basis at S where the XY plane includes D - actually, the unit-length D is the X-axis in this space. Y is the "Up" direction, and Z is the plane normal.

2. Find the point of intersection between the incident ray I, and the XY plane of our space; let's call it Phit. We transform Phit to our space.

3. Examine the x-coordinates of Phit. If negative, then we're on the wrong side of the ray, and we discard it. If we're on the positive-X side, then we examine its Y-component, which is the perpendicular distance to the ray (i.e: distance to the X-axis == Y-component of Phit == perpendicular distance to ray).

Setting up the geometry this way has several advantages over the ray->line intersect method; namely:

1. Antialiasing becomes a simple matter of filtering a pulse function centered at Y=0, of size = line_width. The filter width can be adjusted to blur the lines, etc, etc.

2. Our lines can have arbitrary (and accurate) widths. And the width can be manipulated along its length, etc.

3. Since we've gone to the trouble of constructing a space for it, there's nothing stopping us from restating the surface derivatives at P in terms of that space. Meaning that we can, with very little overhead, derive a local s, t, dPds, dPdv... the works! We can basically construct an RiCurve out of each one of these puppies - meaning we can now shade them any way we like!... a GoodThing? :)

4. The same approach can be extended to other primitives, not just lines (which are of limited use, really).

OK. Get out your hard hat, here come the gory details: ;)

Constructing the basis

We have Sx = normalize(D). Then we cross it with the camera-space {0,0,1} to get an Sy that faces camera. There is a possibility that Sx is already pointing in that direction (in which case the cross product is undefined), so I choose cameraX = {1,0,0} for that special case. Then we cross Sx and Sy to get Sz, which is our plane normal. Finally, we'll need the distance to the plane along Sz to do our intersection, which is given by dot(Sz,S). All together we have:

// Construct basis at S
vector Sx = normalize(D);
vector Sy = dot(Sx,{0,0,1})&gt;.995 ? cross(Sx,{1,0,0}) : cross(Sx,{0,0,1});
vector Sz = cross(Sx,Sy);

// Distance to plane along Sz
vector Sd = dot(S,Sz);

Ray-Plane Intersection

Using the "point-normal" equation for a plane, n.p = D, (with p=point in plane, n=plane normal, D=distance to plane along n), and substituting p with the parametric equation of a ray, p(t) = o + d*t (with o=ray origin, d=ray direction, and t is the parameter "time" -- which is kind'a where you were headed in your last post), we get:

n.p = D

n.p(t) = D

n.(o+d*t) = D

(n.o) + (n.d)*t = D

-> (Sz.{0,0,0}) + (Sz.normalize(I))*t = Sd

-> (Sz.normalize(I))*t = Sd

-> t = Sd / dot(Sz,normalize(I));

-> Phit = normalize(I)*t;

This is the derivation given in that reference I mentioned before. Pretty neat, huh? -- vector algebra is your friend! :)

You should also note that: if dot(Sz,normalize(I))==0, then there's no intersection, and if t is negative than the hit happened "behind us", so we can ignore it.

Calculating the line weight

Once we have the point of intersection, we put it in our space, PH = Phit-S, and check its x-component, PHx = Sx.PH/|Sx| = Sx.PH. If it's negative, we stop, because we're behind the begining of the line {since x-component-of-line >= 0}. If we're on the positive side, then we calculate the y-component, which is (as with x), PHy = Sy.PH/|Sy| = Sy.PH. This last is how far we are (as a signed distance) from the axis of the line. All that's left to do is to check it against the user-provided "line thickness" and antialias it. As a bonus, you can calculate the local s, t, dPds, and dPdt, for that bit of "extra fancy shading" :)

Here's the whole thing as the function "FogLaser":

//-------------------------------------------------------------------------

// Constructs a basis where the XY plane contains the given direction Sv,

// and where the system faces the current space's origin, which it assumes

// to be at {0,0,0}. The distance to the plane along its normal is returned

// as Sd.

//-------------------------------------------------------------------------

void basisPlanePV(vector S, Sv; export vector Sx,Sy,Sz; export float Sd) {

lazer.zip

Link to comment
Share on other sites

Very cool, Mario! This should definitely go into the odforce codex!

Just in case someone tries to copy/paste the code verbatim, note that Sd should be a float instead of a vector. They'll find out right away anyhow. :)

Reading your post made me realize how much math I'd forgotten already. :( I might as well point some obvious facts for those like me. :) Another way to look at it is to interpret the points as vectors from the origin. Then n.p is simply the scalar projection of the vector p onto the vector n. So to spell it out completely, Sd above is the distance to the plane along its normal from the origin.

This ray-plane intersection math then has this neat geometric interpretation. Re-interpret Phit to be a vector from the origin. Then if you take the scalar projection of Phit onto the normal of the plane, you get the distance from the origin to the plane. Same equations, just slightly different interpretation:

n.(o+d*t) = D

But we're dealing with rays from the origin so this is actually:

n.(d*t) = D

Rearrange:

t * (n.d) = D

But n and d are normalized vectors:

t * cos(theta) = D

Where theta is the angle between n and d. t is the distance from the origin to Phit along d. So everything boils back down to right-angle triangles. :)

Rehash of the same thing again:

Scalar projection of Phit onto n = Scalar projection of S onto n

Phit.n = S.n

t * d.n = S.n

t = S.n / d.n

Ok, I thnk I've spent enough time re-saying exactly what you said last post. :)

Link to comment
Share on other sites

Just in case someone tries to copy/paste the code verbatim, note that Sd should be a float instead of a vector.

Thanks for pointing that out, Edward. That's what happens when you post code without even trying to compile it! :o:P

I edited the original post and fixed that as well as a few other things. For example, I found that the optimizer was chewing up the multiple return statements in the original FogLaser() function, and spewing some random garbage here and there... very strange. I changed all functions to single returns and all's well again... hmmm. Oh well.

I also fixed a few things with the VOP version in the hip file, which I'm attaching to this post.

Rehash of the same thing again:

Scalar projection of Phit onto n = Scalar projection of S onto n

Phit.n = S.n

t * d.n = S.n

t = S.n / d.n

:D Yes!

Hahaaaaa! it's good to see someone digs this thing!

I just loved it when I first saw it -- it's so simple and symetrical... very cool.

Then again, all of vector algebra has that effect on me... :rolleyes:

Cheers!

laser2.zip

Link to comment
Share on other sites

Hello,

Thank you Mario, you give more than just help here !

I will take the week you propose but to explore the Vex code.

Obviously this should be in the odforce codex.

thanks

francois

Link to comment
Share on other sites

  • 2 weeks later...

Hey Francois,

WOW! Very nice! :D

Yep. Nothing like some tweakable visuals to see how it all works.

Just a teeny-tiny observation: what you've marked as "laser thickness", actually stands for "signed distance to the laser's central axis (or Sx)"... a tiny detail, really. But again; good job; really nice to see it all like this!

I'm kind'a swamped at the mo, but as soon as I get a little time, I'll put together an "all bells and whistles" package to send in. Actually; if you don't mind, I'll include your otl along with any other usage/examples/demo things I come up with. Would that be OK with you?

Cheers!

Link to comment
Share on other sites

Hello Mario

I have put some changes :

A grid materialize the Phit coordinates on the XY plan.

Sd (distance plan from origin along normal plan) is displayed along a Z world axis

I have change the label "laser Thickness" to "Sy distance from laser Sx" ...

Handles are available to manipulate D, P or S

I'll put together an "all bells and whistles" package to send in.

That will be a super package :)

No problems

cheers

francois

lasertest_GEO1.zip

Link to comment
Share on other sites

  • 3 weeks later...

<update>

OK, the stuff is in. Check in codex->tools->vex.

And don't let the bit about "vex functions" scare you off -- they've all been wrapped in inoffensive, easy-to-use VOPs. :)

These were adapted from my own stuff here, but there was some hand editing involved, so please let me know if something doesn't work (I may have accidentally cut out one thing too many).

Cheers!

Link to comment
Share on other sites

Hello Mario

One regret the FogLaser don't add the Cf and Af... global in the output. It's necessary to add this by ourself.

It is really great, you give a lot of help,

thank you, Odforce site is very usefull. :)

fran

Link to comment
Share on other sites

One regret the FogLaser don't add the Cf and Af... global in the output.

Ooops. Yup; you're right... sorry about that :(

But that's just in the demo hip. The actual VOP just puts out weight, which is not tied to color, or opacity, or anything (and that's as it should be, since you could use the info for anything you like).

Cheers!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...