I have a simple paddle that I am trying to move along the X axis using the mouse. Currently it moves but is off by a large margin, relative to where the mouse is.
I think it is due the fact that half my screen is -7.5 and the other half is 7.5
I was wondering if there is any way to correct this problem. As you can see from my code I am multiplying by 16, which would be the width if the other half was not negative.
I can move the whole screenplay to make it not negative, so I was hoping there was a function
Vector3 paddlePos = new Vector3 (0f, this.transform.position.y , -0.25f);
float mousePosInBlocks = Input.mousePosition.x / Screen.width * 16;
paddlePos.x = Mathf.Clamp(mousePosInBlocks, -7.5f, 7.5f);
this.transform.position = paddlePos;
Use this code -
Vector3 paddlePos = new Vector3 (0f, this.transform.position.y , -0.25f);
float mousePosInBlocks = Input.mousePosition.x / Screen.width * 16;
paddlePos.x = Mathf.Clamp((mousePosInBlocks - 7.5f), -7.5f, 7.5f);
this.transform.position = paddlePos;
Mathf.clamp function only returns the value inside the minimum and maximum value range. While you need the mousePosInBlocks value to consider the negative and positive screen space.
Related
I have a hemisphere with radius 250.
Located on the edge of the hemisphere (15 degrees above the base/horizon), I have 7 equally spaced points (i.e., 1 point every 360/7 degrees).
Using Unity3D, I want to place camera at each of those 7 points such that their FoV is perpendicular/orthogonal to the surface of the sphere.
Given camera number (1,2,3...7) and the radius of the hemisphere (250), what function will place the cameras in the correct position and facing the correct direction?
pointCount = 7;
tilt = 15;
radius = 250;
void PositionCamera(int pointCount, int pointId, float radius, float tilt, Transform camera){
Vector3 temp = Vector3.forward * radius;
temp = Quaternion.Euler(tilt, 0, 0) * temp;
temp = Quaternion.Euler(0, 360/pointCount*pointId, 0) * temp;
camera.position = temp + camera.parent.position;
camera.rotation = Quaternion.LookRotation(temp);
}
Assuming that the center of the hemisphere is at origin and the first point on the z axis.
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.)
I'm trying to calculate the position on the ground that a camera is looking at (without doing a raytrace since I know the forward vector of the camera and the height of the ground). I tried doing this using the dot product but I still seem to be getting the wrong answer. This is what I did with the values I was testing with:
const float groundHeight = 0f;
Vector3 cameraPosition = new Vector3(0f, 3f, 0f);
Vector3 cameraForward = new Vector3(0f, -0.7f, 0.7f); //Unit vector
Vector3 positionOnGround = cameraPosition;
positionOnGround.y = groundHeight;
Vector3 cameraToGround = positionOnGround - cameraPosition;
float scalar = Vector3.Dot(cameraToGround, cameraForward);
Vector3 forwardToGround = cameraForward * scalar;
return cameraPosition + forwardToGround;
For some reason this is giving me the position 0, 1.5, 1.5 when I'm looking for something that has a height of 0. Any ideas of what I'm doing wrong?
Let's define:
camera is located at point C.
camera is looking at its target point on the ground (P) (you want to find P)
camera distance from ground yC = camera.transform.position.y
camera projection on the ground (G)
distance of p from G (zP)
angle of GCP is a. which in your case it's 45 degrees since CP is (0f, -0.7f, 0.7f)
Now
tan(a) = magnitude(PG) / magnitude(CG)
= zP / yC
= zP / camera.transform.position.y
P = new Vector3(xP,yP,zP)
= new Vector3(xC,0,zP)
= new Vector3(camera.transform.position.x, 0, tan(a)*camera.transform.position.y)
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?
I've been trying to combine these two samples from David Amador:
http://www.david-amador.com/2010/03/xna-2d-independent-resolution-rendering/
http://www.david-amador.com/2009/10/xna-camera-2d-with-zoom-and-rotation/
Everything is working fine except I'm having some difficulty getting the mouse coordinates. I was able to get them for each individual sample, but my math for taking both into account seems to be wrong.
The mouse coordinates ARE correct if my virtual resolution and normal resolution are the same. It's when I do something like Resolution.SetVirtualResolution(1920, 1080)
and Resolution.SetResolution(1280, 720, false) when the coordinates slowly get out of sync as I move the camera.
Here is the code:
public static Vector2 MousePositionCamera(Camera camera)
{
float MouseWorldX = (Mouse.GetState().X - Resolution.VirtualWidth * 0.5f + (camera.position.X) * (float)Math.Pow(camera.Zoom, 1)) /
(float)Math.Pow(camera.Zoom, 1);
float MouseWorldY = ((Mouse.GetState().Y - Resolution.VirtualHeight * 0.5f + (camera.position.Y) * (float)Math.Pow(camera.Zoom, 1))) /
(float)Math.Pow(camera.Zoom, 1);
Vector2 mousePosition = new Vector2(MouseWorldX, MouseWorldY);
Vector2 virtualViewport = new Vector2(Resolution.VirtualViewportX, Resolution.VirtualViewportY);
mousePosition = Vector2.Transform(mousePosition - virtualViewport, Matrix.Invert(Resolution.getTransformationMatrix()));
return mousePosition;
}
In resolution I added this:
virtualViewportX = (_Device.PreferredBackBufferWidth / 2) - (width / 2);
virtualViewportY = (_Device.PreferredBackBufferHeight / 2) - (height / 2);
Everything else is the same as the sample code. Thanks in advance!
Thanks to David Gouveia I was able to identify the problem... My camera matrix was using the wrong math.
I'm going to post all of my code with the hopes of helping someone who is trying to do something similar.
Camera transformation matrix:
public Matrix GetTransformMatrix()
{
transform = Matrix.CreateTranslation(new Vector3(-position.X, -position.Y, 0)) * Matrix.CreateRotationZ(rotation) *
Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) * Matrix.CreateTranslation(new Vector3(Resolution.VirtualWidth
* 0.5f, Resolution.VirtualHeight * 0.5f, 0));
return transform;
}
That will also center the camera. Here's how you get the mouse coordinates combining both the Resolution class and camera class:
public static Vector2 MousePositionCamera(Camera camera)
{
Vector2 mousePosition;
mousePosition.X = Mouse.GetState().X;
mousePosition.Y = Mouse.GetState().Y;
//Adjust for resolutions like 800 x 600 that are letter boxed on the Y:
mousePosition.Y -= Resolution.VirtualViewportY;
Vector2 screenPosition = Vector2.Transform(mousePosition, Matrix.Invert(Resolution.getTransformationMatrix()));
Vector2 worldPosition = Vector2.Transform(screenPosition, Matrix.Invert(camera.GetTransformMatrix()));
return worldPosition;
}
Combined with all of the other code I posted/mentioned this should be all you need to achieve resolution independence and an awesome camera!