Eliminating off-of-ball roll in Trackball controls (with code/fix) - three.js

Is the intent of the TrackballControl to have a "border" outside the trackball that induces roll? I personally dislike it. It is a bit discontinuous, and does't really have a lot of purpose (imho).
If not, the function getMouseProjectionOnBall can be changed similar to the following. This does two things (not necessarily "correctly"):
Normalize the radius to fill both axis
Map z values outside of the ball (ie where z was previously 0)
I find this a lot more natural, personally.
Thoughts?
this.getMouseProjectionOnBall = function(clientX, clientY) {
var xnormalized = (clientX - _this.screen.width * 0.5 - _this.screen.offsetLeft) / (_this.screen.width / 2.0);
var ynormalized = (_this.screen.height * 0.5 + _this.screen.offsetTop - clientY) / (_this.screen.height / 2.0);
var mouseOnBall = new THREE.Vector3(
xnormalized,
ynormalized,
0.0
);
var length = mouseOnBall.length();
var ballRadius = 1.0; // As a fraction of the screen
if (length > ballRadius * 0.70710678118654752440) {
var temp = ballRadius / 1.41421356237309504880;
mouseOnBall.z = temp * temp / length;
// Remove old method.
// This Left z = 0, which meant rotation axis
// becomes z, which is a roll
//mouseOnBall.normalize();
} else {
mouseOnBall.z = Math.sqrt(1.0 - length * length);
}
_eye.copy(_this.object.position).sub(_this.target);
var projection = _this.object.up.clone().setLength(mouseOnBall.y);
projection.add(_this.object.up.clone().cross(_eye).setLength(mouseOnBall.x));
projection.add(_eye.setLength(mouseOnBall.z));
return projection;
};

Related

What's wrong with this nearest neighbor interpolation shader?

GPU.js converts a JS func into a shader. The following function knows this.thread.x as the current index being operated on, but it is ultimately working as a WebGL shader.
export default function(sprite, w, h, scale) {
var bufferWidth = w * 4;
var channel = this.thread.x % 4;
var thread = this.thread.x - channel;
var y = Math.round(this.thread.x / bufferWidth);
var x = (thread % bufferWidth) / 4;
var upscale = scale * 10;
var upscaleY = y * 10;
var upscaleX = x * 10;
var scaledY = Math.round(upscaleY / upscale);
var scaledX = Math.round(upscaleX / upscale);
var newIndex = scaledY * bufferWidth + scaledX * 4;
if (x <= w * scale && y <= h * scale) {
return sprite[newIndex + channel];
} else {
return 0;
}
}
This almost works, but rows become skipped completely, actually making the result shorter than it should, and lines where those missing rows travel up and down and left to right on the image as it's scaled over time.
You can see this effect here: https://enviziion.github.io/lost-worlds/
What's wrong with my algo? Ive tried tweaking rounding and all sorts of stuff but no luck.
Use Math.floor when computing y:
var y = Math.floor(thread / bufferWidth);
If you use Math.round then it will start rounding up to the next row halfway across the buffer, which will produce a weird discontinuity.
Mathematically, you should be able to get back thread.x from y * bufferWidth + x * 4, which works for floor but not round.

XNA/Monogame Creating rectangle around texture regardless of rotation?

I know Rectangle is axis aligned, that's fine, I just can't figure out how to create a rectangle so it is always encompassing the entire sprite, regardless of rotation. I have been looking everywhere for an answer but I can't get a straight one anywhere.
For example:
Assuming the origin point is the middle of the texture, how can I go about this?
EDIT
Fiddling around with it a little, I've gotten this far:
public Rectangle BoundingBox
{
get
{
var cos = Math.Cos(SpriteAngle);
var sin = Math.Cos(SpriteAngle);
var t1_opp = Width * cos;
var t1_adj = Math.Sqrt(Math.Pow(Width, 2) - Math.Pow(t1_opp, 2));
var t2_opp = Height * sin;
var t2_adj = Math.Sqrt(Math.Pow(Height, 2) - Math.Pow(t2_opp, 2));
int w = Math.Abs((int)(t1_opp + t2_opp));
int h = Math.Abs((int)(t1_adj + t2_adj));
int x = Math.Abs((int)(Position.X) - (w / 2));
int y = Math.Abs((int)(Position.Y) - (h / 2));
return new Rectangle(x, y, w, h);
}
}
(doing this off the top of my head.. but the principle should work)
Create a matrix to rotate around the center of the rectangle - that is a translate of -(x+width/2), -(y+height/2)
followed by a rotation of angle
followed by a translate of (x+width/2), (y+height/2)
Use Vector2.Transform to transform each corner of the original rectangle
Then make a new rectangle with
x = min(p1.x, p2.x, p3.x, p4.x)
width = max(p1.x, p2.x, p3.x, p4.x) - x
similar for y
Sorry this is coming so late, but I figured this out a while ago and forgot to post an answer.
public virtual Rectangle BoundingBox
{
get
{
int x, y, w, h;
if (Angle != 0)
{
var cos = Math.Abs(Math.Cos(Angle));
var sin = Math.Abs(Math.Sin(Angle));
var t1_opp = Width * cos;
var t1_adj = Math.Sqrt(Math.Pow(Width, 2) - Math.Pow(t1_opp, 2));
var t2_opp = Height * sin;
var t2_adj = Math.Sqrt(Math.Pow(Height, 2) - Math.Pow(t2_opp, 2));
w = (int)(t1_opp + t2_opp);
h = (int)(t1_adj + t2_adj);
x = (int)(Position.X - (w / 2));
y = (int)(Position.Y - (h / 2));
}
else
{
x = (int)Position.X;
y = (int)Position.Y;
w = Width;
h = Height;
}
return new Rectangle(x, y, w, h);
}
}
This is it here. In my work in the edit, I accidentally had Math.Cos in the sin variable, which didn't help.
So it's just basic trigonometry. If the textures angle is something other than zero, calculate the sides of the two triangles formed by the width and the height, and use the sides as the values for the width and the height, then center the rectangle around the texture. If that makes sense.
Here's a picture to help explain:
Here's a gif of the final result:

