I am doing some work with opengl es on the iPhone and I am stuck at a particular point. All the code samples on the internet show you how a matrix can be rotated about the x axis, y axis or the z axis but no one talks about how a matrix can be rotated about an arbitrary point?
I am using open gl es 2.0. Any help would be appreciated.
Regards,
It sounds like you're asking how to construct a matrix that rotates around one of those axes, but at a different point. The way you do that is to first translate to that point, and then apply the rotation for the axis you want. The order of multiplication of matrixes depends on whether you think of it as the axes moving or the geometry.
If you also want to be able to do a rotation of arbitrary x, y, z angle at the same time, you can use the matrix discussed in this article:
static inline void Matrix3DSetRotationByRadians(Matrix3D matrix, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
{
GLfloat mag = sqrtf((x*x) + (y*y) + (z*z));
if (mag == 0.0)
{
x = 1.0;
y = 0.0;
z = 0.0;
}
else if (mag != 1.0)
{
x /= mag;
y /= mag;
z /= mag;
}
GLfloat c = cosf(angle);
GLfloat s = fastSinf(angle);
matrix[3] = matrix[7] = matrix[11] = matrix[12] = matrix[13] = matrix[14] = 0.0;
matrix[15] = 1.0;
matrix[0] = (x*x)*(1-c) + c;
matrix[1] = (y*x)*(1-c) + (z*s);
matrix[2] = (x*z)*(1-c) - (y*s);
matrix[4] = (x*y)*(1-c)-(z*s);
matrix[5] = (y*y)*(1-c)+c;
matrix[6] = (y*z)*(1-c)+(x*s);
matrix[8] = (x*z)*(1-c)+(y*s);
matrix[9] = (y*z)*(1-c)-(x*s);
matrix[10] = (z*z)*(1-c)+c;
}
Related
I want to rotate my player in the way I showed in the picture. I don't understand what Vector3. I would use here in transform.rotate
As we talked in comments I guess that you know what Vectors are from your background.
And with transform.rotate() there are more then one options to use that method which we call Method Overloading. And one of the way to use is that is transform.Rotate(Vector3 direction, float rotation).
And the reason it takes Vector3 as a direction in this method is because the way Unity handles direction.
In Unity as when it comes to direction with Vector3 it is considered/calculated as follows
Vector3.right = x = 1, y = 0, z = 0
Vector3.left = x = -1, y = 0, z = 0
Vector3.up = x = 0, y = 1, z = 0
Vector3.down = x = 0, y = -1, z = 0
Vector3.forward = x = 0, y = 0, z = 1
Vector3.back = x = 0, y = 0, z = -1
So to answering your question you can achieve the functionality by using Vector3.forword as direction. Because the direction/Axis you want your object to be rotated is the one from back to front if you consider Vector3 that would be z axis ans as I've listed above you can use Vector3.forward as a direction/axis of your rotation in transform.Rotate()
Reference:
Tranform.Rotate
Hope this helps, welcome to unity Happy Coding
I'm plotting a square image, but since my camera views out of a circular construction, I want the image to look circular as well. So to do this, I just wanted to create a mask for the image (basically create a matrix, and multiply my data by the mask, so if I want to retain my image I am multiplying by one, and if I want that part of the image to go to black, I multiply by 0).
I'm not sure the best way to make a matrix that will represent a circular opening though. I just want every element within the circle to be a "1" and every element outside the circle to be a "0" so I can color my image accordingly. I was thinking of doing a for loop, but I was hoping there was a faster way to do it. So...all I need is:
A matrix that is 1280x720
I need a circle that has a diameter of 720, centered in the middle of the 1280x720 matrix (what I mean by this is all elements corresponding to being within the circle have a "1" and all other elements have a "0"
My attempt
mask = zeros(1280,720)
for i = 1:1280
for j = 1:720
if i + j > 640 && i + j < 1360
mask(i,j) = 1;
end
end
end
Well the above obviously doesn't work, I need to look at it a little better to form a better equation for determing when to add a 1 =P but ideally I would like to not use a for loop
Thanks, let me know if anything is unclear!
#kol 's answer looks correct. You can do this with vectorized code using the meshgrid function.
width = 1280;
height = 720;
radius = 360;
centerW = width/2;
centerH = height/2;
[W,H] = meshgrid(1:width,1:height);
mask = ((W-centerW).^2 + (H-centerH).^2) < radius^2;
Here is a possible solution:
width = 160;
height = 120;
mask = zeros(width, height);
center_x = width / 2;
center_y = height / 2;
radius = min(width, height) / 2;
radius2 = radius ^ 2;
for i = 1 : width
for j = 1 : height
dx = i - center_x;
dy = j - center_y;
dx2 = dx ^ 2;
dy2 = dy ^ 2;
mask(i, j) = dx2 + dy2 <= radius2;
end;
end;
picture = randn(width, height); % test image :)
masked_image = picture .* mask;
imagesc(masked_image);
I have tried several different solutions but no luck so far.
- (CGPoint)contractLineTemp:(CGPoint)point :(CGPoint)circle :(float)circleRadius {
CGFloat x,y;
x = point.x - circle.x;
y = point.y - circle.y;
CGFloat theta = atan2(x, y);
CGPoint newPoint;
newPoint.x = circle.x + circleRadius * sin(theta);
newPoint.y = circle.y + circleRadius * cos(theta);
return newPoint;
}
- (CGPoint)contractLineTemp:(CGPoint)startPoint :(CGPoint)endPoint :(float)scaleBy {
float dx = endPoint.x - startPoint.x;
float dy = endPoint.y - startPoint.y;
float scale = scaleBy * Q_rsqrt(dx * dx + dy * dy);
return CGPointMake (endPoint.x - dx * scale, endPoint.y - dy * scale);
}
Both of these solutions kind of work. If I draw the line to the center of the circle you can see that it intersects the circle exactly where it should.
http://www.freeimagehosting.net/le5pi
If I use either of the solutions above and draw to the circumference of the circle depending on the angle it is no longer going towards the center of the circle. In the second image the line should be in the middle of the right edge of the circle and going straight right.
http://www.freeimagehosting.net/53ovs
http://www.freeimagehosting.net/sb3b2
Sorry for the links. I am to new to currently post images.
Thanks for you help.
It's easier to treat this as a vector problem. Your second approach is close, but you don't correctly scale the vector between the two points. It's easier to work with a normalized vector in this case, although you have to assume that the distance between the two points on the line is non-zero.
Given:
double x0 = CIRC_X0; /* x-coord of center of circle */
double y0 = CIRC_Y0; /* y-coord of center of circle */
double x1 = LINE_X1; /* x-coord of other point on the line */
double y1 = LINE_Y1; /* y-coord of other point on the line */
Then the vector between the two points is (vx,vy):
double vx = x1 - x0;
double vy = y1 - y0;
It's easier to work with a unit vector, which we can get by normalizing (vx,vy):
double vmag = sqrt(vx*vx + vy*vy);
vx /= vmag; /* Assumption is vmag > 0 */
vy /= vmag;
Now, any point along the line can be described as:
x0 + dist * vx
y0 + dist * vy
where dist is the distance from the center. The intersection of the circle and the line must be a distance of CIRC_RADIUS from the center, so:
double x_intersect = x0 + CIRC_RADIUS * vx;
double y_intersect = y0 + CIRC_RADIUS * vy;
I think that there may be a convention conflict on what theta, x and y are. The atan2 function yields values in the range -pi..pi, by taking the convention of theta as the angle growing from the X axis towards Y. However you are considering theta as the angle from Y to X.
Try changing the code:
CGFloat theta = atan2(y, x);
CGPoint newPoint;
newPoint.x = circle.x + circleRadius * cos(theta);
newPoint.y = circle.y + circleRadius * sin(theta);
Although your formulae are consistent within a coordinate system, it may have conflict with the screen/display device coordinate system.
As I wanted to animate an image in projectile motion,
My code is as follows, but it did not reach the target and give projectile animation, any help please?
-(void)timeLine
{
dTime += 0.1;
.................
double s_x = inVel * cos(angle1) ; // the X speed
double s_y = inVel * sin(angle1) ; // the Y speed
NSLog(#"sx = %i",s_x);
NSLog(#"sy = %i",s_y);
x = oX + (s_x * dTime);
y = oY + ( ( s_y * dTime) - (0.5 * 9.8 * dTime * dTime));
NSLog(#"x = %i",x);
NSLog(#"y = %i",y);
imageViewForAnimation.x += x;
imageViewForAnimation.y -= y;
}
imageViewForAnimation.x += x;
imageViewForAnimation.y -= y;
These lines don't seem right to me. You are calculating the actual x and y each time, not the difference moved since the last time. I'm also uncertain why one was being added and one was being subtracted, but that's beside the point. Basically, try changing the lines to
imageViewForAnimation.x = x;
imageViewForAnimation.y = y;
Also, you're doing some calculations over and over which only need to be done once. v_x == s_x (or it should within floating point error) as well as v_y == s_y. You only need to calculate v_x and V_y once beforehand rather than calculating them every time you update the coordinates.
I have a problem regarding positioning an image according to the touches location, however limited to a circle.
It works for the most part, but if the angle (from the touches location to the desired location) is less than 0, it positions the image on the wrong side of the circle.
Perhaps it's some maths that I've done wrong.
Anyway, here's the code:
float newHeight, newWidth, centerPointX, centerPointY;
newHeight = -(invertedY.y - (view.frame.origin.y+view.frame.size.height/2));
newWidth = -(invertedY.x - (view.frame.origin.x+view.frame.size.width/2));
float tangent = newHeight/newWidth;
float calculatedAngle = atanf(tangent);
float s, c, d, fX, fY;
d = view.frame.size.width/2+30;
if (calculatedAngle < 0) {
s = sinf(calculatedAngle) * d;
c = cosf(calculatedAngle) * d;
} else {
s = -sinf(calculatedAngle) * d;
c = -cosf(calculatedAngle) * d;
}
fX = view.center.x + c;
fY = view.center.y + s;
[delegate setPoint:CGPointMake(fX, fY)];
NSLog(#"angle = %.2f", calculatedAngle);
Any help appreciated.
I think the best way to limit location to a circle is calculate vector from center to touch location. Calculate vector length then divide it by that length so it would be normalized. Then multiply normalized vector by radius of circle and finally add this vector to the center to compute new location.
CGPoint touch, center;
CGPoint vector = CGPointMake(touch.x-center.x, touch.y-center.y);
float length = sqrtf(vector.x*vector.x + vector.y*vector.y);
// Normalize and multiply by radius (r)
vector.x = r * vector.x / length;
vector.y = r * vector.y / length;
[delegate setPoint:CGPointMake(center.x + vector.x, center.y + vector.y)];