Correctly rendering a mirror in XNA - c#

I have my code I wrote for displaying a mirror as a plane with a texture from a RenderTarget2D each frame.
This all works perfectly fine, but I still think that there is something wrong in the way the reflection goes (like, the mirror isn't looking exacly where it's supposed to be looking).
There's a screenshot of the mirror that doesn't really look bad, the distort mainly occurs when the player gets close to the mirror.
Here is my code for creating the mirror texture, notice that the mirror is rotated by 15 degrees on the X axis.
RenderTarget2D rt;
...
rt = new RenderTarget2D(device, (int)(graphics.PreferredBackBufferWidth * 1.5), (int)(graphics.PreferredBackBufferHeight * 1.5));
...
device.SetRenderTarget(rt);
device.Clear(Color.Black);
Vector3 camerafinalPosition = camera.position;
if (camera.isCrouched) camerafinalPosition.Y -= (camera.characterOffset.Y * 6 / 20);
Vector3 mirrorPos = new Vector3((room.boundingBoxes[8].Min.X + room.boundingBoxes[8].Max.X) / 2, (room.boundingBoxes[8].Min.Y + room.boundingBoxes[8].Max.Y) / 2, (room.boundingBoxes[8].Min.Z + room.boundingBoxes[8].Max.Z) / 2);
Vector3 cameraFinalTarget = new Vector3((2 * mirrorPos.X) - camera.position.X, (2 * mirrorPos.Y) - camerafinalPosition.Y, camera.position.Z);
cameraFinalTarget = Vector3.Transform(cameraFinalTarget - mirrorPos, Matrix.CreateRotationX(MathHelper.ToRadians(-15))) + mirrorPos;
Matrix mirrorLookAt = Matrix.CreateLookAt(mirrorPos, cameraFinalTarget, Vector3.Up);
room.DrawRoom(mirrorLookAt, camera.projection, camera.position, camera.characterOffset, camera.isCrouched);
device.SetRenderTarget(null);
And then the mirror is being drawn using the rt texture.
I supposed something isn't completly right with the reflection physics or the way I create the LookAt matrix, Thanks for the help.

I didn't use XNA, but I did some Managed C# DX long time ago, so I don't remember too much, but are you sure mirrorLookAt should point to a cameraFinalTarget? Because basically the Matrix.CreateLookAt should create a matrix out of from-to-up vectors - 'to' in your example is a point where mirror aims. You need to calculate a vector from camera position to mirror position and then reflect it, and I don't see that in your code.
Unless your room.DrawRoom method doesn't calculate another mirrorLookAt matrix, I'm pretty sure your mirror target vector is the problem.
edit: Your reflection vector would be
Vector3 vectorToMirror = new Vector3(mirrorPos.X-camera.position.Y, mirrorPos.Y-camera.position.Y, mirrorPos.Z-camera.position.Z);
Vector3 mirrorReflectionVector = new Vector3(vectorToMirror-2*(Vector3.Dot(vectorToMirror, mirrorNormal)) * mirrorNormal);
Also I don't remember if the mirrorReflectionVector shouldn't be inverted (whether it is pointing to mirror or from mirror). Just check both ways and you'll see. Then you create your mirrorLookAt from
Matrix mirrorLookAt = Matrix.CreateLookAt(mirrorPos, mirrorReflectionVector, Vector3.Up);
Though I don't know wher the normal of your mirror is. Also, I've noticed 1 line I can't really understand
if (camera.isCrouched) camerafinalPosition.Y -= (camera.characterOffset.Y * 6 / 20);
What's the point of that? Let's assume your camera is crouched - shouldn't its Y value be lowered already? I don't know how do you render your main camera, but look at the mirror's rendering position - it's way lower than your main eye. I don't know how do you use your IsCrouched member, but If you want to lower the camera just write yourself a method Crouch() or anything similar, that would lower the Y value a little. Later on you're using your DrawRoom method, in which you pass camera.position parameter - yet, it's not "lowered" by crouch value, it's just "pure" camera.position. That may be the reason it's not rendering properly. Let me know If that helped you anything.

