XNA Rotating multiple objects around a pivot point - c#

Here is my code. It works, except for when I do it at first It jumps far away from where it started, and as it's rotating its twitching and sort of flipping rapidly...
float rotAmount = 0;
Vector2 pivot = CenterSelection();
if (keyboardState.IsKeyDown(Keys.OemPlus)) rotAmount = 0.01f;
if (keyboardState.IsKeyDown(Keys.OemMinus)) rotAmount = -0.01f;
map.DoForSelected(delegate(GameObject mod)
{
Vector2 vDif = pivot - mod.position;
float vDist = (float)Math.Sqrt(Math.Pow(vDif.X, 2) + Math.Pow(vDif.Y, 2));
float vRot = rotAmount + (float)Math.Atan2(vDif.Y, vDif.X);
mod.position = pivot + new Vector2(
(float)Math.Cos(vRot),
(float)Math.Sin(vRot)
) * vDist;
mod.rotation += rotAmount;
});
I am trying to figure out what's wrong!
Your help is greatly appreciated!

Your difference vector points in the wrong direction:
Vector2 vDif = pivot - mod.position;
This is a vector from position to pivot.
Then you assign
mod.position = pivot + newDif;
expecting that newDif is a vector from pivot to position. But it's actually reversed.
So just reverse your difference vector:
Vector2 vDif = mod.position - pivot;

Related

Unity3d: Rotate a gameobject towards forward vector of another gameobject

BackCube.position = cameraEye.position - cameraEye.forward * 2;
float back = cameraEye.position.z - 2f;
BackCube.position = new Vector3(BackCube.position.x, BackCube.position.y, back);
var lookPosBack = cameraEye.position - BackCube.position;
lookPosBack.y = 0;
var rotationBack = Quaternion.LookRotation(lookPosBack);
BackCube.rotation = Quaternion.Slerp(BackCube.rotation, rotationBack, 1);
So, I want the my BackCube to rotate towards the forward vector of cameraEye. The code above looks at the cameraEye, but not towards the forward vector of cameraEye. I want the forward vectors of both pointing at each other being 2 units apart from each other. I have control only over the BackCube
This worked!
Vector3 direction = Vector3.ProjectOnPlane(cameraEye.forward, Vector3.up);
BackCube.transform.position = cameraEye.position - direction.normalized * 2;
var lookPosBack = cameraEye.position - BackCube.position;
lookPosBack.y = 0;
var rotationBack = Quaternion.LookRotation(lookPosBack);
BackCube.rotation = Quaternion.Slerp(BackCube.rotation, rotationBack, 1);

Current frustum culling effects results in flickering objects in openTk