how to figure out cursive paths for an enemy to follow

The Problem
I am making a game where enemies appear at some point on the screen then follow a smooth curvy path and disappear at some point. I can make them follow a straight path but can't figure out the way to make them follow the paths depicted in the image.
Attempts
I started with parabolic curve and implemented them successfully. I just used the equation of parabola to calculate the coordinates gradually. I have no clue what is the equation for desired paths supposed to be.
What I want
I am not asking for the code.I just want someone to explain me the general technique.If you still want to show some code then I don't have special preference for programming language for this particular question you can use C,Java or even pseudo-code.
First you need to represent each curve with a set of points over time, For example:
-At T(0) the object should be at (X0, Y0).
-At T(1) the object should be at (X1, Y1).
And the more points you have, the more smooth curve you will get.
Then you will use those set of points to generate two formulas-one for X, and another one for Y-, using any Interpolation method, like The La-grange's Interpolation Formula:
Note that you should replace 'y' with the time T, and replace 'x' with your X for X formula, and Y for Y formula.
I know you hoped for a simple equation, but unfortunately this is will take from you a huge effort to simplify each equation, and my advise DON'T do it unless it's worth it.
If you are seeking for a more simple equation to perform well in each frame in your game you should read about SPline method, In this method is about splitting your curve into a smaller segments, and make a simple equation for every segment, for example:
Linear Spline:
Every segment contains 2 points, this will draw a line between every two points.
The result will be some thing like this:
Or you could use quadratic spline, or cubic spline for more smooth curves, but it will slow your game performance. You can read more about those methods here.
I think linear spline will be great for you with reasonable set of points for each curve.
Please change the question title to be more generic.
If you want to generate a spiral path you need.
Total time
How many full rotations
Largest radius
So, total time T_f = 5sec, rotations R_f = 2.5 * 2 * PI, the final distance from the start D_f = 200px
function SpiralEnemy(spawnX, spawnY, time) {
this.startX = spawnX;
this.startY = spawnY;
this.startTime = time;
// these will change and be used for rendering
this.x = this.startX;
this.y = this.startY;
this.done = false;
// constants we figured out above
var TFinal = 5.0;
var RFinal = -2.6 * 2 * Math.PI;
var RStart = -Math.PI / 2;
var DFinal = 100;
// the update function called every animation tick with the current time
this.update = function(t) {
var delta = t - this.startTime;
if(delta > TFinal) {
this.done = true;
return;
}
// find out how far along you are in the animation
var percent = delta / TFinal;
// what is your current angle of rotation (in radians)
var angle = RStart + RFinal * percent;
// how far from your start point should you be
var dist = DFinal * percent;
// update your coordinates
this.x = this.startX + Math.cos(angle) * dist;
this.y = this.startY + Math.sin(angle) * dist;
};
}
EDIT Here's a jsfiddle to mess with http://jsfiddle.net/pxb3824z/
EDIT 2 Here's a loop (instead of spiral) version http://jsfiddle.net/dpbLxuz7/
The loop code splits the animation into 2 parts the beginning half and the end half.
Beginning half : angle = Math.tan(T_percent) * 2 and dist = Speed + Speed * (1 - T_percent)
End half : angle = -Math.tan(1 - T_percent) * 2 and dist = **Speed + Speed * T_percent
T_percent is normalized to (0, 1.0) for both halfs.
function LoopEnemy(spawnX, spawnY, time) {
this.startX = spawnX;
this.startY = spawnY;
this.startTime = time;
// these will change and be used for rendering
this.x = this.startX;
this.y = this.startY;
this.last = time;
this.done = false;
// constants we figured out above
var TFinal = 5.0;
var RFinal = -2 * Math.PI;
var RStart = 0;
var Speed = 50; // px per second
// the update function called every animation tick with the current time
this.update = function(t) {
var delta = t - this.startTime;
if(delta > TFinal) {
this.done = true;
return;
}
// find out how far along you are in the animation
var percent = delta / TFinal;
var localDelta = t - this.last;
// what is your current angle of rotation (in radians)
var angle = RStart;
var dist = Speed * localDelta;
if(percent <= 0.5) {
percent = percent / 0.5;
angle -= Math.tan(percent) * 2;
dist += dist * (1 - percent);
} else {
percent = (percent - 0.5) / 0.5;
angle -= -Math.tan(1 - percent) * 2;
dist += dist * percent;
}
// update your coordinates
this.last = t;
this.x = this.x + Math.cos(angle) * dist;
this.y = this.y + Math.sin(angle) * dist;
};
}
Deriving the exact distance traveled and the height of the loop for this one is a bit more work. I arbitrarily chose a Speed of 50px / sec, which give a final x offset of ~+145 and a loop height of ~+114 the distance and height will scale from those values linearly (ex: Speed=25 will have final x at ~73 and loop height of ~57)
I don't understand how you give a curve. If you need a curve depicted on the picture, you can find a curve is given analytically and use it. If you have not any curves you can send me here: hedgehogues#bk.ru and I will help find you. I leave e-mail here because I don't get any messages about answers of users from stackoverflow. I don't know why.
If you have some curves in parametric view in [A, B], you can write a code like this:
struct
{
double x, y;
}SPoint;
coord = A;
step = 0.001
eps = 1e-6;
while (coord + step - eps < B)
{
SPoint p1, p2;
p1.x = x(coord);
p1.y = y(coord);
coord += step;
p2.x = x(coord);
p2.y = y(coord);
drawline(p1, p2);
}