Related

How to Spawn objects only in a certain radius / unity2d

I'm very new to programming and i need to make sure that the objects only spawn inside of a certain radius, I've come up with this solution:
Vector2 incircle = Random.insideUnitCircle * 10;
That works just fine, but the problem is that I want to make sure that no objects can spawn directly next to the Player. Like a small inner circle where nothing can spawn?
Something like this maybe (didn't actually check, but I think that will work)
Vector2 incircle = Random.insideUnitCircle * (10 - reservedRadius);
incircle = incircle + incircle.normalized * reservedRadius;
Assuming reservedRadius is the radius around the player

Unity C# Trig Functions in movement

I'm creating an fps game in unity and chose to not use the included First Person Controller script to reduce complexity. The camera object will constantly be set to the players position and can rotate. I have created a script containing the following code for movement:
float v = Input.GetAxis("Vertical");
float h = Input.GetAxis("Horizontal");
Vector2 rotation = new Vector2(
Mathf.Cos(cam.transform.eulerAngles.y * deg2rad), (Mathf.Sin(cam.transform.eulerAngles.y * deg2rad))
);
rb.velocity = (
new Vector3(
(-rotation.x * h * speed) + (rotation.y * v * speed),
rb.velocity.y,
(-rotation.y * h * speed) + (-rotation.x * v * speed)
)
);
When I test out the game, the movement is correct along the x-axis in both directions, but is unusual when the players y rotation becomes something other than being aligned with the x-axis (Like moving the player backwards will actually move them forwards and visa-versa).
I'm open to an alternative besides using trig functions for the movement, as I have already used transform.forward and transform.right, but they didn't work entirely.
First thing I'd say is that unless you're intending to learn trig and geometrical functions then you should not reinvent the wheel. As you've stated you want to create a FPS game so really you should leverage the scripts and prefabs that others have created to enable the creation of your game.
If you don't want to use the inbuilt FPS Controller script I'd recommend using a free Asset package named '3rdPerson+Fly'. It appears a bit complex at first however you'll learn about states and stackable behaviours/modes which is going to get you an outcome much faster than creating from scratch. You'll also get the flexibility and openness that comes with a non-inbuilt package. This way you can peek at the inner workings if desired or simply build on top of them. Don't fall for NIH (Not Invented Here) syndrome and stand on the shoulders of giants instead :)
Good luck!
The issue you're having is likely caused by the fact that sin and cos can't determine by themselves which "quadrant" they're in. For example 30 degree angle is the same as a 150 degree angle as far as Sin is concerned.
This video is a fast and good explanation of the issue:
https://www.youtube.com/watch?v=736Wkg8uxA8

How to determine an 360° angle from relative direction?

I have a minimap on the screen and having problems to determine the angle to a target relative to the camera.
Here is some drawing of what I mean with some examples of camera position and direction:
The black triangles represent the camera.
The black arrows define their forward direction.
The blue arrows are the direction to the target (= red dot in the middle) from the camera.
The circles in the specific cameras define the wanted orientation of its red dot.
Here's my code so far:
//Anchored position around minimap circle
void CalculateScreenPos(){
Vector3 dir = transform.position - cam.position; //xz distance
dir.y = 0;
angle = Angle360(cam.forward.normalized, dir.normalized, cam.right);
Vector2 desiredPosition = new Vector2(
eX * -Mathf.Cos(angle * Mathf.PI/180f) * dir.z,
eY * Mathf.Sin(angle * Mathf.PI/180f) * dir.x
);
minimapBlip.anchoredPosition = desiredPosition;
}
public static float Angle360(Vector3 from, Vector3 to, Vector3 right)
{
float angle = Vector3.Angle(from, to);
return (Vector3.Angle(right, to) > 90f) ? 360f - angle : angle;
}
But the angle seems not working properly, found out that it ranges from
0° + cam.eulerXAngles.x to 360° - cam.eulerAngles.x
So it works when the cam is never looking to the ground or sky.
How do I get rid of the unwanted added x-eulerAngles by not substracting/adding it again to the angle?
angle -= cam.transform.eulerAngles.x
is a bad choice as when the result of Angle360 is 360, it gets substracted again, leading immediatly to a wrong angle.
Also the circle can be an ellipsoid, that's why I have put eX and eY in the desired position that determine the extends of the ellipse.
I don't know what data type you are using e.g. cam.position, cam.heading, etc. but some general guidance that will help you debug this problem.
Write a unit test. Prepare some canned data, both for input (e.g. set cam.position/cam.heading, transform, etc.) and output (the expected angle). Do this for a few cases, e.g. all the six examples you've shown. This makes it easier to repeat your test, and understand which case isn't working - you might see a pattern. It also makes it easy to run your code through a debugger.
Break your functions into logical units of work. What does Angle360 do? I guess you understand what it is supposed to do, but I think it is really two functions
Get the angle between the two vectors (current direction and target direction)
Rotate map (or something like that)
Write tests for those broken out functions. You're just using some library angle difference function - is it behaving as you expect?
Name your variables. You have a vector called right - what is that? There's no comment. Is it right as in 'correct', or as in 'opposite of left'? Why is it Vector3.Angle(right, to), and why not Vector3.Angle(to, right)?
Generally you are performing some math and getting tripped up because your code is not clear, things are not well named, and the approach is not clear. Break the problem into smaller pieces and the issue will become obvious.
I solved it:
angle = Mathf.Atan2(heading.x, heading.z) * Mathf.Rad2Deg-Camera.main.transform.eulerAngles.y;
Vector2 desiredPosition = new Vector2(
eX * -Mathf.Cos((angle+90) * Mathf.Deg2Rad),
eY * Mathf.Sin((angle+90) * Mathf.Deg2Rad)
);
Thanks for the help so far and happy coding :D

Perspective Projection

Few days ago I decided to start in 3D programming and came across perspective projection.
I use the following code to get the matrix:
public static Matrix3D ProjectionMatrix(double angle, double aspect, double near, double far)
{
double size = near * Math.Tan(MathUtils.DegreeToRadian(angle) / 2.0);
double left = -size, right = size, bottom = -size / aspect, top = size / aspect;
Matrix3D m = new Matrix3D(new double[,] {
{2*near/(right-left),0,(right + left)/(right - left),0},
{0,2*near/(top-bottom),(top+bottom)/(top-bottom),0},
{0,0,-(far+near)/(far-near),-(2 * far * near) / (far - near)},
{0,0,-1,0}
});
return m;
}
I use the following code for the camera:
Matrix3D Camera
{
get
{
Vector3D cameraZAxis = -this.LookDirection;
cameraZAxis.Normalize();
Vector3D cameraXAxis = Vector3D.CrossProduct(this.UpDirection, cameraZAxis);
cameraXAxis.Normalize();
Vector3D cameraYAxis = Vector3D.CrossProduct(cameraZAxis, cameraXAxis);
Vector3D cameraPosition = (Vector3D)this.Position;
double offsetX = -Vector3D.DotProduct(cameraXAxis, cameraPosition);
double offsetY = -Vector3D.DotProduct(cameraYAxis, cameraPosition);
double offsetZ = -Vector3D.DotProduct(cameraZAxis, cameraPosition);
return new Matrix3D(new double[,]{{cameraXAxis.X, cameraYAxis.X, cameraZAxis.X, 0},
{cameraXAxis.Y, cameraYAxis.Y, cameraZAxis.Y, 0},
{cameraXAxis.Z, cameraYAxis.Z, cameraZAxis.Z, 0},
{offsetX, offsetY, offsetZ, 1}});
}
}
However, I don't know how to get the Model or World Matrix, also is there anything wrong with the previous code?
A Matrix is used to transform an object from one "space" into another. Think of a Model which is a cube, the model center is 0,0,0 and each corner is at an extent of 5. Now to transform that into your world you would apply a Worldmatrix with the transformation to put these model coordinates into your world.
A translation for example which should "move" the model to 5, 5, 5. Now just think of adding this position to your model and all its points, and now these new coordinates are called "in world space". Now the model is, via your World matrix placed in the world at position 5,5,5 (your former model center resides now in your world at this position).
The view matrix is a little bit tricky to understand, but the easiest is to think of "We can't move a camera, so we move all ojects in the opposite direction so it looks like we moved the camera". This sounds difficult, but in fact its the same like transforming from model space to world space.
Now we transform from World space into view space. Finally, we need to get it on the screen. Obviously your screen is 2D and you still have a 3D scene, now you need a way to transform your 3D objects into your view space. This can be achieved with different kinds of projection. The two important ones are orthogonal projection and perspective projection. In fact this uses the Z component( which we don't have on a 2D surface like a screen) and the screen resolution to "project" our visible world into our screen space.
All this is easily accomplished using matrices. One for each transformation is a good start. To be fair, you don't need any of it, you could directly supply your data in screen space, but this wouldn't be practical. If you don't need a World matrix for example, which happens if your model is modeled so that it could be used directly, you would use an Matrix.Identity which, can roughly be interpreted as multiplying a number by 1 which gives you the same number. Also an Identity Matrix for the view is like having the camera placed in the world on 0,0,0 and looking down the Z axis (which axis heavly depends on the coordinate system you use)
To get the final matrix for a shader you usually pass all these matrices (or a combined one via multiplication) to your shader. If you use the fixed function pipeline there are usually methods to supply them. The projection is usually fixed, but could be changed to apply some visual effects like zooming a sniper rifle or a fisheye effect. The camera matrix of course is used to move and rotate the camera. And the world matrix is used to position your objects in the scene, move players, rotate doors etc.
Disclaimer: This is how i understood the whole thing for myself, so it is by no means a mathematical correct explanation, but maybe it is of any help for the OP.
To get a better understanding of the whole subject you can read this.

C# XNA - Calculating next point in a vector direction

lets say i have two points A & B in my 3D Space
now i want to start calculate points from A to B in direction of B and i want to continue calculation farther from B on the same line.
How t do it ?
what i am actually working on is bullets from plane.
If I understood your question correctly, you should first get the direction vector by calculating
dir = B - A
and then you can continue the travel by
C = B + dir
Otherwise, please clarify your question, like for example what you mean by "calculate points from A to B", because mathematically there is an infinite amount of points between A and B.
Edit:
If you want to trace a bullet path you have two options:
1) You implement it as hitscan weapon like done in many FPS; any bullets fired will immediately hit where they were aimed. This can be best achieved by doing a raytrace via Ray.Intersects and is probably the simplest and least computationally intensive way to do it. Of course, it's also not terribly realistic.
2) You make the bullet a physical entity in your world and move it during your Update() call via a "normal" combination of current position vector and movement/velocity vector, doing a manual collision detection with any hittable surfaces and objects. The advantage of this is that you can implement proper physics like travel time, drop, friction, etc., however it is also orders of magnitude more difficult to implement in a robust way. If you want to go this way, I suggest using either a pre-made physics API (like Bullet, but I'm not sure if there's a version for XNA) or at least doing extensive Google research on the subject, so you can avoid the many pitfalls of collision detection with fast-moving objects.
its a try to implement a 2D technique in 3D, i calculate the following once
position = start;
dx = destination.X - start.X;
dy = destination.Y - start.Y;
dz = destination.Z - start.Z;
distance = (float)Math.Sqrt( dx * dx + dy * dy + dz * dz );
scale = 2f / distance;
then i go on calculating
position.X += dx * scale;
position.Y += dy * scale;
position.Z += dz * scale;
but the result is still is not working of 3D Space, i am getting result for only 2 Dimension, the third axis is not being changed

Categories

Resources