I am having some issues with the way in which I do my frustum culling. The current way does resolve in culling but there is a really odd effect. When I get too close to my main parent object, I am using a scenegraph to render everything, the objects starts flickering really fast. This is gone when I move away. I have tried a lot of things but have no ideas anymore. Do you guys have any thoughts. Any help is greatly appreciated.
I first create a boundingbox consisting of eight points around my models. These are correct as far as i am aware after a lot of testing.
This is my way of calculating the points of the frustum planes.
THe camera position is the position in world space and the orientation is the direction it is looking at. Furhtermore the cameraUp and cameraRight are calculated every time the camera is rotated.
Vector3 pos = Camera.staticPosition;
Vector3 view = Camera.staticOrientation;
Vector3 upVector3 = Camera.cameraUp;
Vector3 rightVector3 = Camera.cameraRight;
float toRadians = (float)Math.PI / 180.0f;
float nearDis = .1f;
float farDistance = 1000f;
float fov = Game.FOV;
float aspectRatio = 1.3f;
//Get with and height of near and far plane
float tanDiv = 2 * (float) Math.Tan(fov*toRadians / 2);
float heightNear = tanDiv * nearDis;
float widthNear = heightNear * aspectRatio;
float heightFar = tanDiv * farDistance;
float widthFar = heightFar * aspectRatio;
// get the centre points of the planes so they can be used to calculate the edge points
Vector3 centreNear = pos + view * nearDis;
Vector3 centreFar = pos + view * farDistance;
// get the halfht values of the width and hegiht to make sure you can get the points
float hNearHalf = heightNear / 2;
float wNearHalf = widthNear / 2;
float hFarHalf = heightFar / 2;
float wFarHalf = widthFar / 2;
Vector3 nearTopLeft = centreNear + (upVector3 * hNearHalf) - (rightVector3 * wNearHalf);
Vector3 nearTopRight = centreNear + (upVector3 * hNearHalf) + (rightVector3 * wNearHalf);
Vector3 nearBottomLeft = centreNear - (upVector3 * hNearHalf) - (rightVector3 * wNearHalf);
Vector3 nearBottomRight = centreNear - (upVector3 * hNearHalf) + (rightVector3 * wNearHalf);
Vector3 farTopLeft = centreFar + (upVector3 * hFarHalf) - (rightVector3 * wFarHalf);
Vector3 farTopRight = centreFar + (upVector3 * hFarHalf) + (rightVector3 * wFarHalf);
Vector3 farBotomLeft = centreFar - (upVector3 * hFarHalf) - (rightVector3 * wFarHalf);
Vector3 farBottomRight = centreFar - (upVector3 * hFarHalf) + (rightVector3 * wFarHalf);
I store my frustum points in an array. First thhe nearplane points, then the farplane, topplane, bottomplane, leftplane and lastly the rightplane. Then i loop through all the six planes and 8 points of the boundinbox if the point is on the right side of the plane increment the value of that key in the dictionary.
Vector3[] frustumPoints = new Vector3[18]
{
nearTopLeft, nearTopRight, nearBottomLeft, farTopLeft, farTopRight, farBotomLeft, nearTopLeft, farTopLeft,
nearTopRight, nearBottomLeft, farBotomLeft, nearBottomRight, nearTopLeft, nearBottomLeft, farTopLeft,
nearTopRight, nearBottomRight, farTopRight
};
Dictionary<Vector3, int> count = new Dictionary<Vector3, int>(8);
for (int value = 0; value < 8; value++)
{
count.Add(cubePositions[value], 0);
}
for (int x = 0; x < 18; x += 3)
{
Vector3 normal = NormalPlane(frustumPoints[x], frustumPoints[x + 1], frustumPoints[x + 2]);
for (int y = 0; y < 8; y++)
{
Vector3 pointPlane = frustumPoints[x] - cubePositions[y];
float dot = Vector3.Dot(pointPlane, normal);
if (dot <= 0 && x % 6 == 0)
{
count[cubePositions[y]]++;
}
else if (dot >= 0 && x % 3 == 0)
{
count[cubePositions[y]]++;
}
}
}
This is my method to get the normals of the plane
Vector3 NormalPlane(Vector3 pointOne, Vector3 pointTwo, Vector3 pointThree)
{
Vector3 normal;
Vector3 edgeOne = pointTwo - pointOne; // calculate vector from point one to point two
Vector3 edgeTwo = pointThree - pointOne; // calculate vector from point one to point three
normal = Vector3.Normalize(Vector3.Cross(edgeOne, edgeTwo)); // calculate the cross product of the two given vectors. Then normalize it so you have normal of plane
return normal; // return the normal
}
If for one of these points on the cube the count is six, the points is within all planes and thus the frustum and I draw the object. If none of the points is equal to 6 the objects don't get drawn.
Problem is i have no idea where I am making a mistake so do you guys have any ideas?
Thanks in advance,
Jeromer
If for one of these points on the cube the count is six, the points is within all planes and thus the frustum and I draw the object. If none of the points is equal to 6 the objects don't get drawn.
Your logic here seems to be
"if there is no vertex of the cube lying inside the frustum, the cube is not visible."
However. This is just wrong. Even if all 8 vertices of the cube lie outside the frustum, the cube still can intersect the frustum, as demonstrated in this 2D sketch:
*----------*
| |
+-----------------+--+ |
\ | / |
\ |/ |
\ / |
\ /| |
\ / *----------*
\ /
\ /
+----+
Hence you cull stuff which is potentially visible.
The usual logic for frustum culling is to cull the box only if all of its vertices are rejected by the same plane. (This will result in some odd cases where the box is completely outside and not culled, but these situations are quite unlikely and usually not a big deal to worry about.)

