I have this function where i want to convert my sprite x, y, width, height into view port rect so that i can set it to my camera.
void SetImageRectToCameraRect() {
float x = sideCameraMask.rectTransform.rect.x;
float y = sideCameraMask.rectTransform.rect.y;
float width = sideCameraMask.rectTransform.rect.width;
float height = sideCameraMask.rectTransform.rect.height;
Debug.Log(x);
Debug.Log(y);
Debug.Log(width);
Debug.Log(height);
Debug.Log(sideCamGUI.bounds.size.x);
Debug.Log(sideCamGUI.bounds.size.y);
Debug.Log(sideCamGUI.bounds.size);
Vector3 v3 = GetComponent<Camera>().ScreenToViewportPoint(new Vector3(x,y,0));//x,y,0f
Debug.Log("ScreenToViewportPoint::" + v3);
camComponent.rect = new Rect(x, y, width, height);
}
The problem is that how do I convert width and height into camera view port width height
I'm assuming that you're working in 2D and using an orthographic camera. A perspective camera makes things more complicated.
To get the percentage (fraction) of the viewport that the sprite takes up, you'd divide width and height by the camera's width and height respectively.
float camHeight = camera.orthographicSize * 2;
float camWidth = camHeight * camera.aspect;
float heightFraction = height / camHeight;
float widthFraction = width / camWidth;
If you're using Camera.rect (which I think is the case) just use widthFraction and heightFraction directly. If you're using Camera.pixelRect, multiply widthFraction and heightFraction by Camera.pixelWidth and Camera.pixelHeight respectively.
If you want the width and height only of the area visible by the camera, you'll have to perform a bounds intersection which should be trivial to implement.
Related
I'm currently trying to scale a texture to the given size in pixels via SharpDX.Direct3D9.
I have the following code which draws a texture on the screen (2D)
public static bool DrawTexture(IntPtr device, IntPtr txt, RectangleF rect, float rotation, Color tint)
{
try {
Texture texture = (Texture)txt;
Matrix m = Matrix.Identity * Matrix.Translation(-0.5f, -0.5f, 0.0f) * Matrix.Scaling(rect.Width, rect.Height, 1.0f) * Matrix.RotationZ(rotation) * Matrix.Translation(rect.X, rect.Y, 0.0f);
using (Sprite s = new Sprite((Device)device)) {
s.Begin();
s.Transform = m;
s.Draw(texture, tint.ToRawColorBGRA());
s.End();
}
return true;
}
catch (Exception ex) {
Main.managerInstance.console.PrintError(string.Format("[Direct3D9] An error occured while trying to draw texture. Details: {0}", ex.ToString()));
}
return false;
}
Matrix.Scaling(rect.Width, rect.Height, 1.0f) is responsible for scaling my texture to the given size (128x128 pixel).
But as far as i understand, the Matrix.Scaling function takes in a float from 0 - 1 where 1 is the full texture size and 2 would be double the texture size. But i would like to enter the size in pixel and not in units(?).
So i tried the following:
Size res = CGame.Resolution;
float cW = rect.Width / res.Width;
float cH = rect.Height / res.Height;
Matrix m = Matrix.Identity * Matrix.Translation(-0.5f, -0.5f, 0.0f) * Matrix.Scaling(cW, cH, 1.0f) * Matrix.RotationZ(rotation) * Matrix.Translation(rect.X, rect.Y, 0.0f);
I divide the given texture Width and Height (which is 128x128 pixel) by the Width and Height of the current screen resolution (Which in my case is 1920x1080).
This leaves me with the following:
The result of the division by the screen resolution
As you can see there is a red rectangle in the texture, which is actually 128x128 pixel in size, and in the background, there is my texture, which is supposed to be scaled to 128x128 but as you can see, it clearly is larger then the red rectangle which is 128x128.
Here is how i load my texture
// D3DX.DefaultNonPowerOf2 = -2
Texture t = Texture.FromFile(device, filePath, D3DX.DefaultNonPowerOf2, D3DX.DefaultNonPowerOf2, 1, Usage.None, Format.Unknown, Pool.Managed, Filter.None, Filter.None, 0);
If someone could help me out with this problem i would be really grateful!
Got it working!
Needed to divide the target Size of the texture by the actual texture size like so:
SurfaceDescription sd = texture.GetLevelDescription(0);
float cW = rect.Width / sd.Width;
float cH = rect.Height / sd.Height;
I'm trying to automatically create a photo collage with Win2D library. I've defined a couple of methods to do that:
ICanvasImage RotateImage(ICanvasImage photo, Size size, float degrees) returns a rotated image. I need to pass the image, its size and the degrees number. This method works for other things so I don't think it's that the problem.
ICanvasImage AddImage(ICanvasImage image, Size size, float x, float y, float degrees) it's the guilty. It draws the image on a CanvasRenderTarget with the specified position and size. It first call RotateImage to get the photo with the correct rotation and then draw it on the canvas.
At the end I use a method to save the content of the canvas as an image but it's not important, it works...
If I draw an horizontal image (no rotation => 0 degrees) I have no problem because the destination rectangle to pass to renderer.drawImage() is perfectly align with the photo. If I specified any angle the the image comes rotated correctly but the destination rectangle keeps horizontal an then the photo get cropped where it's out of the bounds of the rectangle.
This is my code:
//photo => photo to rotate
//size => size of the photo
//degrees => degrees to rotate the photo
ICanvasImage RotateImage(ICanvasImage photo, Size size, float degrees)
{
double height = Math.Sqrt(size.Width * size.Width + size.Height*size.Height);
//convert degreese to radians
float radians = (float)(degrees * Math.PI / 180d);
//get x,y where to place the rotated image
float y = (float)((height - size.Height) / 2.0f);
float x = (float)((height - size.Width) / 2.0f);
Vector2 endpoint = new Vector2((float)size.Width / 2, (float)size.Height / 2);
ICanvasImage image = new Transform2DEffect
{
Source = photo,
TransformMatrix = Matrix3x2.CreateRotation(radians, endpoint)
};
return image;
}
//size => final size that I want to have
//x,y => position of the photo
ICanvasImage AddImage(ICanvasImage image, Size size, float x, float y, float degrees)
{
//get the rotated image
ICanvasImage rotatedImage = RotateImage(image, size, degrees);
//start to draw in the canvas
using (var ds = renderer.CreateDrawingSession())
{
//destination rectangle with the specified position and size
Rect destRect = new Rect(x,y,size.Width,size.Height);
//source rectangle of the photo
Rect sourceRect = new Rect(0,0,rotatedImage.GetBounds(renderer).Width,rotatedImage.GetBounds(renderer).Height);
//draw the image on the canvas
ds.DrawImage(rotatedImage,destRect, sourceRect);
}
//here I call the method to save canvas' content as an image...
//you can simply try drawing directly on a canvasControl
}
I'm working on an image viewer in C# WPF that can zoom and crop images. I'd like to be able to make the two work together, but I don't know how to calculate that.
To zoom an image, it is done by modifying TranslateTransform and ScaleTransform X & Y values. Inspired by this answer https://stackoverflow.com/a/6782715/2923736
The crop function is done by calculating TopLeftX, TopRightY, BottomRightX, BottomLeftY that has been drawn on screen.
The size and aspect ratio calculation is done like so:
maxWidth = Math.Min(ScreenWidth, imageWidth);
maxHeight = Math.Min(ScreenHeight, imageHeight);
AspectRatio = Math.Min(maxWidth / imageWidth, maxHeight / imageHeight);
ImageWidth = imageWidth * AspectRatio;
ImageHeight = imageHeight * AspectRatio;
I use this code to calculate the cropped area, but don't know how to put TranslateTransform and ScaleTransform X & Y values into the formula.
internal static Int32Rect? GetCrop()
{
// Contains the dimensions and coordinates of cropped area
var cropArea = CropService.GetCroppedArea();
if (cropArea == null) { return null; }
int x, y, width, height;
x = Convert.ToInt32(cropArea.CroppedRectAbsolute.X / AspectRatio);
y = Convert.ToInt32(cropArea.CroppedRectAbsolute.Y / AspectRatio);
switch (Rotateint) // Degress the image has been rotated by
{
case 0:
case 180:
width = Convert.ToInt32(cropArea.CroppedRectAbsolute.Width / AspectRatio);
height = Convert.ToInt32(cropArea.CroppedRectAbsolute.Height / AspectRatio);
break;
default:
width = Convert.ToInt32(cropArea.CroppedRectAbsolute.Height / AspectRatio);
height = Convert.ToInt32(cropArea.CroppedRectAbsolute.Width / AspectRatio);
break;
}
return new Int32Rect(x, y, width, height);
}
Example of image being cropped, where it has been resized to fit the window and zoomed in by 20%.
I need to calculate that, so it can be saved on the user's hard disk.
I am generating dynamic textures in monogame for simple shapes. Yes I know the disadvantages to this system, but I am just experimenting with building my own physics engine. I am trying to generate the texture for an ellipse as is described here.
I have a function PaintDescriptor that takes an x and y pixel coordinate and gives back what color it should be. Red is just while I am debugging, and normally it would be Color.Transparent.
public override Color PaintDescriptor(int x, int y)
{
float c = (float)Width / 2;
float d = (float)Height / 2;
return pow((x - c) / c, 2) + pow((y - d) / d, 2) <= 1 ? BackgroundColor : Color.Red;
}
Now this works if Width == Height, so, a circle. However, if they are not equal, it generates a texture with some ellipse like shapes, but also with banding/striping.
I have tried seeing if my width and height were switched, and ive tried several other things. One thing to note is that where in the normal coordinate system on desmos I have (y + d) / d, but since the screen's y axis is flipped, I have to flip the y offset in the code: (y - d) / d. The rest of the relating code for texture generation and drawing is here:
public Texture2D GenerateTexture(GraphicsDevice device, Func<int, int, Color> paint)
{
Texture2D texture = new Texture2D(device, Width, Height);
Color[] data = new Color[Width * Height];
for (int pixel = 0; pixel < data.Count(); pixel++)
data[pixel] = paint(pixel / Width, pixel % Height);
texture.SetData(data);
return texture;
}
public void Draw(float scale = 1, float layerdepth = 0, SpriteEffects se = SpriteEffects.None)
{
if (SBRef == null)
throw new Exception("No reference to spritebatch object");
SBRef.Draw(Texture, new Vector2(X, Y), null, null, null, 0, new Vector2(scale, scale), Color.White, se, layerdepth);
}
public float pow(float num, float power) //this is a redirect of math.pow to make code shorter and more readable
{
return (float)Math.Pow(num, power);
}
Why doesnt this match desmos? Why does it not make an ellipse?
EDIT: I forgot to mention, but one possible solution I have come across is to always draw a circle, and then scale it to the desired width and height. This is not acceptable for me for one because of some possible blurriness in drawing, or other artifacts, but more mainly because I want to understand whatever im not currently getting with this solution.
After sleeping and coming back with a fresh mindset for like the 10th time, I found the answer. in the function GenerateTexture:
data[pixel] = paint(pixel / Width, pixel % Height);
should be
data[pixel] = paint(pixel % Width, pixel / Height);
I want to scale an image so that the image is always the size of the screen no matter how it is rotated. Does anyone have any ideas on going about this? By the way I am programing this in C# with xna.
Perhaps something similiar to this, although I'm unsure how you expect to draw the texture. It would be easiest by using triangles and texture wrapping them.
This is how I got the new width and new height after rotating:
Matrix origin = Matrix.CreateTranslation(0, 0, 0);
Matrix scale = Matrix.CreateScale(1f);
Matrix rotation = Matrix.CreateRotationZ(MathHelper.ToRadians(rotate));
Matrix translation = Matrix.CreateTranslation(0, 0, 0);
Vector2 pos1 = Vector2.Transform(new Vector2(Texture.Width / 2, Texture.Height / 2), origin * scale * rotation * origin);
Vector2 pos2 = Vector2.Transform(new Vector2(Texture.Width, Texture.Height), origin * scale * rotation * translation);
int width = (int)Math.Abs(pos2.X - pos1.X) * 2;
int height = (int)Math.Abs(pos2.Y - pos1.Y) * 2;
float scaleX = (graphics.PreferredBackBufferWidth / width);
float scaleY = (graphics.PreferredBackBufferHeight / height);
You will probably figure out the best way to draw this, because an image flipped 45 degrees will look weird drawn on the screen so you probably have to scale it up so it fits the screen but still be rotated. That you left out, an image rotated 180 degrees or 90 degrees should work better.
You can apply a RotateTransform to transform the image, then enclose that in a LayoutTransform to fill the dimensions of the container (the screen in this case).