I am trying to draw a diagonal shadow.
First I make all pixel to black:
Next with a simple for cicle this is are the result
Now I want to stretch this image diagonally to simulate a shadow.
I have tried:
Bitmap b = new Bitmap(tImage.Width + 100, tImage.Height);
Graphics p = Graphics.FromImage(b);
p.RotateTransform(30f);
p.TranslateTransform(100f, -200f);
p.DrawImage(tImage, new Rectangle(0, -20, b.Width+20, b.Height));
but the images are rotated and translated.
Please anyone have a solution for me?
I need it to look like this (created in Photoshop):
Creating a nice dropshadow is quite a task using Winforms and GDI+.
It features neither polygon scaling nor blurring; and let's not even think about 3D..! - But we can at least do a few things without too much work and get a nice result for many images..
Let's assume you already have an image that is cut out from its background.
The next step would be to turn all colors into black.
Then we most likely would want to add some level of transparency, so that the background the shadow falls on, still shines through.
Both task are done quite effectively by using a suitable ColorMatrix.
With a very transparent version we can also create simple blurring by drawing the image with offsets. For best results I would draw it nine times with 3 differents weights/alpha values..
High quality blurring is an art as you can see by even just looking at the filters and adjustments in pro software like Adobe Photoshop or Affinity Photo. Here is a nice set of interesting links..
But since we are only dealing with a b/w bitmap a simplitstic appraoch is good enough.. I use 3 alpha values of 5%, 10% and 20% for the 4 corner, the 4 edge and the 1 center drawings.
The final step is drawing the shadow with some skewing.
This is explained here; but while this is seemingly very simple it is also somewhat impractical. The three points the DrawImage overlay expects need to be calculated.
So here is a method that does just that; do note that is is a strongly simplified method:
The overlay takes three points, that is 6 floats. We only use 3 numbers:
one for the amount of skewing; 0.5 means the top is shifted to the right by half the width of the bitmap.
the other two are the scaling of the resulting bounding box. 1 and 0.5 mean that the width is unchanged and the height is reduced to 50%.
Here is the function:
public Bitmap SkewBitmap(Bitmap inMap, float skewX, float ratioX, float ratioY )
{
int nWidth = (int)(inMap.Width * (skewX + ratioX));
int nHeight = (int)(Math.Max(inMap.Height, inMap.Height * ratioY));
int yOffset = inMap.Height - nHeight;
Bitmap outMap = new Bitmap(nWidth, nHeight);
Point[] destinationPoints = {
new Point((int)(inMap.Width * skewX), (int)(inMap.Height * ratioY) + yOffset),
new Point((int)(inMap.Width * skewX + inMap.Width * ratioX),
(int)(inMap.Height * ratioY) + yOffset),
new Point(0, inMap.Height + yOffset ) };
using (Graphics g = Graphics.FromImage(outMap))
g.DrawImage(inMap, destinationPoints);
return outMap;
}
Note a few simplifications:
If you want to drop the shadow to the left you will need to not just move the first two points to the left but also to adapt the calculation of the width and also the way you overlay the object over the shadow.
If you study the MSDN example you will see that the DrawImage overlay also allows to do a rotation. I didn't add this to our function, as it is a good deal more complicated to calculate and even to just to write a signature.
If you wonder where the info of the six numbers go, here is the full layout:
3 go into our parameters
1 would be the angle of the rotation we don't do
2 could be either the rotation center point or a point (deltaX&Y) the by which the result is translated
If you look closely you can see the shadow of the left foot is a little below the foot. This is because the feet are not at the same level and with the vertical compression the base lines drift apart. To correct that we would either modify the image or add a tiny rotation after all.
Looking at your example imag it is clear that you will nee to take it apart and treat 'house' and 'tree' separately!
The signature is kept simple; this always a balance between ease of use and effort in coding. On could wish for a paramter the takes angle to control the skewing. Feel free to work out the necessary calculations..
Note that adding the functions behind the other buttons would go beyond the scope of the question. Suffice it to say that most are just one line to do the drawing and a dozen or so to set up the colormatrix..
Here is the code in the 'Skew' button:
Bitmap bmp = SkewBitmap((Bitmap)pictureBox4.Image, 0.5f, 1f, 0.5f);
pictureBox5.Image = pictureBox1.Image;
pictureBox5.BackgroundImage = bmp;
pictureBox5.ClientSize = new Size(bmp.Width, bmp.Height);
Instead of drawing the object over the shadow I make use of the extra layer of the PictureBox. You would of course combine the two Bitmaps..
Related
I would like to draw and then fill a signal using graphics.drawcurve and graphics.fillclosedcurve as following:
Graphics
gX = drawPanel.CreateGraphics();
Pen pen1 = new Pen(Color.Black);
Brush be = new SolidBrush(Color.Gray);
gX.DrawCurve(pen1, pointArray1, 0.01F);
gX.FillClosedCurve(be, pointArray1);
Although there is no minus in the plotted data I got some filled curved at the minus side of the curve (due to interpolation?) as following:
How can I get rid of these artifacts?
Thanks in advance!
Do not use DrawCurves to plot real data!
They look nice and are useful when creating a freehand plot of your mouse movements.
But when plotting data they are not so good as they tend to overdraw esp. when the direction changes quickly.
See here for an instructive example of overdrawing! Setting a Tension is a way to limit the problem; but it will also limit the smoothness of the lines..
The solution there uses Beziers, but this not what you should do!
With the great number of dara points you seem to have I suggest you stick to DrawLines & FillPolygon instead; they still should look rather smooth..
Right now I'm using XNA 4.0 with Windows Phone Developer Tools to create a textured cube using a predefined quad class on MSDN.
The front/back/left/right faces of the cube will draw fine (for every cube that I make), however the top and bottom faces won't render. The rasterizer state's cull mode is set to none and the quad that represents the top face exists, and it seems as if it would draw, but for some reason it won't.
Is there a problem with my code, or is this not happening for some other reason?
Here's the code:
Game1.cs: http://pastebin.com/RHU7jNXA
Quad.cs & Cube.cs: http://pastebin.com/P9gz5q4C
It's because your top and bottom faces have a height to them. They should have 0 height.
Here you are passing in a value as height:
Faces[4] = new Quad(topFaceOrigin, Vector3.Normalize(Vector3.Down), Up, Size, Size);
And then here in Quad constructor it's being used to give incorrect LowerLeft & LowerRight values:
LowerLeft = UpperLeft - (Up * height);
LowerRight = UpperRight - (Up * height);
I would recommend changing how you create all your quads; each face really should have different parameters. Right now all your faces are passing in practically the same stuff.
I'm developing an UI for a project for school, and I've tried similar methods to scaling my texture as listed here, but here is the issue:
Our project is developed at 1440 x 900, so I've made my own images that fit that screen resolution. When we have to demo our project in class, the projector can only render up to 1024 x 768, thus, many things on the screen goes missing. I have added window resizing capabilities, and I'm doing my scaling like this. I have my own class called "button" which has a texture 2d, and a Vector2 position contruscted by Button(Texture2d img, float width, float height).
My idea is to set the position of the image to a scalable % of the window width and height, so I'm attempting to set the position of the img to a number between 0-1 and then multiply by the window width and height to keep everything scaled properly.
(this code is not the proper syntax, i'm just trying to convey the point)
Button button = new Button(texture, .01, .01 );
int height = graphicsdevice.viewport.height * button.position.Y;
int width = graphicsdevice.viewport.width * button.position.X;
Rectangle rect = new Rectangle(0,0,width, height);
sprite.being()
sprite.draw (button.img, rect, color.white);
sprite.end
it doesn't end up scaling anything when i go to draw it and resize the window by dragging the mouse around. if i hard code in a different bufferheight and bufferwidth to begin with, the image stays around the same size regardless of resolution, except that the smaller the resolution is, the more pixelated the image looks.
what is the best way to design my program to allow for dynamic texture2d scaling?
As Hannesh said, if you run it in fullscreen you won't have these problems. However, you also have a fundamental problem with the way you are doing this. Instead of using the position of the sprite, which will not change at all during window resize, you must use the size of the sprite. I often do this using a property called Scale in my Sprite class. So instead of clamping the position of the sprite between 0 and 1, you should be clamping the Size property of the sprite between 0 and 1. Then as you rescale the window it will rescale the sprites.
In my opinion, a better way to do this is to have a default resolution, in your case 1440 x 900. Then, if the window is rescaled, just multiply all sprites' scaling factors by the ratio of the new screensize to the old screensize. This takes only 1 multiplication per resize, instead of a multiplication per update (which is what your method will do, because you have to convert from the clamped 0-1 value to the real scale every update).
Also, the effects you noticed during manual rescale of the sprites is normal. Rescaling images to arbitrary sizes causes artifacts in the rendered image because the graphics device doesn't know what to do at most sizes. A good way to get around this is by using filler art during the development process and then create the final art in the correct resolution(s). Obviously this doesn't apply in your situation because you are resizing a window to arbitrary size, but in games you will usually only be able to switch to certain fixed resolutions.
Here's the code i'm using to rotate:
Dim m As New System.Drawing.Drawing2D.Matrix
Dim size = image.Size
m.RotateAt(degreeAngle, New PointF(CSng(size.Width / 2), CSng(size.Height / 2)))
Dim temp As New Bitmap(600, 600, Imaging.PixelFormat.Format32bppPArgb)
Dim g As Graphics = Graphics.FromImage(temp)
g.Transform = m
g.DrawImage(image, 0, 0)
(1) Disposals removed for brevity.
(2) I test the code with a 200 x 200 rectangle.
(3) Size 600,600 it just an arbitrary large value that I know will fit the right and bottom sides of the rotated image for testing purposes.
(4) I know, with this code, the top and left edges will be clipped because I'm not transforming the orgin after the rotate.
The problem only occurs at certain angles:
(1) At 90, the right hand edge disappears completely.
(2) At 180, the right and bottom edges are there, but very faded.
(3) At 270, the bottom edge disappears completely.
Is this a known bug?
If I manually rotate the corners an draw the image by specifying an output rectangle, I don't get the same problem - though it is slightly slower than using RotateAt.
RotateAt uses formulas and sadness to do rotations, because this is necessary when rotating by anything other than 90 degree increments. If you're going to rotate in 90 degree increments, use RotateFlip, which is much more efficient and more accurate.
I had the very same issue, when rotating images, GDI+ shifting the image by 1 pixel, or cropping a 1 pixel border if I try to "fix" the coordinates manually.
Found the solution:
graphics.SetPixelOffsetMode( Gdiplus::PixelOffsetMode::PixelOffsetModeHalf );
I have a 48x48 image which is rotated using a transformation matrix.
For some reason, the rotated image in design-time differs from the rotated image in run-time as you can see from this screenshot (link dead) (design-time on the left, run-time on the right):
It might be a little bit difficult to spot, but if you look closely at the right edge of the blue circle, it is about a pixel wider in the image to the right. Note that the image is layered - the white glow in the foreground is the part that's being rotated, while the blue ball in the background is static.
It seems like the image is offset 1 pixel in run-time, when rotating exactly 90 degrees (as in the screenshot), 180 degrees and probably also 270 degrees. The image looks the same with any other rotation angle, as far as I can see.
Here's a snippet:
protected static Image RotateImage(Image pImage, Single pAngle)
{
Matrix lMatrix = new Matrix();
lMatrix.RotateAt(pAngle, new PointF(pImage.Width / 2, pImage.Height / 2));
Bitmap lNewBitmap = new Bitmap(pImage.Width, pImage.Height);
lNewBitmap.SetResolution(pImage.HorizontalResolution, pImage.VerticalResolution);
Graphics lGraphics = Graphics.FromImage(lNewBitmap);
lGraphics.Transform = lMatrix;
lGraphics.DrawImage(pImage, 0, 0);
lGraphics.Dispose();
lMatrix.Dispose();
return lNewBitmap;
}
void SomeMethod()
{
// Same results in design-time and run-time:
PictureBox1.Image = RotateImage(PictureBox2.Image, 18)
// Different results in design-time and run-time.
PictureBox1.Image = RotateImage(PictureBox2.Image, 90)
}
Can anyone explain the reason for this behaviour? Or better yet, a solution to make run-time results look like design-time results?
It's important for me because this image is part of an animation which is generated from code based on a single image which is then rotated in small steps. In design-time, the animation looks smooth and nice. In run-time it looks like it's jumping around :/
I'm using Visual Studio 2005 on Windows Vista Business SP2.
It might have something to do with differences in the Graphics object used at design time versus run time like the PixelOffsetMode.
How are you specifying your angle of rotation? in Degrees or in Radians?
Sometimes I get results like those you describe when I've accidentally specified my angle in degrees when it should've been radians (and as a result the object has been rotated several hundred degrees instead of a few)
I don't know for sure given your specific example, but its worth suggesting.
Hm, my consideration is to try:
lMatrix.RotateAt(pAngle, new PointF((pImage.Width + 1)/2.0f, (pImage.Height + 1)/ 2.0f));
I think that should be a problem about the math being performed in floating point; when rounding back to integer coordinates.
One question that might be relevant... is your image completely square and the width and height an even number? Maybe the problem lies there.
Edit: In the first read I passed through the dimensions of the image... If that wasn't the problem maybe you could do a simple rotation by yourself:
angle = 90 : img[i][j] = img[j][w-i]
angle = 180: img[i][j] = img[w-i][w-j]
angle = 270: img[i][j] = img[w-j][i]
(I think the index swappings are ok, but a double check won't be bad)