Calculate middle point of Bezier Curve

I have a function to draw Bezier Curve through three points. I have already 2 points (start and end) - A and B. How do I calculate middle point between those two points as middle point would be always a little higher or lower than linear function of those two points.
Example:
Any formulas, ideas would be great!
I think this is what you're looking for:
http://blog.sklambert.com/finding-the-control-points-of-a-bezier-curve/
It goes into detail on calculating the various points on a Bezier curve.
You may also be interested in this more specific example for your application:
http://www.codeproject.com/Articles/223159/Midpoint-Algorithm-Divide-and-Conquer-Method-for-D
If you really want to get into it, then I suggest this Primer:
http://pomax.github.io/bezierinfo/
Bezier curves are a bit more complicated than simple arcs. For an arc, you can just use this formula:
R = H/2 + W^2/8H
...which definitely won't work for a Bezier curve. On a Quadratic Bezier curve, for example, to calculate a point, you must use:
Sources: http://en.wikipedia.org/wiki/B%C3%A9zier_curve, Quadratic Bezier Curve: Calculate Point
Below is what I use to get the control point of a quad bezier curve. It should work for your problem where the control point is on the curve. It's in Swift but you should be able to convert it to another language easily. Basically at the midpoint of the line (whose points are point1 and point2) I work out a perpendicular line with the given length. Clockwise parameter determines which side of the line the point should fall on.
func getControlPointWithPoint1(point1:CGPoint, point2:CGPoint, length:CGFloat, clockwise:Bool) -> CGPoint {
let angle = getAngleWithPoint1(point1, point2:point2)
let direction = clockwise ? 1 : -1
let perpendicularAngle = angle + (CGFloat(direction) * CGFloat((M_PI / 2)))
let midPoint = getMidPointWithPoint1(point1, point2:point2)
return CGPointMake(midPoint.x + (cos(perpendicularAngle) * length), midPoint.y + (sin(perpendicularAngle) * length))
}
func getAngleWithPoint1(point1:CGPoint, point2:CGPoint) -> CGFloat {
return atan2((point2.y - point1.y), (point2.x - point1.x))
}
func getMidPointWithPoint1(point1:CGPoint, point2:CGPoint) -> CGPoint {
return CGPointMake((point1.x + point2.x) / 2, (point1.y + point2.y) / 2)
}
Below is how it would map to your diagram letters:
c = getControlPointWithPoint1(a, point2:b, length:h, clockwise:true)
following Mark's answer, here is the snippet in C#
public static Path DrawBezeireUsingTwoPoints(Point startPoint, Point endPoint)
{
Path path = new Path();
PathFigure pathFigure = new PathFigure();
// Set up the Path to insert the segments
PathGeometry pathGeometry = new PathGeometry();
BezierSegment bezeireSeg;
// Draw an ellipse passing by the 2 points and let the path cross it
Point beziereMidPoint = CalculateBezierePoint(startPoint, endPoint, true);
bezeireSeg = new BezierSegment(startPoint, beziereMidPoint, endPoint, true);
pathFigure.StartPoint = startPoint;
pathFigure.IsClosed = false;
pathFigure.Segments.Add(bezeireSeg);
pathGeometry.Figures.Add(pathFigure);
path.Data = pathGeometry;
path.Stroke = Brushes.Brown;
path.StrokeThickness = 2;
return path;
}
I would be happy if help you.
It is my solution.
Vector2 posA = sphereA.transform.position;
Vector2 posB = sphereB.transform.position;
Gizmos.color = Color.blue;
Gizmos.DrawLine(posA, posB);
float distance = Vector2.Distance(posA, posB);
Vector2 direction = (posB - posA).normalized;
Vector2 v2 = end - start;
var angle = Mathf.Atan2(v2.y, v2.x) * Mathf.Rad2Deg;
var midStartPos = posA + direction * (distance / 2f);
Gizmos.color = Color.red;
Gizmos.DrawSphere(midStartPos, 0.02f);
var height = 0.3f;
height = Mathf.Clamp(height, 0f, Vector2.Distance(posA, posB) * 0.5f);
angle = 90f + angle;
var goalDirection = new Vector2(Mathf.Cos(angle * Mathf.Deg2Rad), Mathf.Sin(angle * Mathf.Deg2Rad));
if (goalDirection.y < 0f)
{
goalDirection.x = -goalDirection.x;
goalDirection.y = Mathf.Abs(goalDirection.y);
}
var midEndPos = midStartPos + goalDirection * height;
Gizmos.color = Color.blue;
Gizmos.DrawLine(midStartPos, midEndPos);
Gizmos.color = Color.red;
Gizmos.DrawSphere(midEndPos, 0.02f);