Three.js r60 Height Map

So I have a heightmap system which works well enough, however since the THREE.js has updated to r60 which removed the Face4 object, I am having issues.
My code is something like this:
this.buildGeometry = function(){
var geo, len, i, f, y;
geo = new THREE.PlaneGeometry(3000, 3000, 128, 128);
geo.dynamic = true;
geo.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI / 2));
this.getHeightData('heightmap.png', function (data) {
len = geo.faces.length;
for(i=0;i<len;i++){
f = geo.faces[i];
if( f ){
y = (data[i].r + data[i].g + data[i].b) / 2;
geo.vertices[f.a].y = y;
geo.vertices[f.b].y = y;
geo.vertices[f.c].y = y;
geo.vertices[f.d].y = y;
}
}
geo.computeFaceNormals();
geo.computeCentroids();
mesh = new THREE.Mesh(geo, new THREE.MeshBasicMaterial({color:0xff0000}) );
scene.add(mesh);
});
};
This works well since a pixel represents each face. How is this done now that the faces are all triangulated?
Similarly I use image maps for model positioning as well. Each pixel matches to the respective Face4 and a desired mesh is placed at its centroid. How can this be accomplished now?
I really miss being able to update the library and do not want to be stuck in r59 anymore =[
This approach works fine on the recent versions (tested on r66).
Notice that the genFn returns the height y given current col and row, maxCol and maxRow (for testing purposes, you can of course replace it with a proper array lookup or from a grayscale image... 64x64 determines the mesh resolution and 1x1 the real world dimensions.
var genFn = function(x, y, X, Y) {
var dx = x/X;
var dy = y/Y;
return (Math.sin(dx*15) + Math.cos(dy * 5) ) * 0.05 + 0.025;
};
var geo = new THREE.PlaneGeometry(1, 1, 64, 64);
geo.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI / 2));
var iz, ix,
gridZ1 = geo.widthSegments +1,
gridX1 = geo.heightSegments+1;
for (iz = 0; iz < gridZ1; ++iz) {
for (ix = 0; ix < gridX1; ++ix) {
geo.vertices[ ix + gridX1*iz ].y = genFn(ix, iz, gridX1, gridZ1);
}
}
geo.computeFaceNormals();
geo.computeVertexNormals();
geo.computeCentroids();
var mesh = new THREE.Mesh(
geo,
mtl
);
scene.add(mesh);

Enemy manager class AS3

How can I make a enemy that moving across the line and throwing something to our player?
I want to do it with ActionScript 3, and I already have enemy_manager class
I already have this code for getting angle
var dx : Number = point1.x - point2.x;
var dy : Number = point1.y - point2.y;
var angleInRadians : Number = Math.atan2(dy, dx);
var andleInDegrees : Number = angleInRadians * (180 / Math.PI);
What I think that your asking is how to get decimal values to multiple by the projectiles speed to make the projectile go towards the player. This is the code to accomplish that.
var projectileSpeed:Number=30 (pixels a second)
var dx : Number = point2.x - point1.x;
var dy : Number = point2.y - point1.y;
var angleInRadians : Number = Math.atan2(dy, dx);
var angleInDegrees : Number = angleInRadians * (180 / Math.PI);
this.directionX = Math.cos(angleInRadians) * projectileSpeed; // Turns the angleInRadians into a decimal value
// For example ( 180 degrees would be 1 PI and the cos() and sin() would make directionX=-1 and directionY=0
this.directionY = Math.sin(angleInRadians) * projectileSpeed;
projectile.rotation = angleInDegrees; // makes it face where it is going ( if you event want this)
...
private function loop(e:Event):void { // loop to show the projectile move
// Updates the projectile's positions using directionX and directionY
projectile.x += directionX;
projectile.y += directionY;
}

Resources