OpenGL ES: Translate a matrix to a particular point - iphone

Hi guys I am working on a app which requires the use of opengl es. However I have some questions. My task at hand is to rotate a matrix about an arbitrary point say (0,0,0). I did some research on google and the most common approach is
translate the matrix to (0,0,0)
Rotate the matrix
Translate the matrix back to its original position
Effectively
glTranslatef(centerX, centerY, centerZ);
glRotatef(angle, 0, 0, 1);
glTranslatef(-centerX, -centerY, -centerZ);
However my problem is I am using opengl es 2.0. The function translatef does not exist in opengl es 2.0. I have a function called as translateBy but I am unable to figure out how to use translateBy function to translate my matrix to a certain point
Thanks any help would be appreciated.

In OpenGL ES 2.0 you have to use vertex shader and just update the modelview matrix in every frame using
GLint modelviewmatrix = glGetUniformLocation(m_simpleProgram, "ModelviewMatrix");
matrx4 modelviewMatrix = rotation * translation;
glUniformMatrix4fv(modelviewmatrix, 1, 0, modelviewMatrix.Pointer());
assuming matrx4 as a matrix class of 4x4. and rotation and translation are the 4x4 matrix objects for rotation and translation.
Just make your own translate and rotate functions,
Translatef(x,y,z) is equivalent to
Matrx4 Translate( x, y, z)
{
Matrx4 m;
m = { 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, z, 1 }
return m;
}
and Rotatef(degree, vector3 axis) is equivalent to
Matrx4 Rotate( float degree, vector3 axis)
{
float radians = degrees * 3.14159f / 180.0f;
float s = std::sin(radians);
float c = std::cos(radians);
Matrx4 m = Identity(); /// load identity matrix
m[0] = c + (1 - c) * axis.x * axis.x;
m[1] = (1 - c) * axis.x * axis.y - axis.z * s;
m[2] = (1 - c) * axis.x * axis.z + axis.y * s;
m[4] = (1 - c) * axis.x * axis.y + axis.z * s;
m[5] = c + (1 - c) * axis.y * axis.y;
m[6] = (1 - c) * axis.y * axis.z - axis.x * s;
m[8] = (1 - c) * axis.x * axis.z - axis.y * s;
m[9] = (1 - c) * axis.y * axis.z + axis.x * s;
m[10] = c + (1 - c) * axis.z * axis.z;
return m;
}

Related

How to draw line until middle point using quadraticBezierTo in flutter?

I'm trying to draw a line between three points using quadraticsBezierTo but here is my problem.
Current result:
Current result
Expected result:
Expected result
Code:
final path = Path();
path.moveTo(p1.x, p1.y);
path.quadraticBezierTo(p2.x, p2.y, p3.x, p3.y);
//Also tried: path.cubicTo(p2.x, p2.y, p2.x, p2.y, p3.x, p3.y);
Do you know how to achieved this result?
Maybe,
path.quadraticBezierTo(
2.0 * p2.x - 0.5 * (p1.x + p3.x), 2.0 * p2.y - 0.5 * (p1.y + p3.y),
p3.x, p3.y);
or
path.cubicTo(
(4.0 * p2.x - p3.x) / 3.0, (4.0 * p2.y - p3.y) / 3.0,
(4.0 * p2.x - p1.x) / 3.0, (4.0 * p2.y - p1.y) / 3.0,
p3.x, p3.y);
Appendix
If you prefer sharper/blunter curves, throw away quadratics Bezier curve and take cubic Bezier curve. Then shift the control points evenly inwards/outwards.
double epsilon = -0.1;
path.cubicTo(
(4.0 * p2.x - p3.x - epsilon * (p3.x - p1.x)) / 3.0, (4.0 * p2.y - p3.y - epsilon * (p3.y - p1.y)) / 3.0,
(4.0 * p2.x - p1.x + epsilon * (p3.x - p1.x)) / 3.0, (4.0 * p2.y - p1.y + epsilon * (p3.y - p1.y)) / 3.0,
p3.x, p3.y);
This breaks tangents at end points of the curve, though.
Bezier curves aren't designed to pass through their control points, but if that's what you want you can do it by modifying the center point. From Wikipedia
For quadratic Bézier curves one can construct intermediate points Q0 and Q1 such that as t varies from 0 to 1:
Point Q0(t) varies from P0 to P1 and describes a linear Bézier curve.
Point Q1(t) varies from P1 to P2 and describes a linear Bézier curve.
Point B(t) is interpolated linearly between Q0(t) to Q1(t) and describes a quadratic Bézier curve.
Thus,
q0 = p0 * (1 - t) + p1 * t and q1 = p1 * (1 - t) + p2 * t and the actual curve is
b = q0 * (1 - t) + q1 * t
= p0 * (1 - t)^2 + p1 * t * (t - 1) + p1 * t * (t - 1) + p2 * t^2
= p0 * (1 - t)^2 + 2 * p1 * t * (t - 1) + p2 * t^2
Note that by ^ I mean exponent, not xor.
So if you want your curve to pass through some point c at time t = 1/2, then we can find what p1 should be.
c = p0 * 0.25 + p1 * 0.5 + p2 * 0.25
So,
p1 = 2 * c - 0.5 * (p0 + p2)

