Skip to content

Commit c529177

Browse files
committed
Update
1 parent 6d9049f commit c529177

File tree

6 files changed

+1110
-0
lines changed

6 files changed

+1110
-0
lines changed
File renamed without changes.
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# Expression 2 - Line-plane intersection tutorial
2+
3+
## Details
4+
5+
### Author
6+
7+
- Author: feha
8+
- Steam Profile: https://steamcommunity.com/profiles/76561197972236094
9+
10+
### Publication Info
11+
12+
- Title: Line-plane intersection tutorial
13+
- Date (dd-mm-yyyy): 26-03-2010
14+
- Source: https://web.archive.org/web/20110429165506/http://www.wiremod.com/forum/expression-2-discussion-help/19008-line-plane-intersection-tutorial.html
15+
- Source Accessed (dd-mm-yyyy): 28-09-2025
16+
17+
## Description
18+
19+
> [!Note]
20+
> Images are missing
21+
22+
### Introduction
23+
24+
Ok, I was told by some people that reading someones code is not their best way to learn something (even though its well-commented), and that they would like a tutorial instead. So here I respond to that request, and will explain line-plane intersection as well as I can. After reading this tutorial you are (hopefully) going to be able of finding the position your line intersects the plane.
25+
26+
First of all, I will assume you are idiots and explain what a line, a plane and intersection is, so that people who actually dont know it will still have a chance of understanding.
27+
28+
### A Line
29+
30+
This sounds like something simple to understand, and I would argue that it is. For simplicity I will explain this in 2 dimensions, as that means one less variable to work with (and the fact I hardly can paint, especially not 3d).
31+
32+
A line is something that goes from point a to b, just like a line you would draw on a piece of paper. This description does ofcource not assume that it is straight, but I will explain assuming it is, as non-straight lines is harder to use, and I actually got no clue how to do this with them.
33+
34+
If we look at the extrordinary well-made picture below, you will notice how I marked point a and b. The only extraordinary with any point in that graph is that they are a point in the line. The line is infact infinite, and not finite as you can see I drawn. We could however say that it got a direction, which we would in this case say is from A to B (hence the arrow), which could be explained as <ins>direction=B-A</ins>.
35+
<!-- &#108;&#105;&#110;&#101;&#46;.png -->
36+
37+
### A Plane
38+
39+
A plane might also sound easy, but it is infact much more advanced. As you might understand, a plane is something 3-dimensional, so excuse me if my drawings is hard to understand.
40+
41+
A plane is something you could describe by giving the corners, but as a plane in theory is infinite (just like the line), that is not what I am going to do here. A plane is better described by, just like the line, giving a position in the plane, but instead of the directions it stretch out in, we only need one direction. The normal.
42+
43+
As you can see in this awesome drawing, I painted a plane (altough as I said, it actualyl is infinite), inside a box to give a slight 3-dimensional feeling.
44+
As you see I defined a point on this plane, lets call it point (hi point). But as I said you also need something called a normal, this "normal" is a direction vector, which points away from the plane (aka it is perpendicular to the plane). As you see I labeled it N, as in normal (big suprise!). The normal could just aswell be inverted, and still define the same plane, but to define a plane you only need one normal.
45+
<!-- &#112;&#108;&#97;&#110;&#101;&#46;.png -->
46+
47+
### Intersection
48+
49+
Well this is simple to understand. It is chuck. This whole tutorial is to find where on the plane chuck stands, right? Nah it is not that simple, intersection means where one thing goes trough the other, or the point where they blend together (hence why chuck is called the intersect (computer blended into human)).
50+
51+
Lets draw yet another 2-dimensional picture to make sure you understand it. As you can see it is just 2 lines, which intersects eachothers. If you got 2 lines in 2 dimensions, they will intersect eachothers, unless they are parralell (same direction) or lies within eachothers (same direction, but any position on line a, does also exist in line b).
52+
<!-- &#105;&#110;&#116;&#101;&#114;&#115;&#101;&#99;&#116;&#105;&#111;&#110;&#46;.png -->
53+
54+
### Line-Plane Intersection
55+
56+
Ok, we are finally here, the thing this tutorial is actually supposed to be about. You should now know what a line, a plane and a intersection is. Lets combine this. As I explained in the last chapter, 2 lines in 2 dimensions will always intersect, except in 2 cases. The same goes for 1 line and 1 plane in 3 dimensions. The line will always intersect the plane (or other way around if you prefer that), unless the line is parralell to the plane, or the line lies within the plane.
57+
58+
Lets study some e2 code explaining this whole thing, and go trough it, step by step.
59+
60+
```plaintext
61+
#How does line-plane intersection work?
62+
PlanePoint = Holo:pos() #Get a point in the plane
63+
Normal = Holo:up() #Get the normal (a vector perpendicular to the surface) of the plane
64+
LinePoint1 = Origin #Get a point on the line
65+
LinePoint2 = Origin+OriginDirVec #Get a point on the line "after" point 1#
66+
X = (Normal:dot(PlanePoint-LinePoint1))/(Normal:dot(LinePoint2-LinePoint1)) #Not really sure how, but it returns how many times the distance from point 1 to point 2 you need to go from point 1 to reach the intersection
67+
Vec = LinePoint1+X*(LinePoint2-LinePoint1) #Get the intersections position using f(X) = LinePoint1+X*(LinePoint2-LinePoint1)
68+
```
69+
70+
#### Plane
71+
72+
As you see, we start with finding a position on the plane. As I explained earlier, any position will do. After that we get the normal of the plane. With this, we have defined our plane.
73+
74+
#### Line
75+
76+
But to find where the line intersects the plane, we also need to define the line. We do this by getting a point in the line, which for example could be a players `shootPos()`.
77+
As I explained earlier though, we need another point aswell, if it is a players vision, we can get the direction using `eye()`. This is then added to point1, and we got point2.
78+
79+
#### Math
80+
81+
We also need a function to get the position, lets call it `f(X)`. `f(X) = LinePoint1+X*(LinePoint2-LinePoint1)`. I will explain more about it later, but first, lets find out how we figure out `X`.
82+
83+
```plaintext
84+
X = Normal:dot(PlanePoint-LinePoint1)/Normal:dot(LinePoint2-LinePoint1)
85+
```
86+
87+
As you can see this thing uses the dot product (aka scalar product), and to be honest I do not entirely understand it. Azrael helped me in this case though (check page 2-3), so I can give you a better explanation.
88+
89+
What this does, is it calculates how many times the direction vector of the line `(point2-point1)` there is between point1 on the line, and the point where the line intersects the plane.
90+
91+
Now that we explained that, we can also explain `f(X)`, infact, it is required if we want to explain how you can know that `X = Normal:dot(PlanePoint-LinePoint1)/Normal:dot(LinePoint2-LinePoint1)` works.
92+
As I said, `X` is how many times you need to add the lines direction vector to point1 (sure the direction vector can be of any magnitude, but right now we speak of `LinePoint2-LinePoint1`)
93+
94+
```plaintext
95+
f(X) = LinePoint1+X*(LinePoint2-LinePoint1)
96+
```
97+
98+
In short, what this function does, is add the lines direction vector on `LinePoint1`, `X` amount of times, which returns the intersection point on the plane.
99+
100+
If we now start from `f(X)`, we could figure out how you know that `X = Normal:dot(PlanePoint-LinePoint1)/Normal:dot(LinePoint2-LinePoint1)`.
101+
102+
```plaintext
103+
f(X) = LinePoint1+ X * (LinePoint2-LinePoint1)
104+
f(X):dot(N) = PlanePoint:dot(N)
105+
```
106+
107+
Is what we know. If you wonder how we know that `f(X):dot(N) = PlanePoint:dot(N)` there is an explanation a little bit further down.
108+
If we now change `f(X)` to the actual function, we get:
109+
110+
```plaintext
111+
(LinePoint1 + X * (LinePoint2-LinePoint1)):dot(N) = PlanePoint:dot(N)
112+
```
113+
114+
Which can be taken out of its paranthesis which results in:
115+
116+
```plaintext
117+
LinePoint1:dot(N) + X * ((LinePoint2-LinePoint1):dot(N)) = PlanePoint:dot(N)
118+
```
119+
120+
With this, we could put `X` on its own side of the = mark (don't know the mathematical term in english).
121+
122+
```plaintext
123+
X = (PlanePoint:dot(N) - LinePoint1:dot(N)) / (LinePoint2-LinePoint1):dot(N)
124+
```
125+
126+
We could now make the numerator into a single dot-product again:
127+
128+
```plaintext
129+
X = (PlanePoint-LinePoint1):dot(N) / (LinePoint2-LinePoint1):dot(N)
130+
```
131+
132+
That is as you can see the same as I already stated, so we can say:
133+
Q.E.D.
134+
135+
As I said at start of the above segment, `f(X):dot(N) = PlanePoint:dot(N)`. Here is as promised an explanation on how we know that.
136+
137+
`A:dot(B) = 0` if A and B are perpendicular. The normal N is perpendicular to the plane, and for any two points Point1 and Point2 on the plane, Point1-Point2 is within the plane (remember top of this chapter?). As the direction vector we made is within the plane, we know that the normal, which is perpendicular to the plane, also is perpendicular to this direction vector.
138+
And as `A:dot(B) = 0` if A and B are perpendicular, we can say
139+
140+
```plaintext
141+
(r-a):dot(n)=0
142+
```
143+
144+
If we then pull them out of their paranthesis, we get two dot-products:
145+
146+
```plaintext
147+
r:dot(n)-a:dot(n)=0
148+
```
149+
150+
From here, we can add `a:dot(n)` on both sides, and we get:
151+
152+
```plaintext
153+
r:dot(n)=a:dot(n)
154+
```
155+
156+
Q.E.D.
157+
158+
<!--
159+
This might be easyer to understand using a picture, but as I suck at painting and I know one that is pretty good, I steal that.
160+
161+
&#112;&#108;&#97;&#110;&#101;&#45;&#108;&#105;&#110;&#101;&#45;&#105;&#110;&#116;&#101;&#114;&#1.gif -->
162+
163+
### Credits/Sources
164+
165+
Azrael - Thnx for explaining the dot product part a bit better for me!
166+
167+
[Intersection of a plane and a line](https://web.archive.org/web/20110429165506/http://local.wasp.uwa.edu.au/~pbourke/geometry/planeline/)
168+
This is where I read and understood the whole concept of line-plane intersection. It has one flaw tough, it uses a variable named P3, which it never explained what it was (well kind of did, but I did not realise that, as it left out saying it was "any" point on the plane, only that it was on the plane). However, with some reasoning I figured out that was a point on the plane. Also the site where I stole the line-plane intersection image.
169+
170+
I used 3 sites more, but all of them had a flaw, or used a way I felt was more advanced then I wanted to (matrixes or such), so they didnt teach me anything really and dont deserve credits 👿.
171+
172+
### Other
173+
174+
Hope this helped you, if I did or said something wrong, please inform me so, and if you think you can explain some part a bit further, I would be very GLaD.
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
@name HCS-Dummy
2+
@inputs
3+
@outputs Health
4+
@persist E:entity HoloID Scale DamageArray2:array
5+
@trigger
6+
7+
if (first() | duped()) {
8+
gSetStr("Damage","")
9+
signalSetGroup("HCS")
10+
runOnSignal("Damage",1,1)
11+
gShare(1)
12+
13+
Health = 100
14+
Scale = 25
15+
16+
holoCreate(1)
17+
holoScaleUnits(1,vec(Scale,Scale,Scale)*1.04)
18+
holoModel(1,"hqsphere")
19+
holoAlpha(1,100)
20+
holoParent(1,entity())
21+
22+
holoCreate(2)
23+
holoScaleUnits(2,vec(2,2,2))
24+
holoParent(2,entity())
25+
26+
E = holoEntity(1)
27+
HoloID = E:id()
28+
}
29+
30+
#Damage-taking
31+
if (signalClk("HCS","Damage",1)) {
32+
DamageArray = glonDecode(gGetStr("Damage"))
33+
34+
Mode = DamageArray[1,number]
35+
Time = DamageArray[2,number]
36+
37+
if (Mode == 1) {
38+
# getting the variables I need to use #
39+
Damage = DamageArray[3,string]:toNumber()
40+
Origin = DamageArray[4,vector]
41+
OriginDirVec = DamageArray[5,vector]:normalized()
42+
Range = DamageArray[6,number]
43+
ID = DamageArray[7,string]
44+
Flag = DamageArray[8,number]
45+
46+
Plane = E:pos() #Get the planes center
47+
P1 = Origin #Get a point on the line
48+
P2 = Origin+OriginDirVec #Get a point on the line "after" point 1
49+
Normal = -OriginDirVec #Get the normal (a vector pointin straight out of the surface) of the plane
50+
X = Normal:dot(Plane-P1)/Normal:dot(P2-P1) #Not really sure how, but it returns how many times the distance from point 1 to point 2 you need to go from point 1 to reach the intersection
51+
HitPos = P1+X*(P2-P1) #Get the intersections position
52+
53+
if(HitPos & X > 0) {
54+
A = Plane:distance(HitPos)
55+
C = Scale/2
56+
if (A < C) {
57+
B = sqrt(C^2-A^2)
58+
HitPos = HitPos+Normal:normalized()*B
59+
60+
Distance = HitPos:distance(Origin)
61+
if (Distance < Range) {
62+
HitArray = glonDecode(gGetStr(ID+"Hit"))
63+
64+
if (Flag | !HitArray[1,vector]) {
65+
HitArray:pushVector(HitPos)
66+
gSetStr(ID+"Hit",glonEncode(HitArray))
67+
68+
Hit = 1
69+
}
70+
}
71+
}
72+
}
73+
} elseif (Mode == 2) {
74+
ExplosionDamage = DamageArray[3,string]:toNumber()
75+
Radius = DamageArray[4,number]
76+
Falloff = DamageArray[5,number]
77+
Origin = DamageArray[6,vector]
78+
ID = DamageArray[7,string]
79+
Flag = DamageArray[8,number]
80+
81+
Target = E:pos()
82+
Distance = Origin:distance(Target)
83+
if (Distance <= Radius) {
84+
Hit = 1
85+
86+
Damage = ExplosionDamage/(Distance*Falloff+1)
87+
88+
HitArray = glonDecode(gGetStr(ID+"Hit"))
89+
90+
if (Flag | !HitArray[1,vector]) {
91+
HitArray:pushVector(Origin)
92+
gSetStr(ID+"Hit",glonEncode(HitArray))
93+
}
94+
}
95+
} elseif (Mode == 3) {
96+
Damage = DamageArray[3,string]:toNumber()
97+
ExplosionDamage = DamageArray[4,number]
98+
Radius = DamageArray[5,number]
99+
Falloff = DamageArray[6,number]
100+
Origin = DamageArray[7,vector]
101+
OriginDirVec = DamageArray[8,vector]:normalized()
102+
Range = DamageArray[9,number]
103+
ID = DamageArray[10,string]
104+
Flag = DamageArray[11,number]
105+
106+
Plane = E:pos() #Get the planes center
107+
P1 = Origin #Get a point on the line
108+
P2 = Origin+OriginDirVec #Get a point on the line "after" point 1
109+
Normal = -OriginDirVec #Get the normal (a vector pointin straight out of the surface) of the plane
110+
X = Normal:dot(Plane-P1)/Normal:dot(P2-P1) #Not really sure how, but it returns how many times the distance from point 1 to point 2 you need to go from point 1 to reach the intersection
111+
HitPos = P1+X*(P2-P1) #Get the intersections position
112+
113+
if(HitPos & X > 0) {
114+
A = Plane:distance(HitPos)
115+
C = Scale/2
116+
if (A < C) {
117+
B = sqrt(C^2-A^2)
118+
HitPos = HitPos+Normal:normalized()*B
119+
120+
Distance = HitPos:distance(Origin)
121+
if (Distance < Range) {
122+
HitArray = glonDecode(gGetStr(ID+"Hit"))
123+
124+
if (Flag | !HitArray[1,vector]) {
125+
HitArray:pushVector(HitPos)
126+
gSetStr(ID+"Hit",glonEncode(HitArray))
127+
128+
Hit = 1
129+
130+
DamageArray2 = array(2,curtime(),ExplosionDamage,Radius,Falloff,HitPos,ID,0)
131+
if (A <= Radius) {
132+
Hit = 1
133+
134+
Damage+= ExplosionDamage/(Distance*Falloff+1)
135+
}
136+
timer("explosion",0)
137+
}
138+
}
139+
}
140+
}
141+
}
142+
} elseif (clk("explosion")) {
143+
gSetStr("Damage",glonEncode(DamageArray2))
144+
signalSetGroup("HCS")
145+
signalSend("Damage",1)
146+
}
147+
148+
if (Hit) {
149+
Health-=Damage
150+
}
151+
152+
if (Health <= 0) {
153+
holoColor(1,vec(255,0,0))
154+
}

0 commit comments

Comments
 (0)