pwnaz0r
11-20-2007, 11:31 PM
Creating your own Move Mouse via Bezier Spline
Ok, well understanding the spline path algorithms can sometimes be confusing, so if you ever get a little overwhelmed during this tutorial, please take a deep breath and read that little part over again. I will try to make this as easy to understand as possible with visuals.
In the Beginning...
Alright, so just starting out with Splines? Ready to make your own custom move mouse? Well you have come to the right place. I will be explaining an algorythm for the Cubic Bezier Spline in order to produce a human like curve for the Move Mouse.
The Bezier Spline is also known as NURBS (Non - Uniform Rational Bezier Spline). It uses an equation using what is known as Control Points, or the points that regulate the mouse path. You can have any number of control points, but I suggest that you make that number four. The first Control Point is always the starting position of you mouse, and the last control point is always the end of your line.
The History of the Bezier Spine
I try not to just copy things to show that I understand them fully. However, I feel it necessary for you to understand why NURBS were made.
Development of NURBS (Non Uniform Rational Basis, or Bézier Spline) began in the 1950s by engineers who were in need of a mathematically precise representation of freeform surfaces like those used for car bodies and ship hulls, which could be exactly reproduced whenever technically needed. Prior representations of this kind of surface only existed as a single physical model created by a designer.
The pioneers of this development were Pierre Bézier who worked as an engineer at Renault, and Paul de Casteljau who worked at Citroën, both in France. Bézier worked nearly parallel to de Casteljau, neither knowing about the work of the other. But because Bézier published the results of his work, the average computer graphics user today recognizes splines — which are represented with control points lying off the curve itself — as Bézier splines, while de Casteljau’s name is only known and used for the algorithms he developed to evaluate parametric surfaces. In the 1960s it became clear that non-uniform, rational B-splines are a generalization of Bézier splines, which can be regarded as uniform, non-rational B-splines.
At first NURBS were only used in the proprietary CAD packages of car companies. Later they became part of standard computer graphics packages.
Real-time, interactive rendering of NURBS curves and surfaces were first made available on Silicon Graphics workstations in 1989. In 1993, the first interactive NURBS modeller for PCs, called NöRBS, was developed by CAS Berlin, a small startup company cooperating with the Technical University of Berlin. Today most professional computer graphics applications available for desktop use offer NURBS technology, which is most often realized by integrating a NURBS engine from a specialized company.
.
Understanding Control Points
Control Points are simply points that the spline will follow. For instance, if you put two control points right in the middle of the line of a Mouse Path, you will get a straight line.
http://img156.imageshack.us/img156/152/onmiddleqf0.png.
As you move the Control Points away from the middle of the line, your path will be more spline.
http://img410.imageshack.us/img410/646/offset1tm8.png.
You can always put the control points behind outside the two start and end points, which will result in a cut-back, (like curving the mouse backwards and forwards like so), but I find it easier to just start at a higher theta, which I will explain later in the tutorial.
http://img441.imageshack.us/img441/5135/offset2ac6.png
There are not many things you can do with control points. You need to have a slight understanding of the coordinate system used in SCAR to use them.
The main reason that people hate using Control Points is because YOU HAVE TO FIGURE OUT SOME WAY TO PLACE THEM. Its actually very simple. Simply google "Control Point Detection" or something to that extent and find a procedure made for it, or make one your own!
Understanding Theta
Theta is, to be put simply, the regulator of your spline. When you are creating points along a line, you have to have step correct? Theta is your "step" kind of. Here is the best way to explain it: Theta is an extended value, from 0.0 to 1.0. It defines where your point is on the line. For instance, in a normal NURBS, the startpoints theta value is 0.0, the endpoints theta value 1.0, and the midpoints value is 0.5. Look at the picture below for more clarification.
http://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Bezier_3_big.gif/240px-Bezier_3_big.gif
Since all Bezier splines follow this pattern, we find our step formula for this. If you wish to make a wind mouse like Benland, I will show you how to do that later. However, for now we are looking for a smooth, standard function. In the following SCAR tags, we will be finding what is called the theta increase. When making a spline path, you will have to have to increase theta as you go along the line correct? Well here is how to find it.
theta_Inc:= 1.0 div Distance; // really the equation is 1.0 - 0.0 div Distance
the reason the equation is really 1.0 - 0.0 because you do the total theta value of them divided by the distance you are traveling, but that doesn't concern you :).
So basically, as theta increases, the "current point" along the line is moved closer to the endpoint.
Creating the Spline Path Function
Ok, so lets start out with a core function. I have the basic variables commented and declared here.
function Spline(ex, ey: integer; CTRLP1, CTRLP2: TPoint): TPointArray;
var
theta, theta_Inc: extended; //must be extended;
sx, sy: integer; //start x and y
Dist: integer; //distance between startpoint and endpoint.
begin
GetMousePos(sx, sy); //Get your start point.
Dist:= Distance(sx, sy, ex, ey);
end;
CtrlP1 and 2 are the two center control points. End X and End Y are going to be your last control point and Start X and Start Y are going to be your start point.
now, you are going to want to put your ctrlpoints all into one array, like so.
function Spline(ex, ey: integer; CTRLP1, CTRLP2: TPoint): TPointArray;
var
theta, theta_Inc: extended; sx, sy: integer;
Dist: integer;
CtrlPoints: Array [1..4] of TPoint; //Added, Control Points array.
begin
GetMousePos(sx, sy);
Dist:= Distance(sx, sy, ex, ey);
CtrlPoints[1]:= Point(sx, sy);
CtrlPoints[2]:= CtrlP1;
CtrlPoints[3]:= CtrlP2;
CtrlPoints[4]:= Point(ex, ey);
end;
now, you set theta's value at 0.0, and use a repeat statement. I will use a little line that will make sure I don't go over 1.0 theta, think about it for a second and you will understand.
function Spline(ex, ey: integer; CTRLP1, CTRLP2: TPoint): TPointArray;
var
theta, theta_Inc: extended; sx, sy: integer;
Dist: integer;
CtrlPoints: Array [1..4] of TPoint; //Added, Control Points array.
begin
GetMousePos(sx, sy);
Dist:= Distance(sx, sy, ex, ey);
CtrlPoints[1]:= Point(sx, sy);
CtrlPoints[2]:= CtrlP1;
CtrlPoints[3]:= CtrlP2;
CtrlPoints[4]:= Point(ex, ey);
theta_inc:= 1.0 div Dist;
theta:= 0.0;
repeat
theta_Inc:= MinE(1.0 - theta, theta_Inc); //This is the line to stop theta over 1.0
theta:= theta + theta_Inc;
until(Theta >= 1.0);
result[High(result)]:= Point(ex, ey); //This is a failsafe. High = Length - 1.
end;
now, here is where you will need to equation for finding a point on a Quadratic Spline using theta. Since you have come this far, I will supply you with this equation :D.
function PointOnCubicBezier(cp: TPointArray; t, Curve: Extended): TPoint;
var
ax, ay, bx, by, cx, cy,
tSquared, tCubed: Extended;
i: integer;
begin
cx := Curve * (cp[1].x - cp[0].x);
bx := Curve * (cp[2].x - cp[1].x) - cx;
ax := cp[3].x - cp[0].x - cx - bx;
cy := Curve * (cp[1].y - cp[0].y);
by := Curve * (cp[2].y - cp[1].y) - cy;
ay := cp[3].y - cp[0].y - cy - by;
tSquared := t * t;
tCubed := tSquared * t;
result.x := Round((ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x);
result.y := Round((ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y);
end;
function Spline(ex, ey: integer; CTRLP1, CTRLP2: TPoint): TPointArray;
var
theta, theta_Inc: extended; sx, sy: integer;
Dist: integer;
CtrlPoints: Array [1..4] of TPoint; //Added, Control Points array.
begin
GetMousePos(sx, sy);
Dist:= Distance(sx, sy, ex, ey);
CtrlPoints[1]:= Point(sx, sy);
CtrlPoints[2]:= CtrlP1;
CtrlPoints[3]:= CtrlP2;
CtrlPoints[4]:= Point(ex, ey);
theta_inc:= 1.0 div Dist;
theta:= 0.0;
repeat
theta_Inc:= MinE(1.0 - theta, theta_Inc); //This is the line to stop theta over 1.0
theta:= theta + theta_Inc;
until(Theta >= 1.0);
result[High(result)]:= Point(ex, ey); //This is a failsafe. High = Length - 1.
end;
Now, we will just add the point-adding into this function and wrap it up :D
function PointOnCubicBezier(cp: TPointArray; t: Extended): TPoint;
var
ax, ay, bx, by, cx, cy,
tSquared, tCubed, Curve: Extended;
i: integer;
begin
Curve:= 3.0; //average curve.
cx := Curve * (cp[1].x - cp[0].x);
bx := Curve * (cp[2].x - cp[1].x) - cx;
ax := cp[3].x - cp[0].x - cx - bx;
cy := Curve * (cp[1].y - cp[0].y);
by := Curve * (cp[2].y - cp[1].y) - cy;
ay := cp[3].y - cp[0].y - cy - by;
tSquared := t * t;
tCubed := tSquared * t;
result.x := Round((ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x);
result.y := Round((ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y);
end;
function Spline(ex, ey: integer; CTRLP1, CTRLP2: TPoint): TPointArray;
var
theta, theta_Inc: extended; sx, sy: integer;
Dist: integer;
CtrlPoints: Array [1..4] of TPoint; //Added, Control Points array.
begin
GetMousePos(sx, sy);
Dist:= Distance(sx, sy, ex, ey);
CtrlPoints[1]:= Point(sx, sy);
CtrlPoints[2]:= CtrlP1;
CtrlPoints[3]:= CtrlP2;
CtrlPoints[4]:= Point(ex, ey);
theta_inc:= 1.0 div Dist;
theta:= 0.0;
repeat
theta_Inc:= MinE(1.0 - theta, theta_Inc); //This is the line to stop theta over 1.0
theta:= theta + theta_Inc;
SetLength(Result,Length(Result)+1);
Result[High(result)]:= PointOnCubicBezier(ctrlpoints, theta);
until(Theta >= 1.0);
result[High(result)]:= Point(ex, ey); //This is a failsafe. High = Length - 1.
end;
now, to execute this spline path, just make a function like so. This will simply move your mouse path.
procedure MoveTheMouse(x, y, rx, ry: integer);
var
P: TPointArray;
I: integer;
begin
x:= x+random(rx);
y:= y+random(ry);
P:= Spline(x, y, {CTRLP1}, {CTRLP2});
for i:= 0 to High(P) do
begin
MoveMouse(P[i].x, P[i].y);
wait(randomrange(4, 8));
end;
end;
.
Adding Wind
Adding wind is simple. You can do a calculated version or a failsafe version. We will not discuss the calculated version, since you could make some math mistakes and it would take longer, but the failsafe, where you do almost no math and you cannot fail :D. Lets get our magic line again :D:
theta_Inc:= MinE(1.0 - theta, theta_Inc);
Simply add a wind variable into your parameters and replace the magic line with this code.
theta_inc:= theta_inc + wind;
theta_Inc:= MinE(1.0 - theta, theta_Inc);
You can play around with these variables to have a little fun :D.
Some Theta Tricks
ok, now there are some things you can do with theta that are actually pretty cool. This is what I was talking about when I said starting at a higher theta. Now, remember that line where we said
theta:= 0.0
well, you can change it to this
theta:= 0.3;
Let me explain what this will do, since it is hard to make a picture for it. Look at the first picture with the green spline path. Image the first blue control point marked 0.3 theta. Now, if you start this repeating equation with theta at 0.3, it will start the curve there on the line and it will "skip over" theta 0.0-0.2. You will still end up at end X and end Y, but you will start with a different curve other than this very strict line. You could also try something like
case random(4) of
0: theta := 0.2;
1: theta:= 0.122;
//etc..
For more information:
Wikipedia (http://en.wikipedia.org/wiki/B%C3%A9zier_curve)
Ok, well understanding the spline path algorithms can sometimes be confusing, so if you ever get a little overwhelmed during this tutorial, please take a deep breath and read that little part over again. I will try to make this as easy to understand as possible with visuals.
In the Beginning...
Alright, so just starting out with Splines? Ready to make your own custom move mouse? Well you have come to the right place. I will be explaining an algorythm for the Cubic Bezier Spline in order to produce a human like curve for the Move Mouse.
The Bezier Spline is also known as NURBS (Non - Uniform Rational Bezier Spline). It uses an equation using what is known as Control Points, or the points that regulate the mouse path. You can have any number of control points, but I suggest that you make that number four. The first Control Point is always the starting position of you mouse, and the last control point is always the end of your line.
The History of the Bezier Spine
I try not to just copy things to show that I understand them fully. However, I feel it necessary for you to understand why NURBS were made.
Development of NURBS (Non Uniform Rational Basis, or Bézier Spline) began in the 1950s by engineers who were in need of a mathematically precise representation of freeform surfaces like those used for car bodies and ship hulls, which could be exactly reproduced whenever technically needed. Prior representations of this kind of surface only existed as a single physical model created by a designer.
The pioneers of this development were Pierre Bézier who worked as an engineer at Renault, and Paul de Casteljau who worked at Citroën, both in France. Bézier worked nearly parallel to de Casteljau, neither knowing about the work of the other. But because Bézier published the results of his work, the average computer graphics user today recognizes splines — which are represented with control points lying off the curve itself — as Bézier splines, while de Casteljau’s name is only known and used for the algorithms he developed to evaluate parametric surfaces. In the 1960s it became clear that non-uniform, rational B-splines are a generalization of Bézier splines, which can be regarded as uniform, non-rational B-splines.
At first NURBS were only used in the proprietary CAD packages of car companies. Later they became part of standard computer graphics packages.
Real-time, interactive rendering of NURBS curves and surfaces were first made available on Silicon Graphics workstations in 1989. In 1993, the first interactive NURBS modeller for PCs, called NöRBS, was developed by CAS Berlin, a small startup company cooperating with the Technical University of Berlin. Today most professional computer graphics applications available for desktop use offer NURBS technology, which is most often realized by integrating a NURBS engine from a specialized company.
.
Understanding Control Points
Control Points are simply points that the spline will follow. For instance, if you put two control points right in the middle of the line of a Mouse Path, you will get a straight line.
http://img156.imageshack.us/img156/152/onmiddleqf0.png.
As you move the Control Points away from the middle of the line, your path will be more spline.
http://img410.imageshack.us/img410/646/offset1tm8.png.
You can always put the control points behind outside the two start and end points, which will result in a cut-back, (like curving the mouse backwards and forwards like so), but I find it easier to just start at a higher theta, which I will explain later in the tutorial.
http://img441.imageshack.us/img441/5135/offset2ac6.png
There are not many things you can do with control points. You need to have a slight understanding of the coordinate system used in SCAR to use them.
The main reason that people hate using Control Points is because YOU HAVE TO FIGURE OUT SOME WAY TO PLACE THEM. Its actually very simple. Simply google "Control Point Detection" or something to that extent and find a procedure made for it, or make one your own!
Understanding Theta
Theta is, to be put simply, the regulator of your spline. When you are creating points along a line, you have to have step correct? Theta is your "step" kind of. Here is the best way to explain it: Theta is an extended value, from 0.0 to 1.0. It defines where your point is on the line. For instance, in a normal NURBS, the startpoints theta value is 0.0, the endpoints theta value 1.0, and the midpoints value is 0.5. Look at the picture below for more clarification.
http://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Bezier_3_big.gif/240px-Bezier_3_big.gif
Since all Bezier splines follow this pattern, we find our step formula for this. If you wish to make a wind mouse like Benland, I will show you how to do that later. However, for now we are looking for a smooth, standard function. In the following SCAR tags, we will be finding what is called the theta increase. When making a spline path, you will have to have to increase theta as you go along the line correct? Well here is how to find it.
theta_Inc:= 1.0 div Distance; // really the equation is 1.0 - 0.0 div Distance
the reason the equation is really 1.0 - 0.0 because you do the total theta value of them divided by the distance you are traveling, but that doesn't concern you :).
So basically, as theta increases, the "current point" along the line is moved closer to the endpoint.
Creating the Spline Path Function
Ok, so lets start out with a core function. I have the basic variables commented and declared here.
function Spline(ex, ey: integer; CTRLP1, CTRLP2: TPoint): TPointArray;
var
theta, theta_Inc: extended; //must be extended;
sx, sy: integer; //start x and y
Dist: integer; //distance between startpoint and endpoint.
begin
GetMousePos(sx, sy); //Get your start point.
Dist:= Distance(sx, sy, ex, ey);
end;
CtrlP1 and 2 are the two center control points. End X and End Y are going to be your last control point and Start X and Start Y are going to be your start point.
now, you are going to want to put your ctrlpoints all into one array, like so.
function Spline(ex, ey: integer; CTRLP1, CTRLP2: TPoint): TPointArray;
var
theta, theta_Inc: extended; sx, sy: integer;
Dist: integer;
CtrlPoints: Array [1..4] of TPoint; //Added, Control Points array.
begin
GetMousePos(sx, sy);
Dist:= Distance(sx, sy, ex, ey);
CtrlPoints[1]:= Point(sx, sy);
CtrlPoints[2]:= CtrlP1;
CtrlPoints[3]:= CtrlP2;
CtrlPoints[4]:= Point(ex, ey);
end;
now, you set theta's value at 0.0, and use a repeat statement. I will use a little line that will make sure I don't go over 1.0 theta, think about it for a second and you will understand.
function Spline(ex, ey: integer; CTRLP1, CTRLP2: TPoint): TPointArray;
var
theta, theta_Inc: extended; sx, sy: integer;
Dist: integer;
CtrlPoints: Array [1..4] of TPoint; //Added, Control Points array.
begin
GetMousePos(sx, sy);
Dist:= Distance(sx, sy, ex, ey);
CtrlPoints[1]:= Point(sx, sy);
CtrlPoints[2]:= CtrlP1;
CtrlPoints[3]:= CtrlP2;
CtrlPoints[4]:= Point(ex, ey);
theta_inc:= 1.0 div Dist;
theta:= 0.0;
repeat
theta_Inc:= MinE(1.0 - theta, theta_Inc); //This is the line to stop theta over 1.0
theta:= theta + theta_Inc;
until(Theta >= 1.0);
result[High(result)]:= Point(ex, ey); //This is a failsafe. High = Length - 1.
end;
now, here is where you will need to equation for finding a point on a Quadratic Spline using theta. Since you have come this far, I will supply you with this equation :D.
function PointOnCubicBezier(cp: TPointArray; t, Curve: Extended): TPoint;
var
ax, ay, bx, by, cx, cy,
tSquared, tCubed: Extended;
i: integer;
begin
cx := Curve * (cp[1].x - cp[0].x);
bx := Curve * (cp[2].x - cp[1].x) - cx;
ax := cp[3].x - cp[0].x - cx - bx;
cy := Curve * (cp[1].y - cp[0].y);
by := Curve * (cp[2].y - cp[1].y) - cy;
ay := cp[3].y - cp[0].y - cy - by;
tSquared := t * t;
tCubed := tSquared * t;
result.x := Round((ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x);
result.y := Round((ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y);
end;
function Spline(ex, ey: integer; CTRLP1, CTRLP2: TPoint): TPointArray;
var
theta, theta_Inc: extended; sx, sy: integer;
Dist: integer;
CtrlPoints: Array [1..4] of TPoint; //Added, Control Points array.
begin
GetMousePos(sx, sy);
Dist:= Distance(sx, sy, ex, ey);
CtrlPoints[1]:= Point(sx, sy);
CtrlPoints[2]:= CtrlP1;
CtrlPoints[3]:= CtrlP2;
CtrlPoints[4]:= Point(ex, ey);
theta_inc:= 1.0 div Dist;
theta:= 0.0;
repeat
theta_Inc:= MinE(1.0 - theta, theta_Inc); //This is the line to stop theta over 1.0
theta:= theta + theta_Inc;
until(Theta >= 1.0);
result[High(result)]:= Point(ex, ey); //This is a failsafe. High = Length - 1.
end;
Now, we will just add the point-adding into this function and wrap it up :D
function PointOnCubicBezier(cp: TPointArray; t: Extended): TPoint;
var
ax, ay, bx, by, cx, cy,
tSquared, tCubed, Curve: Extended;
i: integer;
begin
Curve:= 3.0; //average curve.
cx := Curve * (cp[1].x - cp[0].x);
bx := Curve * (cp[2].x - cp[1].x) - cx;
ax := cp[3].x - cp[0].x - cx - bx;
cy := Curve * (cp[1].y - cp[0].y);
by := Curve * (cp[2].y - cp[1].y) - cy;
ay := cp[3].y - cp[0].y - cy - by;
tSquared := t * t;
tCubed := tSquared * t;
result.x := Round((ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x);
result.y := Round((ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y);
end;
function Spline(ex, ey: integer; CTRLP1, CTRLP2: TPoint): TPointArray;
var
theta, theta_Inc: extended; sx, sy: integer;
Dist: integer;
CtrlPoints: Array [1..4] of TPoint; //Added, Control Points array.
begin
GetMousePos(sx, sy);
Dist:= Distance(sx, sy, ex, ey);
CtrlPoints[1]:= Point(sx, sy);
CtrlPoints[2]:= CtrlP1;
CtrlPoints[3]:= CtrlP2;
CtrlPoints[4]:= Point(ex, ey);
theta_inc:= 1.0 div Dist;
theta:= 0.0;
repeat
theta_Inc:= MinE(1.0 - theta, theta_Inc); //This is the line to stop theta over 1.0
theta:= theta + theta_Inc;
SetLength(Result,Length(Result)+1);
Result[High(result)]:= PointOnCubicBezier(ctrlpoints, theta);
until(Theta >= 1.0);
result[High(result)]:= Point(ex, ey); //This is a failsafe. High = Length - 1.
end;
now, to execute this spline path, just make a function like so. This will simply move your mouse path.
procedure MoveTheMouse(x, y, rx, ry: integer);
var
P: TPointArray;
I: integer;
begin
x:= x+random(rx);
y:= y+random(ry);
P:= Spline(x, y, {CTRLP1}, {CTRLP2});
for i:= 0 to High(P) do
begin
MoveMouse(P[i].x, P[i].y);
wait(randomrange(4, 8));
end;
end;
.
Adding Wind
Adding wind is simple. You can do a calculated version or a failsafe version. We will not discuss the calculated version, since you could make some math mistakes and it would take longer, but the failsafe, where you do almost no math and you cannot fail :D. Lets get our magic line again :D:
theta_Inc:= MinE(1.0 - theta, theta_Inc);
Simply add a wind variable into your parameters and replace the magic line with this code.
theta_inc:= theta_inc + wind;
theta_Inc:= MinE(1.0 - theta, theta_Inc);
You can play around with these variables to have a little fun :D.
Some Theta Tricks
ok, now there are some things you can do with theta that are actually pretty cool. This is what I was talking about when I said starting at a higher theta. Now, remember that line where we said
theta:= 0.0
well, you can change it to this
theta:= 0.3;
Let me explain what this will do, since it is hard to make a picture for it. Look at the first picture with the green spline path. Image the first blue control point marked 0.3 theta. Now, if you start this repeating equation with theta at 0.3, it will start the curve there on the line and it will "skip over" theta 0.0-0.2. You will still end up at end X and end Y, but you will start with a different curve other than this very strict line. You could also try something like
case random(4) of
0: theta := 0.2;
1: theta:= 0.122;
//etc..
For more information:
Wikipedia (http://en.wikipedia.org/wiki/B%C3%A9zier_curve)