Scaling a rotated ellipse

I have a function that draws an ellipse respecting some major axis (vx) and minor axis (vy) scales rotated clockwise by an angle a. I would like to adjust it so that the unrotated ellipse satisfies the equation:
(x / vx)^2 + (y / vy)^2 = s
For some value s which is passed in.
function [] = plotellipse(cx, cy, vx, vy, s, a)
t = linspace(0, 2 * pi);
x = cx + vx * cos(t) * cos(-a) - vy * sin(t) * sin(-a);
y = cy + vy * sin(t) * cos(-a) + vx * cos(t) * sin(-a);
plot(x,y,'y-');
The usual equation for an ellipse, which you have implemented correctly, is
To reduce the desired equation to the same form, divide through by s:
Now x and y become
vxs = vx / sqrt(s)
vys = vy / sqrt(s)
x = cx + vxs * cos(t) * cos(-a) - vys * sin(t) * sin(-a);
y = cy + vys * sin(t) * cos(-a) + vxs * cos(t) * sin(-a);

iOS OpenGL ES 2.0 Quaternion Rotation Slerp to XYZ Position

I am following the quaternion tutorial: http://www.raywenderlich.com/12667/how-to-rotate-a-3d-object-using-touches-with-opengl and am trying to rotate a globe to some XYZ location. I have an initial quaternion and generate a random XYZ location on the surface of the globe. I pass that XYZ location into the following function. The idea was to generate a lookAt vector with GLKMatrix4MakeLookAt and define the end Quaternion for the slerp step from the lookAt matrix.
- (void)rotateToLocationX:(float)x andY:(float)y andZ:(float)z {
// Turn on the interpolation for smooth rotation
_slerping = YES; // Begin auto rotating to this location
_slerpCur = 0;
_slerpMax = 1.0;
_slerpStart = _quat;
// The eye location is defined by the look at location multiplied by this modifier
float modifier = 1.0;
// Create a look at vector for which we will create a GLK4Matrix from
float xEye = x;
float yEye = y;
float zEye = z;
//NSLog(#"%f %f %f %f %f %f",xEye, yEye, zEye, x, y, z);
_currentSatelliteLocation = GLKMatrix4MakeLookAt(xEye, yEye, zEye, 0, 0, 0, 0, 1, 0);
_currentSatelliteLocation = GLKMatrix4Multiply(_currentSatelliteLocation,self.effect.transform.modelviewMatrix);
// Turn our 4x4 matrix into a quat and use it to mark the end point of our interpolation
//_currentSatelliteLocation = GLKMatrix4Translate(_currentSatelliteLocation, 0.0f, 0.0f, GLOBAL_EARTH_Z_LOCATION);
_slerpEnd = GLKQuaternionMakeWithMatrix4(_currentSatelliteLocation);
// Print info on the quat
GLKVector3 vec = GLKQuaternionAxis(_slerpEnd);
float angle = GLKQuaternionAngle(_slerpEnd);
//NSLog(#"%f %f %f %f",vec.x,vec.y,vec.z,angle);
NSLog(#"Quat end:");
[self printMatrix:_currentSatelliteLocation];
//[self printMatrix:self.effect.transform.modelviewMatrix];
}
The interpolation works, I get a smooth rotation, however the ending location is never the XYZ I input - I know this because my globe is a sphere and I am calculating XYZ from Lat Lon. I want to look directly down the 'lookAt' vector toward the center of the earth from that lat/lon location on the surface of the globe after the rotation. I think it may have something to do with the up vector but I've tried everything that made sense.
What am I doing wrong - How can I define a final quaternion that when I finish rotating, looks down a vector to the XYZ on the surface of the globe? Thanks!
Is the following your meaning:
Your globe center is (0, 0, 0), radius is R, the start position is (0, 0, R), your final position is (0, R, 0), so rotate the globe 90 degrees around X-asix?
If so, just set lookat function eye position to your final position, the look at parameters to the globe center.
m_target.x = 0.0f;
m_target.y = 0.0f;
m_target.z = 1.0f;
m_right.x = 1.0f;
m_right.y = 0.0f;
m_right.z = 0.0f;
m_up.x = 0.0f;
m_up.y = 1.0f;
m_up.z = 0.0f;
void CCamera::RotateX( float amount )
{
Point3D target = m_target;
Point3D up = m_up;
amount = amount / 180 * PI;
m_target.x = (cos(PI / 2 - amount) * up.x) + (cos(amount) * target.x);
m_target.y = (cos(PI / 2 - amount) * up.y) + (cos(amount) * target.y);
m_target.z = (cos(PI / 2 - amount) * up.z) + (cos(amount) * target.z);
m_up.x = (cos(amount) * up.x) + (cos(PI / 2 + amount) * target.x);
m_up.y = (cos(amount) * up.y) + (cos(PI / 2 + amount) * target.y);
m_up.z = (cos(amount) * up.z) + (cos(PI / 2 + amount) * target.z);
Normalize(m_target);
Normalize(m_up);
}
void CCamera::RotateY( float amount )
{
Point3D target = m_target;
Point3D right = m_right;
amount = amount / 180 * PI;
m_target.x = (cos(PI / 2 + amount) * right.x) + (cos(amount) * target.x);
m_target.y = (cos(PI / 2 + amount) * right.y) + (cos(amount) * target.y);
m_target.z = (cos(PI / 2 + amount) * right.z) + (cos(amount) * target.z);
m_right.x = (cos(amount) * right.x) + (cos(PI / 2 - amount) * target.x);
m_right.y = (cos(amount) * right.y) + (cos(PI / 2 - amount) * target.y);
m_right.z = (cos(amount) * right.z) + (cos(PI / 2 - amount) * target.z);
Normalize(m_target);
Normalize(m_right);
}
void CCamera::RotateZ( float amount )
{
Point3D right = m_right;
Point3D up = m_up;
amount = amount / 180 * PI;
m_up.x = (cos(amount) * up.x) + (cos(PI / 2 - amount) * right.x);
m_up.y = (cos(amount) * up.y) + (cos(PI / 2 - amount) * right.y);
m_up.z = (cos(amount) * up.z) + (cos(PI / 2 - amount) * right.z);
m_right.x = (cos(PI / 2 + amount) * up.x) + (cos(amount) * right.x);
m_right.y = (cos(PI / 2 + amount) * up.y) + (cos(amount) * right.y);
m_right.z = (cos(PI / 2 + amount) * up.z) + (cos(amount) * right.z);
Normalize(m_right);
Normalize(m_up);
}
void CCamera::Normalize( Point3D &p )
{
float length = sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
if (1 == length || 0 == length)
{
return;
}
float scaleFactor = 1.0 / length;
p.x *= scaleFactor;
p.y *= scaleFactor;
p.z *= scaleFactor;
}
The answer to this question is a combination of the following rotateTo function and a change to the code from Ray's tutorial at ( http://www.raywenderlich.com/12667/how-to-rotate-a-3d-object-using-touches-with-opengl ). As one of the comments on that article says there is an arbitrary factor of 2.0 being multiplied in GLKQuaternion Q_rot = GLKQuaternionMakeWithAngleAndVector3Axis(angle * 2.0, axis);. Remove that "2" and use the following function to create the _slerpEnd - after that the globe will rotate smoothly to XYZ specified.
// Rotate the globe using Slerp interpolation to an XYZ coordinate
- (void)rotateToLocationX:(float)x andY:(float)y andZ:(float)z {
// Turn on the interpolation for smooth rotation
_slerping = YES; // Begin auto rotating to this location
_slerpCur = 0;
_slerpMax = 1.0;
_slerpStart = _quat;
// Create a look at vector for which we will create a GLK4Matrix from
float xEye = x;
float yEye = y;
float zEye = z;
_currentSatelliteLocation = GLKMatrix4MakeLookAt(xEye, yEye, zEye, 0, 0, 0, 0, 1, 0);
// Turn our 4x4 matrix into a quat and use it to mark the end point of our interpolation
_slerpEnd = GLKQuaternionMakeWithMatrix4(_currentSatelliteLocation);
}

What is kAccelerometerMinStep?

I have been looking at the Accelerometer Graph example in the iOS Developer library and I have a question about one of the variables that is used...
#define kAccelerometerMinStep 0.02
What is the Accelerometer Min Step? and what role does it have?
Here is how it is being used in the Low Pass Filter...
-(void)addAcceleration:(UIAcceleration*)accel
{
double alpha = filterConstant;
if(adaptive)
{
double d = Clamp(fabs(Norm(x, y, z) - Norm(accel.x, accel.y, accel.z)) / kAccelerometerMinStep - 1.0, 0.0, 1.0);
alpha = (1.0 - d) * filterConstant / kAccelerometerNoiseAttenuation + d * filterConstant;
}
x = accel.x * alpha + x * (1.0 - alpha);
y = accel.y * alpha + y * (1.0 - alpha);
z = accel.z * alpha + z * (1.0 - alpha);
}
And here is how it is being used in the High Pass Filter...
-(void)addAcceleration:(UIAcceleration*)accel
{
double alpha = filterConstant;
if(adaptive)
{
double d = Clamp(fabs(Norm(x, y, z) - Norm(accel.x, accel.y, accel.z)) / kAccelerometerMinStep - 1.0, 0.0, 1.0);
alpha = d * filterConstant / kAccelerometerNoiseAttenuation + (1.0 - d) * filterConstant;
}
x = alpha * (x + accel.x - lastX);
y = alpha * (y + accel.y - lastY);
z = alpha * (z + accel.z - lastZ);
lastX = accel.x;
lastY = accel.y;
lastZ = accel.z;
}
If someone could tell me what the min step is responsible for I would be very grateful...
I would like to capture accelerations ranging in magnitude from 0.05 to 2.00 g force with a frequency response of 0.25-2.50 Hz
Thanks.!

Box2d Calculating Trajectory

I'm trying to make physics bodies generated at a random position with a random velocity hit a target. I gleaned and slightly modified this code from the web that was using chipmunk to run in Box2d
+ (CGPoint) calculateShotForTarget:(CGPoint)target from:(CGPoint) launchPos with:(float) velocity
{
float xp = target.x - launchPos.x;
float y = target.y - launchPos.y;
float g = 20;
float v = velocity;
float angle1, angle2;
float tmp = pow(v, 4) - g * (g * pow(xp, 2) + 2 * y * pow(v, 2));
if(tmp < 0){
NSLog(#"No Firing Solution");
}else{
angle1 = atan2(pow(v, 2) + sqrt(tmp), g * xp);
angle2 = atan2(pow(v, 2) - sqrt(tmp), g * xp);
}
CGPoint direction = CGPointMake(cosf(angle1),sinf(angle1));
CGPoint force = CGPointMake(direction.x * v, direction.y * v);
NSLog(#"force = %#", NSStringFromCGPoint(force));
NSLog(#"direction = %#", NSStringFromCGPoint(direction));
return force;
}
The problem is I don't know how to apply this to my program, I have a gravity of -20 for y but putting 20 for g and a lower velocity like 10 for v gets me nothing but "No Firing Solution".
What am I doing wrong?
A lower velocity of 10 is never going to work the projectile doesn't have enough power to travel the distance.
The error in the calculation is that everything is in meters except for the distance calculations which are in pixels!
Changing the code to this fixed the crazy velocities i was getting:
+ (CGPoint) calculateShotForTarget:(CGPoint)target from:(CGPoint) launchPos with:(float) velocity
{
float xp = (target.x - launchPos.x) / PTM_RATIO;
float y = (target.y - launchPos.y) / PTM_RATIO;
float g = 20;
float v = velocity;
float angle1, angle2;
float tmp = pow(v, 4) - g * (g * pow(xp, 2) + 2 * y * pow(v, 2));
if(tmp < 0){
NSLog(#"No Firing Solution");
}else{
angle1 = atan2(pow(v, 2) + sqrt(tmp), g * xp);
angle2 = atan2(pow(v, 2) - sqrt(tmp), g * xp);
}
CGPoint direction = CGPointMake(cosf(angle1),sinf(angle1));
CGPoint force = CGPointMake(direction.x * v, direction.y * v);
NSLog(#"force = %#", NSStringFromCGPoint(force));
NSLog(#"direction = %#", NSStringFromCGPoint(direction));
return force;
}