I'm trying to get some basic OpenGL-ES with Shaders to run on the iPhone, based on some examples.
For some reason my projection matrix refuses to result in something on the screen. It feels like a clipping plane is set very near but that contradicts with the values I supply. If I render the same scene with an Orthogonal projection matrix I see my object just no perspective obviously.
Here's the code that generates the projection matrix:
esPerspective(&proj, 45.f, 768.0/1024.0, 1.f, 10000.f);
void esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ)
{
float frustumW, frustumH;
frustumH = tanf( fovy / 360.0f * PI ) * nearZ;
frustumW = frustumH * aspect;
esFrustum( result, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ );
}
void esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ)
{
float deltaX = right - left;
float deltaY = top - bottom;
float deltaZ = farZ - nearZ;
ESMatrix frust;
if ( (nearZ <= 0.0f) || (farZ <= 0.0f) ||
(deltaX <= 0.0f) || (deltaY <= 0.0f) || (deltaZ <= 0.0f) )
return;
frust.m[0][0] = 2.0f * nearZ / deltaX;
frust.m[0][1] = frust.m[0][2] = frust.m[0][3] = 0.0f;
frust.m[1][1] = 2.0f * nearZ / deltaY;
frust.m[1][0] = frust.m[1][2] = frust.m[1][3] = 0.0f;
frust.m[2][0] = (right + left) / deltaX;
frust.m[2][1] = (top + bottom) / deltaY;
frust.m[2][2] = -(nearZ + farZ) / deltaZ;
frust.m[2][3] = -1.0f;
frust.m[3][2] = -2.0f * nearZ * farZ / deltaZ;
frust.m[3][0] = frust.m[3][1] = frust.m[3][3] = 0.0f;
esMatrixMultiply(result, &frust, result);
}
My projection matrix comes out as:
[3.21, 0, 0, 0]
[0, 2.41, 0, 0]
[0, 0, -1, -1]
[0, 0, -2, 0]
Even if I manually set the [3][3] cell to 1 I still don't see anything.
Any ideas?
Swap your rows and columns over (ie transpose).
Well your projection matrix is transposed either way. You have a row major projection matrix ...
Related
select objects
Camera is moved but top cut
Move the camera so that all objects are in the camera's field of view
I want to make the objects that are not the selected ones invisible and enlarge them as much as I can while making all visible objects visible
Vector3 averagePos=Vector3.zero;
for (int i = 0; i < set[num].Count; i++)
{
objectManager.SetActive(set[num][i], true);
averagePos += objectManager.ReturnPos(set[num][i]);
}
averagePos /= set[num].Count;
if (move_On)
{
angle += Time.deltaTime;
if (angle > 0.01)
angle = 0.009f;
// transform.position = Vector3.SmoothDamp(transform.position, destPos, ref velocity, smoothTime);
Vector3 ve3=Vector3.Lerp(transform.position, destPos, angle);
Debug.Log(Vector3.Distance(ve3, destPos));
if (Vector3.Distance(ve3,destPos)>1)
transform.position = Vector3.Lerp(transform.position, destPos, angle);
}
centerOfPos = new Vector3((maxPosX + minPosX) / 2, (maxPosY + minPosY) / 2, 0);
Camera.main.transform.LookAt(centerOfPos);
float hoizontalCamZ = (maxPosY + 1 - minPosY) / Mathf.Cos(Camera.main.fieldOfView / 2 * Mathf.Deg2Rad);
float verticalCamZ = (maxPosX + 1 - minPosX) / Mathf.Cos
(Mathf.Atan(Mathf.Tan(Camera.main.fieldOfView / 2 * Mathf.Deg2Rad)));
if (hoizontalCamZ < verticalCamZ)
camZ = verticalCamZ;
else
camZ = hoizontalCamZ;
Vector3 newCamPos = new Vector3(0, 0, -camZ);
I'm writing a script for an Object in Unity3D.
I want to get the volume of my object.
rigidBody = GetComponent<Rigidbody>();
I'm looking in the documentation at the attributes contained in Rigidbody but I don't see anything I can use.
I tried using bounds but I found that rotation of an object changed those values even without size changing:
int getSize(Vector3 bounds)
{
float size = bounds[0] * bounds[1] * bounds[2] * 1000;
Debug.Log("size value = " + (int)size);
return (int)size;
}
What properties can I use to calculate the volume of an object?
The math is explained here.
In C# for convencience:
float SignedVolumeOfTriangle(Vector3 p1, Vector3 p2, Vector3 p3)
{
float v321 = p3.x * p2.y * p1.z;
float v231 = p2.x * p3.y * p1.z;
float v312 = p3.x * p1.y * p2.z;
float v132 = p1.x * p3.y * p2.z;
float v213 = p2.x * p1.y * p3.z;
float v123 = p1.x * p2.y * p3.z;
return (1.0f / 6.0f) * (-v321 + v231 + v312 - v132 - v213 + v123);
}
float VolumeOfMesh(Mesh mesh)
{
float volume = 0;
Vector3[] vertices = mesh.vertices;
int[] triangles = mesh.triangles;
for (int i = 0; i < mesh.triangles.Length; i += 3)
{
Vector3 p1 = vertices[triangles[i + 0]];
Vector3 p2 = vertices[triangles[i + 1]];
Vector3 p3 = vertices[triangles[i + 2]];
volume += SignedVolumeOfTriangle(p1, p2, p3);
}
return Mathf.Abs(volume);
}
Mesh mesh = GetComponent<MeshFilter>().sharedMesh;
Debug.Log(VolumeOfMesh(mesh));
I am working on creating an Ofscreen Enemy indicator using the tutorial mentioned on below link. However I can get the indicator to rotate to point to the enemy but the indicator does not move from end to end of screen.
http://gamedevelopment.tutsplus.com/tutorials/positioning-on-screen-indicators-to-point-to-off-screen-targets--gamedev-6644
This is the desired outcome:
Until now i have managed to figure out the below Please help.
var screenCenter:Vector3 = new Vector3(0.5, 0.5, 0f);
//Note coordinates are translated
//Make 00 the centre of the screen instead of bottom left
screenpos -= screenCenter;
//find angle from center of screen instead of bototom left
var angle:float = Mathf.Atan2(screenpos.y, screenpos.x);
angle -= 90 * Mathf.Deg2Rad;
var cos:float = Mathf.Cos(angle);
var sin:float = -Mathf.Cos(angle);
screenpos = screenCenter + new Vector3(sin*150, cos*150, 0);
//y=mx + b format
var m:float = cos/sin;
var ScreenBounds:Vector3 = screenCenter;// * 0.9f;
//Check up and down first
if(cos > 0){
screenpos = new Vector3(ScreenBounds.y/m, ScreenBounds.y, 0);
}else{//down
screenpos = new Vector3(-ScreenBounds.y/m, -ScreenBounds.y, 0);
}
//If out of bound then get point on appropriate side
if(screenpos.x > ScreenBounds.x){//Out of bound must be on right
screenpos = new Vector3(ScreenBounds.x, ScreenBounds.y*m, 0);
}else if(screenpos.x < ScreenBounds.x){//Out of bound must be on left
screenpos = new Vector3(-ScreenBounds.x, -ScreenBounds.y*m, 0);
}
//Remove the co ordinate translation
screenpos += screenCenter;
var DistanceIndicatorRectT = DistanceIndicator.GetComponent(RectTransform);
DistanceIndicatorRectT.localPosition = new Vector3(screenpos.x * scrWidth/2, screenpos.y * scrHeight/2, DistanceIndicatorRectT.localPosition.z * screenpos.z);
DistanceIndicator.transform.rotation = Quaternion.Euler(0, 0, angle*Mathf.Rad2Deg);
I did a bit of a different approach than you, what Carlos suggested but without using physics.
If "t" is your target, this way you can get it's position on screen in pixels (if it's off screen it just goes to negative values or values higher that width)
Vector3 targetPosOnScreen = Camera.main.WorldToScreenPoint (t.position);
And this function that return a bool whether the Vector3 (in pixels) is on screen
bool onScreen(Vector2 input){
return !(input.x > Screen.width || input.x < 0 || input.y > Screen.height || input.y < 0);
}
First thing we should do is check if the target is on screen, if it's not then proceed with code.
if (onScreen (targetPosOnScreen)) {
//Some code to destroy indicator or make it invisible
return;
}
Then a simple calculation of angle between center of screen and target.
Vector3 center = new Vector3 (Screen.width / 2f, Screen.height / 2f, 0);
float angle = Mathf.Atan2(targetPosOnScreen.y-center.y, targetPosOnScreen.x-center.x) * Mathf.Rad2Deg;
Next part of code determines where the object is compared to camera based on angle we just calculated.
float coef;
if (Screen.width > Screen.height)
coef = Screen.width / Screen.height;
else
coef = Screen.height / Screen.width;
float degreeRange = 360f / (coef + 1);
if(angle < 0) angle = angle + 360;
int edgeLine;
if(angle < degreeRange / 4f) edgeLine = 0;
else if (angle < 180 - degreeRange / 4f) edgeLine = 1;
else if (angle < 180 + degreeRange / 4f) edgeLine = 2;
else if (angle < 360 - degreeRange / 4f) edgeLine = 3;
else edgeLine = 0;
http://s23.postimg.org/ytpm82ad7/Untitled_1.png
Image represents what value "edgeLine" will have based on target position (red represents camera's view) and black lines division of space.
And then we have this code which sets Transform "t2" (indicator) to correct position and angle.
t2.position = Camera.main.ScreenToWorldPoint(intersect(edgeLine, center, targetPosOnScreen)+new Vector3(0,0,10));
t2.eulerAngles = new Vector3 (0, 0, angle);
Below we have function "intersect" which code is:
Vector3 intersect(int edgeLine, Vector3 line2point1, Vector3 line2point2){
float[] A1 = {-Screen.height, 0, Screen.height, 0};
float[] B1 = {0, -Screen.width, 0, Screen.width};
float[] C1 = {-Screen.width * Screen.height,-Screen.width * Screen.height,0, 0};
float A2 = line2point2.y - line2point1.y;
float B2 = line2point1.x - line2point2.x;
float C2 = A2 * line2point1.x + B2 * line2point1.y;
float det = A1[edgeLine] * B2 - A2 * B1[edgeLine];
return new Vector3 ((B2 * C1[edgeLine] - B1[edgeLine] * C2) / det, (A1[edgeLine] * C2 - A2 * C1[edgeLine]) / det, 0);
}
We send to this function index of which line of camera's view (rectangle) we need to check intersection with, and construct a line between center of screen and target position.
For better explanation of this function look here : https://www.topcoder.com/community/data-science/data-science-tutorials/geometry-concepts-line-intersection-and-its-applications/
I just modified values of A1, B1 and C1, each of them is now array of 4 and each values represents value needed for one line of camera's view (rectangle).
If you want to implement margins just change the pivot of indicator (put the actual sprite renderer as child and move it in local space as you want).
Next thing would be making this work for array of targets and putting all those targets in given array. Hope this helps and don't be too hard on me, it's my first time posting here :)
Create a rectangle box collider delimiting the borders of the screen and use Physics2D.Raycast in the direction of the enemy.
The point of collision will tell you where the green arrow needs to be drawn.
In the example above, there is an error with the definition of the angle of visibility of a straight rectangle.
private void SetIndicatorPosition(Indicator obj)
{
var target = obj.Target;
var indicator = obj.PointToTarget;
if (target == null)
{
indicator.SetActive(false);
return;
}
Vector3 targetPosOnScreen = cam.WorldToScreenPoint(target.transform.position);
if (onScreen(targetPosOnScreen))
{
indicator.SetActive(false);
return;
}
indicator.SetActive(true);
Vector3 center = new Vector3(Screen.width / 2f, Screen.height / 2f, 0);
float angle = Mathf.Atan2(targetPosOnScreen.y - center.y, targetPosOnScreen.x - center.x) * Mathf.Rad2Deg;
float scale;
if (Screen.width > Screen.height)
scale = Screen.width / Screen.height;
else
scale = Screen.height / Screen.width;
float degreeRange = 360f / (scale + 1);
float angle2 = Mathf.Atan2(Screen.height - center.y, Screen.width - center.x) * Mathf.Rad2Deg;
if (angle < 0) angle = angle + 360;
int edgeLine;
if (angle < angle2) edgeLine = 0;
else if (angle < 180 - angle2) edgeLine = 1;
else if (angle < 180 + angle2) edgeLine = 2;
else if (angle < 360 - angle2) edgeLine = 3;
else edgeLine = 0;
indicator.transform.position = Camera.main.ScreenToWorldPoint(Intersect(edgeLine, center, targetPosOnScreen));
indicator.transform.eulerAngles = new Vector3(0, 0, angle);
}
Vector3 Intersect(int edgeLine, Vector3 line2point1, Vector3 line2point2)
{
float[] A1 = { -Screen.height, 0, Screen.height, 0 };
float[] B1 = { 0, -Screen.width, 0, Screen.width };
float[] C1 = { -Screen.width * Screen.height, -Screen.width * Screen.height, 0, 0 };
float A2 = line2point2.y - line2point1.y;
float B2 = line2point1.x - line2point2.x;
float C2 = A2 * line2point1.x + B2 * line2point1.y;
float det = A1[edgeLine] * B2 - A2 * B1[edgeLine];
var x = (B2 * C1[edgeLine] - B1[edgeLine] * C2) / det;
var y = (A1[edgeLine] * C2 - A2 * C1[edgeLine]) / det;
return new Vector3(x, y, 0);
}
bool onScreen(Vector2 input)
{
return !(input.x > Screen.width || input.x < 0 || input.y > Screen.height || input.y < 0);
}
public class Indicator
{
public GameObject Target { get; private set; }
public GameObject PointToTarget { get; private set; }
public Indicator(GameObject target, GameObject pointToTarget, ObjectTypeEnum type)
{
Target = target;
PointToTarget = pointToTarget;
var texture = pointToTarget.GetComponentInChildren<UITexture>();
if (texture != null)
{
texture.color = Helper.GetHintColor(type);
}
}
}
You can call in update
foreach (var obj in listIndicator)
{
SetIndicatorPosition(obj);
}
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);
}
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;
}