How do you map the points on a normalized sphere (radius of 0.5, center of 0,0,0) to a fish eye texture image? I am using the C# language and OpenGL. The results should be UV coordinates for the image. The sphere is simply a list of 3D coordinates for each vertice of the sphere, so each of these would get a UV coordinate in to the image.
The end results would be a full sphere with the fish eye image wrapping all the way around 360 degrees when textured on to the sphere.
Example fish eye image:
There isn't a single way to map to a sphere. The texture in your post looks like the seam would be up in a nominated world plane. Compare that to a typical skydome type texture, where the sphere usually joins at the bottom (where the camera cant see the join).
You might use shader code like this to map a point based on UV:
float3 PointOnSphere(float phi, float theta, float radius)
{
float3 pos = float3(0, 0, 0);
pos.x = radius * cos(phi) * sin(theta);
pos.y = radius * sin(phi) * sin(theta);
pos.z = radius * cos(theta);
return pos;
}
Or reverse that to get UV from a point on the surface:
float2 AngleFromPoint(float3 pos)
{
float phi = atan(pos.y / pos.x);
float theta = atan(pos.y / pos.z / sin(phi));
return(float2(phi, theta));
}
Which way is up and where the seam joins is something you'll have to workout yourself. If the texture looks compressed because it is non linear you may need to try something like:
texcoord = pow(texcoord, 0.5f);
Edit: and obviously, normalise the angles to 0 - 1 for texture coordinates
Related
Example Image here
I am trying to find a way to calculate points on my cylinders top circle surface. My situation looks like this, I have a vector which is defining my cylinders direction in 3d room. Then I already calculated me a perpendicular vector with
Vector3.Cross(vector1, vector2)
Now I use the diameter/2 to calculate the point which is lying on the edge of the circular top surface of my cylinder. Now I want to rotate my vector always 90 degrees in order to get 4 points on the edge of the surface. All the 4 vectors defining them should be perpendicular to the cylinders direction. Can you help me how I can rotate the first perpendicular to achieve this?
I already tried:
Matrix4x4.CreateFromAxisAngle(vectorcylinderdirection, radiant)
Then I calculated again cross product but it doesnt work like I want to.
Edit:
public static void calculatePontsOnCylinder()
{
//Calculate Orthogonal Vector to Direction
Vector3 tCylinderDirection = new Vector3(1, 0, 0);
Vector3 tOrthogonal = Vector3.Cross(tCylinderDirection, new Vector3(-tCylinderDirection.Z,tCylinderDirection.X,tCylinderDirection.Y));
Vector3 tNormOrthogonal = Vector3.Normalize(tOrthogonal);
//Calculate point on surface circle of cylinder
//10mm radius
int tRadius = 10;
Vector3 tPointFinder = tNormOrthogonal * tRadius;
//tPointFinder add the cylinder start point
//not yet implemented
//now i need to rotate the vector always 90 degrees to find the 3 other points on the circular top surface of the cylinder
//don't know how to do this
// I thought this should do it
Matrix4x4.CreateFromAxisAngle(tCylinderDirection, (float)DegreeToRadian(90));
}
private static double DegreeToRadian(double angle)
{
return Math.PI * angle / 180.0;
}
In the picture you can see a example, the vector1 is what I need, always rotated 90 degrees and vector2 would be my cylinder direction vector
I possibly have found the correct formula:
Vector3 tFinal = Vector3.Multiply((float)Math.Cos(DegreeToRadian(90)), tPointFinder) + Vector3.Multiply((float)Math.Sin(DegreeToRadian(90)), Vector3.Cross(tCylinderDirection, tPointFinder));
Vector3 tFinal180 = Vector3.Multiply((float)Math.Cos(DegreeToRadian(180)), tPointFinder) + Vector3.Multiply((float)Math.Sin(DegreeToRadian(180)), Vector3.Cross(tCylinderDirection, tPointFinder));
Vector3 tFinal270= Vector3.Multiply((float)Math.Cos(DegreeToRadian(270)), tPointFinder) + Vector3.Multiply((float)Math.Sin(DegreeToRadian(270)), Vector3.Cross(tCylinderDirection, tPointFinder));
Interesting is that if I try it with (1,1,0) as cylinder direction it gives me correct directions but the length is different for 90 degrees and 270.
Here is the code that should solve your problem assuming that the input requirements are satisfied.
float zCutPlaneLocation = 20; // should not get bigger than cylinder length
float cylinderRadius = 100;
Vector3 cylinderCenter = new Vector3(0, 0, 0); // or whatever you got as cylinder center point, given as Vector3 since Point type is not defined
// will return 360 points on cylinder edge, corresponding to this z section (cut plane),
// another z section will give another 360 points and so on
List<Vector3> cylinderRotatedPointsIn3D = new List<Vector3>();
for (int angleToRotate = 0; angleToRotate < 360; angleToRotate++)
{
cylinderRotatedPointsIn3D.Add(GetRotatedPoint(zCutPlaneLocation, angleToRotate, cylinderRadius, cylinderCenter));
}
....
private static Vector3 GetRotatedPoint(
float zLocation, double rotationAngleInRadian, float cylinderRadius, Vector3 cylinderCenter)
{
Vector2 cylinderCenterInSection = new Vector2(cylinderCenter.X, cylinderCenter.Y);
float xOfRotatedPoint = cylinderRadius * (float)Math.Cos(rotationAngleInRadian);
float yOfRotatedPoint = cylinderRadius * (float)Math.Sin(rotationAngleInRadian);
Vector2 rotatedVector = new Vector2(xOfRotatedPoint, yOfRotatedPoint);
Vector2 rotatedSectionPointOnCylinder = rotatedVector + cylinderCenterInSection;
Vector3 rotatedPointOnCylinderIn3D = new Vector3(
rotatedSectionPointOnCylinder.X,
rotatedSectionPointOnCylinder.Y,
zLocation + cylinderCenter.Z);
return rotatedPointOnCylinderIn3D;
}
I just created a console app for this. First part of code should be added in main method.
Working with those matrices seems is not that easy. Also I am not sure if your solution works ok for any kind of angle.
Here the idea is that the rotated points from cylinder are calculated in a section of the cylinder so in 2D than the result is moved in 3D by just adding the z where the Z section was made on cylinder. I suppose that world axis and cylinder axis are on the same directions. Also if your cylinder gets along (increases) on the X axis, instead of Z axis as in example just switch in code the Z with X.
I attached also a picture for more details. This should work if you have the cylinder center, radius, rotation angle and you know the length of the cylinder so that you create valid Z sections on cylinder. This could get tricky for clockwise/counter clock wise cases but lets see how it works for you.
If you want to handle this with matrices or whatever else I think that you will end up having this kind of result. So I think that you cannot have "all" the rotated points in just a list for the entire cylinder surface, they would depend on something like the rotated points of a Z section on the cylinder.
I am getting 2d coordinates from Vector3. I have to correct positions to get right results. Indeed it seems I get correct positions like this but I do not know how to correct position when rotated.
Here my worldViewMatrix that I do operations but those operations not passed to my VertexData then I try to correct positions.
WorldViewMatrix = Matrix.Scaling(Scale) * Matrix.RotationX(Rotation.X) * Matrix.RotationY(Rotation.Y) * Matrix.RotationZ(Rotation.Z) * Matrix.Translation(Position.X, Position.Y, Position.Z) * viewProj;
I am trying to correct it like:
public Vector2 Convert_3Dto2D(Vector3 position, Vector3 translation, Vector3 scale, Vector3 rotation, Matrix viewProj, RenderForm_EX form)
{position += translation;
position += translation;
position = Vector3.Multiply(position, scale);
//ROTATION ?
var project = Vector3.Project(position, 0, 0, form.ClientSize.Width, form.ClientSize.Height, 0, 1, viewProj);
Console.WriteLine(project.X+" "+ project.Y);
return new Vector2(project.X, project.Y);
}
What can I do to correct rotated position ?
If you can, post a little more information about "correct positions". I will take a stab at this and assume you want to move your vertex into world space, then work out what pixel it occupies.
Usually you order multiplying your order by
Translate * Rotate * Scale;
if you want Viewprojection to apply correctly, I believe it should be at the start. V * (t * r * s).
The following link on gamedev stackexchange goes into this. matrix order
Also, your project takes in a Vector3 that has been already multiplied into wvp matrix, I dont see you have multiplied it in your convert_3dto2d function.
Basically, execute a TRS matrix multiply on your original vert, then multiply your WVP matrix then execute your project. You will then get your screen space pixel.
Context
I have some DMX spotlights fixed to a round platform located at 12 meters above the floor. A camera is fixed to the centre (approximately) of this platform. The camera is supposed to film the ground to find and track some targets. This camera is static and give me a 2D plan with an X/Y Cartesian coordinates system. When I found a target, I need to put a spotlight on it.
Illustration
Top view of the scene
Top View Image http://img15.hostingpics.net/pics/635699691.png
Side view of the scene
Side View Image http://img15.hostingpics.net/pics/275272232.png
Problem
To light a target with a spotlight, I need to find the Pan and Tilt angles corresponding of the X/Y position of this target. These spotlights have no specific orientation, but I can find the X/Y projection point of its on the ground with the camera.
Some Data
I found some formulas on the web :
float radius = sqrt( x*x + y*y + z*z );
float inclination = atan2( y, x ) * 180.0 / PI;
float azimuth = acos( z/radius ) * 180.0 / PI;
or
rotx = Math.atan2( y, z )
roty = Math.atan2( x * Math.cos(rotx), z )
rotz = Math.atan2( Math.cos(rotx), Math.sin(rotx) * Math.sin(roty)
but I don't know if it is correct after inconclusive tests..
I don't know if I have the corresponding x, y and z values.
I can find everything you want on my 2D plan: points, vectors, zenith point of the spotlights and I can positioning spotlights where ever you want too. I just can't find the corresponding Pan and Tilt of a particular X/Y point (the target in the camera view) and I don't know how to find its.
I develop in C#.
This is my Transform. I got it from an example of a simple 2D camera.
public Matrix Transform(GraphicsDevice graphicsDevice)
{
float ViewportWidth = graphicsDevice.Viewport.Width;
float ViewportHeight = graphicsDevice.Viewport.Height;
matrixTransform =
Matrix.CreateTranslation(new Vector3(-cameraPosition.X, -cameraPosition.Y, 0)) *
Matrix.CreateRotationZ(Rotation) *
Matrix.CreateScale(new Vector3(Zoom, Zoom, 0)) *
Matrix.CreateTranslation(
new Vector3(ViewportWidth * 0.5f, ViewportHeight * 0.5f, 0));
return matrixTransform;
}
If I understand it correctly, it allows for a roll(rotation), sprite scale change on zoom, and translation between world and camera for simple up, down, left, right controls. However, it does not alter the Z depth.
But what I need is for the game world to zoom, not just the sprites drawn. And I assume in order to do this I need to change the Z distance between the camera and the world matrix.
I am VERY NEW to programming and have only a simple understanding of matrix in general. I have even less understanding as to how XNA uses them in the draw method. And so far I feel like pulling my hair out from a fruitless search for answers... I just need the world coordinates to scale on zoom, so that before my mouse at a pre-zoom X.60 Y.60 will be at X.600 Y.600 post-zoom (ie: zoom level 0.1). But my mouse has not moved, only the world got bigger in view (or shrank).
I know this question is old, but this is in case anyone comes across this problem and can't find a solution. #RogueDeus was trying to convert scaled input coordinates when he was zooming in or out with his camera. In order to scale the mouse, all you need is to get the inverse matrix of the scale.
So if his scale matrix was created as this:
Matrix.CreateScale(zoom, zoom, 0);
The mouse coordinates should be inverse scaled and shifted by the necessary translation:
float ViewportWidth = graphicsDevice.Viewport.Width;
float ViewportHeight = graphicsDevice.Viewport.Height;
Matrix scale = Matrix.CreateScale(zoom, zoom, 0);
Matrix inputScalar = Matrix.Invert(scale);
...
public MouseState transformMouse(MouseState mouse)
{
/// Shifts the position to 0-relative
Vector2 newPosition = new Vector2(mouse.X - ViewportWidth,
mouse.Y - ViewportHeight);
/// Scales the input to a proper size
newPosition = Vector2.Transform(newPosition, InputScalar);
return new MouseState((int)newPosition.X, (int)newPosition.Y,
mouse.ScrollWheelValue, mouse.LeftButton,
mouse.MiddleButton, mouse.RightButton,
mouse.XButton1, mouse.XButton2);
}
You are using 2D coordinates, therefore the Z coordinate is of absolutely no importance. In fact, the scale matrix you are using ( Matrix.CreateScale(new Vector3(Zoom, Zoom, 0)) ) multiply the Z coordinate by 0, effectively setting it to 0.
As this scale matrix is in the view matrix, it will scale the entire world. I am not sure to really understand your problem. Could you try to explain it a litle more, please?
I seem to have figured out how to get the coordinates to scale...
I was assuming that the current mouse status would reflect the world matrix its clicked on, but apparently it never actually does this. It is always linked to the view matrix. (The screen itself) and that value needs to scale along with the world matrix (in the transform).
So as the transform is effected by Zoom in the Matrix.CreateScale(new Vector3(Zoom, Zoom, 0)) so too does the mouseState X & Y coordinates need to be scaled by it to virtually mirror the world matrix.
//Offsets any cam location by a zoom scaled window bounds
Vector2 CamCenterOffset
{
get { return new Vector2((game.Window.ClientBounds.Height / Zoom)
* 0.5f, (game.Window.ClientBounds.Width / Zoom) * 0.5f);
}
}
//Scales the mouse.X and mouse.Y by the same Zoom as everything.
Vector2 MouseCursorInWorld
{
get
{
currMouseState = Mouse.GetState();
return cameraPosition + new Vector2(currMouseState.X / Zoom,
currMouseState.Y / Zoom);
}
}
I'm making an XNA game and have run into a small problem figuring out a bit of vector math.
I have a class representing a 2D object with X and Y integer coordinates and a Rotation float. What I need is to have a Vector2 property for Position that gets and sets X and Y as a Vector2 that has been transformed using the Rotation float. This way I can just do something like;
Position += new Vector2((thumbstick.X * scrollSpeed), -(thumbstick.Y * scrollSpeed));
and the object will move in it's own upward direction, rather than the View's upward direction.
So far this is what I have...I think the set is right, but for += changes it needs a get as well and the answer just isn't coming to me right now... >.>
public Vector2 Position
{
get
{
// What goes here? :S
}
set
{
X = value.X * (int)Math.Cos(this.Rotation);
Y = value.Y * (int)Math.Cos(this.Rotation);
}
}
No, both are incorrect.
A 2D vector transforms like this:
x' = x*cos(angle) - y*sin(angle)
y' = x*sin(angle) + y*cos(angle)
where the angle is measured in radians, zero angle is along the positive x-axis, and increases in the counterclockwise direction as you rotate around the z-axis out of plane. The center of rotation is at the end of the vector being transformed, so imagine the vector with origin at (0,0), end at (x,y) rotation through an angle until it becomes a vector with origin at (0,0) and end at (x', y').
You can also use the Matrix helper methods to create a Z rotation matrix then multiply your vector by this to rotate it. Something like this:
Vector v1;
Matrix rot = Matrix.CreateRotationZ(angle);
Vector v2 = v1 * rot;
I think this is a bad idea. Keep all of your objects' X and Y co-ordinates in the same planes instead of each having their own axes. By all means have a Position and Heading properties and consider having a Move method which takes your input vector and does the maths to update position and heading.