Scaling right vector based on light direction

I'm having a quad that I constructed and I would like to scale the quad based on how much light, the problem is the dot product gives me negative values, which I can not use to scale the vectors on the other side of the quad. I have a mesh consists of 6 vertices, two quads. One of the two quads should extend or shrink based on how much is the dot product values, how would I scale one quad and shrink the other side based on that dot product value ?
float lightAngleRightVector = Vector3.Dot(lightDir.normalized, Source.transform.right.normalized);
lightAngleRightVector = Mathf.Clamp(lightAngleRightVector, 0.2f, 0.5f);
Global.Log("Light Angle Right Vecotr" + lightAngleRightVector);
// light projected left side, limit values);
if (lightAngleRightVector < 0.3f)
{
vxAbLeft = lightAngleRightVector;
vxCdRight = lightAngleRightVector - 0.1f;
}
// light projected right side
else if (lightAngleRightVector > 0.3f)
{
vxCdRight = lightAngleRightVector;
vxAbLeft = lightAngleRightVector - 0.1f;
}
Global.Log("VxCDRIGHT = " + vxCdRight);
Global.Log("vxAbLeft = " + vxAbLeft);
// add little bit shift up for fixing z-fighting
Vector3 vxPos1Top = (frontPt + new Vector3(0, mShadowOffestY, 0)) - (mRightFrontPt * vxAbLeft) * scale; // 1,2 vertices or on its left
Vector3 vxPos2Top = (mRightBackPt * vxAbLeft) * scale;
Vector3 vxPos3Top = frontPt;
Vector3 vxPos4Top = backPt;
Vector3 vxPos5Top =(mRightFrontPt * vxCdRight) * scale; // 5,6 vertices are on the right of the car
Vector3 vxPos6Top =(mRightBackPt * vxCdRight * scale);
Perhaps the scale should be abs( scale ), so it will be > 0 from the unlit side. Is that what you want?

How to rotate a Vector2?

I'm trying to rotate a Vector2 but nothing work.
I've tried the following -> didn't work:
x' = cos(angle)*x - sin(angle)*y & y' = sin(angle)*x + cos(angle)*y
I've tried using a rotation matrix -> didn't work
What am I doing wrong ? :/
angle = MathHelper.Pi;
direction.X = (int)((direction.X) * Math.Cos(angle) - direction.Y * Math.Sin(angle));
direction.Y = (int)((direction.X) * Math.Sin(angle) + direction.Y * Math.Cos(angle));
float angle = MathHelper.PiOver2;
Vector2 dir = new Vector2(direction.X, direction.Y);
Vector2.Transform(dir, Matrix.CreateRotationX(angle));
direction = new Point((int)dir.X, (int)dir.Y);
Vector2.Transform() returns a result rather than applying the changes in-place.
var transformed = Vector2.Transform(dir, Matrix.CreateRotationX(angle));
direction = new Point((int) dir.X, (int) dir.Y);
The first method you have written should work, as it's showed here also: http://www.oocities.org/davidvwilliamson/rotpoint.jpg
Remember to store the original values, and use those to determine the new values, and do not use the new x value to calculate y. Or store the products in separate variables.

Categories

Resources