Pixels shift in WriteableBitmap
I have faced a problem with WriteableBitmap. I am trying to render a 3d cube. But when pixels is being written to WriteableBitmap, part of them just shift.
Initialized cube:
And that what's happening, when I am trying to rotate it by 45 degrees along x.
Problem appears for all kind of rotation, except y (rotation by 10 degrees along z)
I have tested same points with usual Bitmap and SetPixel() method. That's what I get after rotating cube along 45 degrees by three axis. I don't see any problems here
I think that problem can be with my writeableBitmap pixels setting algorithm (maybe problem with pixel offset?).
Second image with grey background:
What I am expecting from cube rotated by 45 deegres along x. Red line - edge. Text - facets
WriteableBitmap drawing algorithm:
public WriteableBitmap DrawSceneByPoints(int width, int height, List<MPoint> points)
{
WriteableBitmap wBitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
Int32Rect rect = new Int32Rect(0, 0, width, height);
var stride = (rect.Width * wBitmap.Format.BitsPerPixel + 7) / 8;
byte pixels = new byte[rect.Height * stride];
// For user: Moves 0,0 point from top-left to bottom-left
for (int i = 0; i < points.Count; ++i)
points[i].Y = height - points[i].Y;
int alpha = 255;
int red = 0;
int green = 0;
int blue = 0;
for (int i = 0; i < points.Count; ++i)
{
int pixelOffset = (int)(points[i].X + points[i].Y * wBitmap.PixelWidth) * wBitmap.Format.BitsPerPixel / 8;
pixels[pixelOffset] = (byte)blue;
pixels[pixelOffset + 1] = (byte)green;
pixels[pixelOffset + 2] = (byte)red;
pixels[pixelOffset + 3] = (byte)alpha;
}
wBitmap.WritePixels(rect, pixels, stride, 0);
return wBitmap;
}
Usual bitmap drawing algorithm:
public Bitmap DrawSceneByPointsBitmap(int width, int height, List<MPoint> points)
{
Bitmap bitmap = new Bitmap(width, height);
// For user: Moves 0,0 point from top-left to bottom-left
for (int i = 0; i < points.Count; ++i)
points[i].Y = height - points[i].Y;
for (int i = 0; i < points.Count; ++i)
bitmap.SetPixel((int)points[i].X, (int)points[i].Y, System.Drawing.Color.White);
return bitmap;
}
Scene Render method:
public WriteableBitmap Render()
{
new ShapeEditor().TransformShapes(Shapes, CurrentCamera);
List<MPoint> allPoints = GetAllPoints();
return new Painter().DrawSceneByPoints(this.Width, this.Height, allPoints);
}
Line rastrizer:
class BresenhamLine : ILineRasterizer
{
public List<MPoint> GetLine(MPoint point1, MPoint point2)
{
return Bresenham3D((int)point1.X, (int)point1.Y, (int)point1.Z, (int)point2.X, (int)point2.Y, (int)point2.Z);
}
private List<MPoint> Bresenham3D(int x1, int y1, int z1, int x2, int y2, int z2)
{
var points = new List<MPoint>();
float x0 = x1, y0 = y1, z0 = z1;
int i, dx, dy, dz, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
int point = new int[3];
point[0] = x1;
point[1] = y1;
point[2] = z1;
dx = x2 - x1;
dy = y2 - y1;
dz = z2 - z1;
x_inc = (dx < 0) ? -1 : 1;
l = Math.Abs(dx);
y_inc = (dy < 0) ? -1 : 1;
m = Math.Abs(dy);
z_inc = (dz < 0) ? -1 : 1;
n = Math.Abs(dz);
dx2 = l << 1;
dy2 = m << 1;
dz2 = n << 1;
if ((l >= m) && (l >= n))
{
err_1 = dy2 - l;
err_2 = dz2 - l;
for (i = 0; i < l; i++)
{
points.Add(new MPoint(point[0], point[1], point[2]));
if (err_1 > 0)
{
point[1] += y_inc;
err_1 -= dx2;
}
if (err_2 > 0)
{
point[2] += z_inc;
err_2 -= dx2;
}
err_1 += dy2;
err_2 += dz2;
point[0] += x_inc;
}
}
else if ((m >= l) && (m >= n))
{
err_1 = dx2 - m;
err_2 = dz2 - m;
for (i = 0; i < m; i++)
{
points.Add(new MPoint(point[0], point[1], point[2]));
if (err_1 > 0)
{
point[0] += x_inc;
err_1 -= dy2;
}
if (err_2 > 0)
{
point[2] += z_inc;
err_2 -= dy2;
}
err_1 += dx2;
err_2 += dz2;
point[1] += y_inc;
}
}
else
{
err_1 = dy2 - n;
err_2 = dx2 - n;
for (i = 0; i < n; i++)
{
points.Add(new MPoint(point[0], point[1], point[2]));
if (err_1 > 0)
{
point[1] += y_inc;
err_1 -= dz2;
}
if (err_2 > 0)
{
point[0] += x_inc;
err_2 -= dz2;
}
err_1 += dy2;
err_2 += dx2;
point[2] += z_inc;
}
}
return points;
}
private void Swap<T>(ref T l, ref T r)
{
T temp = l;
l = r;
r = temp;
}
}
Polygon rasterizer:
public List<MPoint> RasterizePolygon(MFacet triangle)
{
var points = new List<MPoint>();
Vector2 vertex0 = new Vector2(triangle.Vertices[0].X, triangle.Vertices[0].Y),
vertex1 = new Vector2(triangle.Vertices[1].X, triangle.Vertices[1].Y),
vertex2 = new Vector2(triangle.Vertices[2].X, triangle.Vertices[2].Y);
if (vertex0.Y == vertex1.Y && vertex0.Y == vertex2.Y) return new BresenhamLine().GetLine(triangle.Vertices[0], triangle.Vertices[2]);
// sort the vertices, vertex0, vertex1, vertex2 lower-to-upper
if (vertex0.Y > vertex1.Y) Swap(ref vertex0, ref vertex1);
if (vertex0.Y > vertex2.Y) Swap(ref vertex0, ref vertex2);
if (vertex1.Y > vertex2.Y) Swap(ref vertex1, ref vertex2);
int total_height = (int)(vertex2.Y - vertex0.Y);
for (int i = 0; i < total_height; i++)
{
bool second_half = i > vertex1.Y - vertex0.Y || vertex1.Y == vertex0.Y;
int segment_height = second_half ? (int)(vertex2.Y - vertex1.Y) : (int)(vertex1.Y - vertex0.Y);
float alpha = (float)i / total_height;
float beta = (float)(i - (second_half ? vertex1.Y - vertex0.Y : 0)) / segment_height; // be careful: with above conditions no division by zero here
Vector2 A = vertex0 + (vertex2 - vertex0) * alpha;
Vector2 B = second_half ? vertex1 + (vertex2 - vertex1) * beta : vertex0 + (vertex1 - vertex0) * beta;
if (A.X > B.X) Swap(ref A, ref B);
for (int j = (int)A.X; j <= B.X; j++)
{
points.Add(new MPoint(j, vertex0.Y + i, 1));
if (j > B.X || (A.X < vertex0.X && A.X < vertex1.X && A.X < vertex2.X))
Swap(ref vertex0, ref vertex0);
}
}
return points;
}
c# wpf graphics 3d writeablebitmap
add a comment |
I have faced a problem with WriteableBitmap. I am trying to render a 3d cube. But when pixels is being written to WriteableBitmap, part of them just shift.
Initialized cube:
And that what's happening, when I am trying to rotate it by 45 degrees along x.
Problem appears for all kind of rotation, except y (rotation by 10 degrees along z)
I have tested same points with usual Bitmap and SetPixel() method. That's what I get after rotating cube along 45 degrees by three axis. I don't see any problems here
I think that problem can be with my writeableBitmap pixels setting algorithm (maybe problem with pixel offset?).
Second image with grey background:
What I am expecting from cube rotated by 45 deegres along x. Red line - edge. Text - facets
WriteableBitmap drawing algorithm:
public WriteableBitmap DrawSceneByPoints(int width, int height, List<MPoint> points)
{
WriteableBitmap wBitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
Int32Rect rect = new Int32Rect(0, 0, width, height);
var stride = (rect.Width * wBitmap.Format.BitsPerPixel + 7) / 8;
byte pixels = new byte[rect.Height * stride];
// For user: Moves 0,0 point from top-left to bottom-left
for (int i = 0; i < points.Count; ++i)
points[i].Y = height - points[i].Y;
int alpha = 255;
int red = 0;
int green = 0;
int blue = 0;
for (int i = 0; i < points.Count; ++i)
{
int pixelOffset = (int)(points[i].X + points[i].Y * wBitmap.PixelWidth) * wBitmap.Format.BitsPerPixel / 8;
pixels[pixelOffset] = (byte)blue;
pixels[pixelOffset + 1] = (byte)green;
pixels[pixelOffset + 2] = (byte)red;
pixels[pixelOffset + 3] = (byte)alpha;
}
wBitmap.WritePixels(rect, pixels, stride, 0);
return wBitmap;
}
Usual bitmap drawing algorithm:
public Bitmap DrawSceneByPointsBitmap(int width, int height, List<MPoint> points)
{
Bitmap bitmap = new Bitmap(width, height);
// For user: Moves 0,0 point from top-left to bottom-left
for (int i = 0; i < points.Count; ++i)
points[i].Y = height - points[i].Y;
for (int i = 0; i < points.Count; ++i)
bitmap.SetPixel((int)points[i].X, (int)points[i].Y, System.Drawing.Color.White);
return bitmap;
}
Scene Render method:
public WriteableBitmap Render()
{
new ShapeEditor().TransformShapes(Shapes, CurrentCamera);
List<MPoint> allPoints = GetAllPoints();
return new Painter().DrawSceneByPoints(this.Width, this.Height, allPoints);
}
Line rastrizer:
class BresenhamLine : ILineRasterizer
{
public List<MPoint> GetLine(MPoint point1, MPoint point2)
{
return Bresenham3D((int)point1.X, (int)point1.Y, (int)point1.Z, (int)point2.X, (int)point2.Y, (int)point2.Z);
}
private List<MPoint> Bresenham3D(int x1, int y1, int z1, int x2, int y2, int z2)
{
var points = new List<MPoint>();
float x0 = x1, y0 = y1, z0 = z1;
int i, dx, dy, dz, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
int point = new int[3];
point[0] = x1;
point[1] = y1;
point[2] = z1;
dx = x2 - x1;
dy = y2 - y1;
dz = z2 - z1;
x_inc = (dx < 0) ? -1 : 1;
l = Math.Abs(dx);
y_inc = (dy < 0) ? -1 : 1;
m = Math.Abs(dy);
z_inc = (dz < 0) ? -1 : 1;
n = Math.Abs(dz);
dx2 = l << 1;
dy2 = m << 1;
dz2 = n << 1;
if ((l >= m) && (l >= n))
{
err_1 = dy2 - l;
err_2 = dz2 - l;
for (i = 0; i < l; i++)
{
points.Add(new MPoint(point[0], point[1], point[2]));
if (err_1 > 0)
{
point[1] += y_inc;
err_1 -= dx2;
}
if (err_2 > 0)
{
point[2] += z_inc;
err_2 -= dx2;
}
err_1 += dy2;
err_2 += dz2;
point[0] += x_inc;
}
}
else if ((m >= l) && (m >= n))
{
err_1 = dx2 - m;
err_2 = dz2 - m;
for (i = 0; i < m; i++)
{
points.Add(new MPoint(point[0], point[1], point[2]));
if (err_1 > 0)
{
point[0] += x_inc;
err_1 -= dy2;
}
if (err_2 > 0)
{
point[2] += z_inc;
err_2 -= dy2;
}
err_1 += dx2;
err_2 += dz2;
point[1] += y_inc;
}
}
else
{
err_1 = dy2 - n;
err_2 = dx2 - n;
for (i = 0; i < n; i++)
{
points.Add(new MPoint(point[0], point[1], point[2]));
if (err_1 > 0)
{
point[1] += y_inc;
err_1 -= dz2;
}
if (err_2 > 0)
{
point[0] += x_inc;
err_2 -= dz2;
}
err_1 += dy2;
err_2 += dx2;
point[2] += z_inc;
}
}
return points;
}
private void Swap<T>(ref T l, ref T r)
{
T temp = l;
l = r;
r = temp;
}
}
Polygon rasterizer:
public List<MPoint> RasterizePolygon(MFacet triangle)
{
var points = new List<MPoint>();
Vector2 vertex0 = new Vector2(triangle.Vertices[0].X, triangle.Vertices[0].Y),
vertex1 = new Vector2(triangle.Vertices[1].X, triangle.Vertices[1].Y),
vertex2 = new Vector2(triangle.Vertices[2].X, triangle.Vertices[2].Y);
if (vertex0.Y == vertex1.Y && vertex0.Y == vertex2.Y) return new BresenhamLine().GetLine(triangle.Vertices[0], triangle.Vertices[2]);
// sort the vertices, vertex0, vertex1, vertex2 lower-to-upper
if (vertex0.Y > vertex1.Y) Swap(ref vertex0, ref vertex1);
if (vertex0.Y > vertex2.Y) Swap(ref vertex0, ref vertex2);
if (vertex1.Y > vertex2.Y) Swap(ref vertex1, ref vertex2);
int total_height = (int)(vertex2.Y - vertex0.Y);
for (int i = 0; i < total_height; i++)
{
bool second_half = i > vertex1.Y - vertex0.Y || vertex1.Y == vertex0.Y;
int segment_height = second_half ? (int)(vertex2.Y - vertex1.Y) : (int)(vertex1.Y - vertex0.Y);
float alpha = (float)i / total_height;
float beta = (float)(i - (second_half ? vertex1.Y - vertex0.Y : 0)) / segment_height; // be careful: with above conditions no division by zero here
Vector2 A = vertex0 + (vertex2 - vertex0) * alpha;
Vector2 B = second_half ? vertex1 + (vertex2 - vertex1) * beta : vertex0 + (vertex1 - vertex0) * beta;
if (A.X > B.X) Swap(ref A, ref B);
for (int j = (int)A.X; j <= B.X; j++)
{
points.Add(new MPoint(j, vertex0.Y + i, 1));
if (j > B.X || (A.X < vertex0.X && A.X < vertex1.X && A.X < vertex2.X))
Swap(ref vertex0, ref vertex0);
}
}
return points;
}
c# wpf graphics 3d writeablebitmap
There is nothing wrong. The problem is you background it white and some of the cube sides are white. So you cannot see where the side of the cube end and the background starts. Make you background grey, and alternate the sides of the cube black and white and the problem will go away.
– jdweng
Nov 24 '18 at 14:44
@jdweng I tried this, but that doesn't help. My cube is black by default. I used cube with white sides for bitmap. Cause bitmap's background is black by default. I'll add picture with grey background to original question
– Dmitry
Nov 24 '18 at 14:56
Is you sides transparent. The cube with grey background (left) make the top side white so you can see it. How do you know where the top side ends and the background starts when both are grey?
– jdweng
Nov 24 '18 at 15:02
@jdweng No, sides are not transparant, all sides are black. And I have only one cube. Left cube is a missing part of a cube in the center. I also don't have any of unseen line removing algorithm. I've also added picture with what cube I expect
– Dmitry
Nov 24 '18 at 15:16
It doesn't look like it is missing to me except if the initialized cube doesn't have 6 faces. The rotation by 10 degrees show two faces. A black front face and a white rear faces. Where are the other 4 faces? The line on the left is the edge of one side. The 45 degrees view which you says is good you are only seeing 3 faces. The bottom, rear, and right. The front, top, and left are missing.
– jdweng
Nov 24 '18 at 20:29
add a comment |
I have faced a problem with WriteableBitmap. I am trying to render a 3d cube. But when pixels is being written to WriteableBitmap, part of them just shift.
Initialized cube:
And that what's happening, when I am trying to rotate it by 45 degrees along x.
Problem appears for all kind of rotation, except y (rotation by 10 degrees along z)
I have tested same points with usual Bitmap and SetPixel() method. That's what I get after rotating cube along 45 degrees by three axis. I don't see any problems here
I think that problem can be with my writeableBitmap pixels setting algorithm (maybe problem with pixel offset?).
Second image with grey background:
What I am expecting from cube rotated by 45 deegres along x. Red line - edge. Text - facets
WriteableBitmap drawing algorithm:
public WriteableBitmap DrawSceneByPoints(int width, int height, List<MPoint> points)
{
WriteableBitmap wBitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
Int32Rect rect = new Int32Rect(0, 0, width, height);
var stride = (rect.Width * wBitmap.Format.BitsPerPixel + 7) / 8;
byte pixels = new byte[rect.Height * stride];
// For user: Moves 0,0 point from top-left to bottom-left
for (int i = 0; i < points.Count; ++i)
points[i].Y = height - points[i].Y;
int alpha = 255;
int red = 0;
int green = 0;
int blue = 0;
for (int i = 0; i < points.Count; ++i)
{
int pixelOffset = (int)(points[i].X + points[i].Y * wBitmap.PixelWidth) * wBitmap.Format.BitsPerPixel / 8;
pixels[pixelOffset] = (byte)blue;
pixels[pixelOffset + 1] = (byte)green;
pixels[pixelOffset + 2] = (byte)red;
pixels[pixelOffset + 3] = (byte)alpha;
}
wBitmap.WritePixels(rect, pixels, stride, 0);
return wBitmap;
}
Usual bitmap drawing algorithm:
public Bitmap DrawSceneByPointsBitmap(int width, int height, List<MPoint> points)
{
Bitmap bitmap = new Bitmap(width, height);
// For user: Moves 0,0 point from top-left to bottom-left
for (int i = 0; i < points.Count; ++i)
points[i].Y = height - points[i].Y;
for (int i = 0; i < points.Count; ++i)
bitmap.SetPixel((int)points[i].X, (int)points[i].Y, System.Drawing.Color.White);
return bitmap;
}
Scene Render method:
public WriteableBitmap Render()
{
new ShapeEditor().TransformShapes(Shapes, CurrentCamera);
List<MPoint> allPoints = GetAllPoints();
return new Painter().DrawSceneByPoints(this.Width, this.Height, allPoints);
}
Line rastrizer:
class BresenhamLine : ILineRasterizer
{
public List<MPoint> GetLine(MPoint point1, MPoint point2)
{
return Bresenham3D((int)point1.X, (int)point1.Y, (int)point1.Z, (int)point2.X, (int)point2.Y, (int)point2.Z);
}
private List<MPoint> Bresenham3D(int x1, int y1, int z1, int x2, int y2, int z2)
{
var points = new List<MPoint>();
float x0 = x1, y0 = y1, z0 = z1;
int i, dx, dy, dz, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
int point = new int[3];
point[0] = x1;
point[1] = y1;
point[2] = z1;
dx = x2 - x1;
dy = y2 - y1;
dz = z2 - z1;
x_inc = (dx < 0) ? -1 : 1;
l = Math.Abs(dx);
y_inc = (dy < 0) ? -1 : 1;
m = Math.Abs(dy);
z_inc = (dz < 0) ? -1 : 1;
n = Math.Abs(dz);
dx2 = l << 1;
dy2 = m << 1;
dz2 = n << 1;
if ((l >= m) && (l >= n))
{
err_1 = dy2 - l;
err_2 = dz2 - l;
for (i = 0; i < l; i++)
{
points.Add(new MPoint(point[0], point[1], point[2]));
if (err_1 > 0)
{
point[1] += y_inc;
err_1 -= dx2;
}
if (err_2 > 0)
{
point[2] += z_inc;
err_2 -= dx2;
}
err_1 += dy2;
err_2 += dz2;
point[0] += x_inc;
}
}
else if ((m >= l) && (m >= n))
{
err_1 = dx2 - m;
err_2 = dz2 - m;
for (i = 0; i < m; i++)
{
points.Add(new MPoint(point[0], point[1], point[2]));
if (err_1 > 0)
{
point[0] += x_inc;
err_1 -= dy2;
}
if (err_2 > 0)
{
point[2] += z_inc;
err_2 -= dy2;
}
err_1 += dx2;
err_2 += dz2;
point[1] += y_inc;
}
}
else
{
err_1 = dy2 - n;
err_2 = dx2 - n;
for (i = 0; i < n; i++)
{
points.Add(new MPoint(point[0], point[1], point[2]));
if (err_1 > 0)
{
point[1] += y_inc;
err_1 -= dz2;
}
if (err_2 > 0)
{
point[0] += x_inc;
err_2 -= dz2;
}
err_1 += dy2;
err_2 += dx2;
point[2] += z_inc;
}
}
return points;
}
private void Swap<T>(ref T l, ref T r)
{
T temp = l;
l = r;
r = temp;
}
}
Polygon rasterizer:
public List<MPoint> RasterizePolygon(MFacet triangle)
{
var points = new List<MPoint>();
Vector2 vertex0 = new Vector2(triangle.Vertices[0].X, triangle.Vertices[0].Y),
vertex1 = new Vector2(triangle.Vertices[1].X, triangle.Vertices[1].Y),
vertex2 = new Vector2(triangle.Vertices[2].X, triangle.Vertices[2].Y);
if (vertex0.Y == vertex1.Y && vertex0.Y == vertex2.Y) return new BresenhamLine().GetLine(triangle.Vertices[0], triangle.Vertices[2]);
// sort the vertices, vertex0, vertex1, vertex2 lower-to-upper
if (vertex0.Y > vertex1.Y) Swap(ref vertex0, ref vertex1);
if (vertex0.Y > vertex2.Y) Swap(ref vertex0, ref vertex2);
if (vertex1.Y > vertex2.Y) Swap(ref vertex1, ref vertex2);
int total_height = (int)(vertex2.Y - vertex0.Y);
for (int i = 0; i < total_height; i++)
{
bool second_half = i > vertex1.Y - vertex0.Y || vertex1.Y == vertex0.Y;
int segment_height = second_half ? (int)(vertex2.Y - vertex1.Y) : (int)(vertex1.Y - vertex0.Y);
float alpha = (float)i / total_height;
float beta = (float)(i - (second_half ? vertex1.Y - vertex0.Y : 0)) / segment_height; // be careful: with above conditions no division by zero here
Vector2 A = vertex0 + (vertex2 - vertex0) * alpha;
Vector2 B = second_half ? vertex1 + (vertex2 - vertex1) * beta : vertex0 + (vertex1 - vertex0) * beta;
if (A.X > B.X) Swap(ref A, ref B);
for (int j = (int)A.X; j <= B.X; j++)
{
points.Add(new MPoint(j, vertex0.Y + i, 1));
if (j > B.X || (A.X < vertex0.X && A.X < vertex1.X && A.X < vertex2.X))
Swap(ref vertex0, ref vertex0);
}
}
return points;
}
c# wpf graphics 3d writeablebitmap
I have faced a problem with WriteableBitmap. I am trying to render a 3d cube. But when pixels is being written to WriteableBitmap, part of them just shift.
Initialized cube:
And that what's happening, when I am trying to rotate it by 45 degrees along x.
Problem appears for all kind of rotation, except y (rotation by 10 degrees along z)
I have tested same points with usual Bitmap and SetPixel() method. That's what I get after rotating cube along 45 degrees by three axis. I don't see any problems here
I think that problem can be with my writeableBitmap pixels setting algorithm (maybe problem with pixel offset?).
Second image with grey background:
What I am expecting from cube rotated by 45 deegres along x. Red line - edge. Text - facets
WriteableBitmap drawing algorithm:
public WriteableBitmap DrawSceneByPoints(int width, int height, List<MPoint> points)
{
WriteableBitmap wBitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
Int32Rect rect = new Int32Rect(0, 0, width, height);
var stride = (rect.Width * wBitmap.Format.BitsPerPixel + 7) / 8;
byte pixels = new byte[rect.Height * stride];
// For user: Moves 0,0 point from top-left to bottom-left
for (int i = 0; i < points.Count; ++i)
points[i].Y = height - points[i].Y;
int alpha = 255;
int red = 0;
int green = 0;
int blue = 0;
for (int i = 0; i < points.Count; ++i)
{
int pixelOffset = (int)(points[i].X + points[i].Y * wBitmap.PixelWidth) * wBitmap.Format.BitsPerPixel / 8;
pixels[pixelOffset] = (byte)blue;
pixels[pixelOffset + 1] = (byte)green;
pixels[pixelOffset + 2] = (byte)red;
pixels[pixelOffset + 3] = (byte)alpha;
}
wBitmap.WritePixels(rect, pixels, stride, 0);
return wBitmap;
}
Usual bitmap drawing algorithm:
public Bitmap DrawSceneByPointsBitmap(int width, int height, List<MPoint> points)
{
Bitmap bitmap = new Bitmap(width, height);
// For user: Moves 0,0 point from top-left to bottom-left
for (int i = 0; i < points.Count; ++i)
points[i].Y = height - points[i].Y;
for (int i = 0; i < points.Count; ++i)
bitmap.SetPixel((int)points[i].X, (int)points[i].Y, System.Drawing.Color.White);
return bitmap;
}
Scene Render method:
public WriteableBitmap Render()
{
new ShapeEditor().TransformShapes(Shapes, CurrentCamera);
List<MPoint> allPoints = GetAllPoints();
return new Painter().DrawSceneByPoints(this.Width, this.Height, allPoints);
}
Line rastrizer:
class BresenhamLine : ILineRasterizer
{
public List<MPoint> GetLine(MPoint point1, MPoint point2)
{
return Bresenham3D((int)point1.X, (int)point1.Y, (int)point1.Z, (int)point2.X, (int)point2.Y, (int)point2.Z);
}
private List<MPoint> Bresenham3D(int x1, int y1, int z1, int x2, int y2, int z2)
{
var points = new List<MPoint>();
float x0 = x1, y0 = y1, z0 = z1;
int i, dx, dy, dz, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
int point = new int[3];
point[0] = x1;
point[1] = y1;
point[2] = z1;
dx = x2 - x1;
dy = y2 - y1;
dz = z2 - z1;
x_inc = (dx < 0) ? -1 : 1;
l = Math.Abs(dx);
y_inc = (dy < 0) ? -1 : 1;
m = Math.Abs(dy);
z_inc = (dz < 0) ? -1 : 1;
n = Math.Abs(dz);
dx2 = l << 1;
dy2 = m << 1;
dz2 = n << 1;
if ((l >= m) && (l >= n))
{
err_1 = dy2 - l;
err_2 = dz2 - l;
for (i = 0; i < l; i++)
{
points.Add(new MPoint(point[0], point[1], point[2]));
if (err_1 > 0)
{
point[1] += y_inc;
err_1 -= dx2;
}
if (err_2 > 0)
{
point[2] += z_inc;
err_2 -= dx2;
}
err_1 += dy2;
err_2 += dz2;
point[0] += x_inc;
}
}
else if ((m >= l) && (m >= n))
{
err_1 = dx2 - m;
err_2 = dz2 - m;
for (i = 0; i < m; i++)
{
points.Add(new MPoint(point[0], point[1], point[2]));
if (err_1 > 0)
{
point[0] += x_inc;
err_1 -= dy2;
}
if (err_2 > 0)
{
point[2] += z_inc;
err_2 -= dy2;
}
err_1 += dx2;
err_2 += dz2;
point[1] += y_inc;
}
}
else
{
err_1 = dy2 - n;
err_2 = dx2 - n;
for (i = 0; i < n; i++)
{
points.Add(new MPoint(point[0], point[1], point[2]));
if (err_1 > 0)
{
point[1] += y_inc;
err_1 -= dz2;
}
if (err_2 > 0)
{
point[0] += x_inc;
err_2 -= dz2;
}
err_1 += dy2;
err_2 += dx2;
point[2] += z_inc;
}
}
return points;
}
private void Swap<T>(ref T l, ref T r)
{
T temp = l;
l = r;
r = temp;
}
}
Polygon rasterizer:
public List<MPoint> RasterizePolygon(MFacet triangle)
{
var points = new List<MPoint>();
Vector2 vertex0 = new Vector2(triangle.Vertices[0].X, triangle.Vertices[0].Y),
vertex1 = new Vector2(triangle.Vertices[1].X, triangle.Vertices[1].Y),
vertex2 = new Vector2(triangle.Vertices[2].X, triangle.Vertices[2].Y);
if (vertex0.Y == vertex1.Y && vertex0.Y == vertex2.Y) return new BresenhamLine().GetLine(triangle.Vertices[0], triangle.Vertices[2]);
// sort the vertices, vertex0, vertex1, vertex2 lower-to-upper
if (vertex0.Y > vertex1.Y) Swap(ref vertex0, ref vertex1);
if (vertex0.Y > vertex2.Y) Swap(ref vertex0, ref vertex2);
if (vertex1.Y > vertex2.Y) Swap(ref vertex1, ref vertex2);
int total_height = (int)(vertex2.Y - vertex0.Y);
for (int i = 0; i < total_height; i++)
{
bool second_half = i > vertex1.Y - vertex0.Y || vertex1.Y == vertex0.Y;
int segment_height = second_half ? (int)(vertex2.Y - vertex1.Y) : (int)(vertex1.Y - vertex0.Y);
float alpha = (float)i / total_height;
float beta = (float)(i - (second_half ? vertex1.Y - vertex0.Y : 0)) / segment_height; // be careful: with above conditions no division by zero here
Vector2 A = vertex0 + (vertex2 - vertex0) * alpha;
Vector2 B = second_half ? vertex1 + (vertex2 - vertex1) * beta : vertex0 + (vertex1 - vertex0) * beta;
if (A.X > B.X) Swap(ref A, ref B);
for (int j = (int)A.X; j <= B.X; j++)
{
points.Add(new MPoint(j, vertex0.Y + i, 1));
if (j > B.X || (A.X < vertex0.X && A.X < vertex1.X && A.X < vertex2.X))
Swap(ref vertex0, ref vertex0);
}
}
return points;
}
c# wpf graphics 3d writeablebitmap
c# wpf graphics 3d writeablebitmap
edited Nov 24 '18 at 15:16
Dmitry
asked Nov 24 '18 at 14:13
DmitryDmitry
183
183
There is nothing wrong. The problem is you background it white and some of the cube sides are white. So you cannot see where the side of the cube end and the background starts. Make you background grey, and alternate the sides of the cube black and white and the problem will go away.
– jdweng
Nov 24 '18 at 14:44
@jdweng I tried this, but that doesn't help. My cube is black by default. I used cube with white sides for bitmap. Cause bitmap's background is black by default. I'll add picture with grey background to original question
– Dmitry
Nov 24 '18 at 14:56
Is you sides transparent. The cube with grey background (left) make the top side white so you can see it. How do you know where the top side ends and the background starts when both are grey?
– jdweng
Nov 24 '18 at 15:02
@jdweng No, sides are not transparant, all sides are black. And I have only one cube. Left cube is a missing part of a cube in the center. I also don't have any of unseen line removing algorithm. I've also added picture with what cube I expect
– Dmitry
Nov 24 '18 at 15:16
It doesn't look like it is missing to me except if the initialized cube doesn't have 6 faces. The rotation by 10 degrees show two faces. A black front face and a white rear faces. Where are the other 4 faces? The line on the left is the edge of one side. The 45 degrees view which you says is good you are only seeing 3 faces. The bottom, rear, and right. The front, top, and left are missing.
– jdweng
Nov 24 '18 at 20:29
add a comment |
There is nothing wrong. The problem is you background it white and some of the cube sides are white. So you cannot see where the side of the cube end and the background starts. Make you background grey, and alternate the sides of the cube black and white and the problem will go away.
– jdweng
Nov 24 '18 at 14:44
@jdweng I tried this, but that doesn't help. My cube is black by default. I used cube with white sides for bitmap. Cause bitmap's background is black by default. I'll add picture with grey background to original question
– Dmitry
Nov 24 '18 at 14:56
Is you sides transparent. The cube with grey background (left) make the top side white so you can see it. How do you know where the top side ends and the background starts when both are grey?
– jdweng
Nov 24 '18 at 15:02
@jdweng No, sides are not transparant, all sides are black. And I have only one cube. Left cube is a missing part of a cube in the center. I also don't have any of unseen line removing algorithm. I've also added picture with what cube I expect
– Dmitry
Nov 24 '18 at 15:16
It doesn't look like it is missing to me except if the initialized cube doesn't have 6 faces. The rotation by 10 degrees show two faces. A black front face and a white rear faces. Where are the other 4 faces? The line on the left is the edge of one side. The 45 degrees view which you says is good you are only seeing 3 faces. The bottom, rear, and right. The front, top, and left are missing.
– jdweng
Nov 24 '18 at 20:29
There is nothing wrong. The problem is you background it white and some of the cube sides are white. So you cannot see where the side of the cube end and the background starts. Make you background grey, and alternate the sides of the cube black and white and the problem will go away.
– jdweng
Nov 24 '18 at 14:44
There is nothing wrong. The problem is you background it white and some of the cube sides are white. So you cannot see where the side of the cube end and the background starts. Make you background grey, and alternate the sides of the cube black and white and the problem will go away.
– jdweng
Nov 24 '18 at 14:44
@jdweng I tried this, but that doesn't help. My cube is black by default. I used cube with white sides for bitmap. Cause bitmap's background is black by default. I'll add picture with grey background to original question
– Dmitry
Nov 24 '18 at 14:56
@jdweng I tried this, but that doesn't help. My cube is black by default. I used cube with white sides for bitmap. Cause bitmap's background is black by default. I'll add picture with grey background to original question
– Dmitry
Nov 24 '18 at 14:56
Is you sides transparent. The cube with grey background (left) make the top side white so you can see it. How do you know where the top side ends and the background starts when both are grey?
– jdweng
Nov 24 '18 at 15:02
Is you sides transparent. The cube with grey background (left) make the top side white so you can see it. How do you know where the top side ends and the background starts when both are grey?
– jdweng
Nov 24 '18 at 15:02
@jdweng No, sides are not transparant, all sides are black. And I have only one cube. Left cube is a missing part of a cube in the center. I also don't have any of unseen line removing algorithm. I've also added picture with what cube I expect
– Dmitry
Nov 24 '18 at 15:16
@jdweng No, sides are not transparant, all sides are black. And I have only one cube. Left cube is a missing part of a cube in the center. I also don't have any of unseen line removing algorithm. I've also added picture with what cube I expect
– Dmitry
Nov 24 '18 at 15:16
It doesn't look like it is missing to me except if the initialized cube doesn't have 6 faces. The rotation by 10 degrees show two faces. A black front face and a white rear faces. Where are the other 4 faces? The line on the left is the edge of one side. The 45 degrees view which you says is good you are only seeing 3 faces. The bottom, rear, and right. The front, top, and left are missing.
– jdweng
Nov 24 '18 at 20:29
It doesn't look like it is missing to me except if the initialized cube doesn't have 6 faces. The rotation by 10 degrees show two faces. A black front face and a white rear faces. Where are the other 4 faces? The line on the left is the edge of one side. The 45 degrees view which you says is good you are only seeing 3 faces. The bottom, rear, and right. The front, top, and left are missing.
– jdweng
Nov 24 '18 at 20:29
add a comment |
1 Answer
1
active
oldest
votes
I use writeablebitmap to convert a 2d array of elevations into a hypsometric picture. Colour represents height.
I recommend working with a 2d array which represents your scene and just iterate through that.
There are 4 bytes per pixel for bgra32.
WriteableBitmap WBM = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
byte pixels = new byte[width * height * 4];
double perColour = (double)(max - min) / 254d;
Color ca = Application.Current.Resources["HypsoColours"] as Color;
int ix = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int elv = elevations[x, y];
int eff = elv - min;
int ptr = 0;
if (eff> 0)
{
ptr = (int)((elv - min) / perColour);
}
Color colour = ca[ptr];
pixels[ix] = colour.B;
ix++;
pixels[ix] = colour.G;
ix++;
pixels[ix] = colour.R;
ix++;
pixels[ix] = 255;
ix++;
}
}
WBM.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * 4, 0);
WBM.Freeze();
return WBM;
Yeah, strict iterating through array helped me (at least for now). Thank you!
– Dmitry
Nov 24 '18 at 19:25
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53459044%2fpixels-shift-in-writeablebitmap%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I use writeablebitmap to convert a 2d array of elevations into a hypsometric picture. Colour represents height.
I recommend working with a 2d array which represents your scene and just iterate through that.
There are 4 bytes per pixel for bgra32.
WriteableBitmap WBM = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
byte pixels = new byte[width * height * 4];
double perColour = (double)(max - min) / 254d;
Color ca = Application.Current.Resources["HypsoColours"] as Color;
int ix = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int elv = elevations[x, y];
int eff = elv - min;
int ptr = 0;
if (eff> 0)
{
ptr = (int)((elv - min) / perColour);
}
Color colour = ca[ptr];
pixels[ix] = colour.B;
ix++;
pixels[ix] = colour.G;
ix++;
pixels[ix] = colour.R;
ix++;
pixels[ix] = 255;
ix++;
}
}
WBM.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * 4, 0);
WBM.Freeze();
return WBM;
Yeah, strict iterating through array helped me (at least for now). Thank you!
– Dmitry
Nov 24 '18 at 19:25
add a comment |
I use writeablebitmap to convert a 2d array of elevations into a hypsometric picture. Colour represents height.
I recommend working with a 2d array which represents your scene and just iterate through that.
There are 4 bytes per pixel for bgra32.
WriteableBitmap WBM = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
byte pixels = new byte[width * height * 4];
double perColour = (double)(max - min) / 254d;
Color ca = Application.Current.Resources["HypsoColours"] as Color;
int ix = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int elv = elevations[x, y];
int eff = elv - min;
int ptr = 0;
if (eff> 0)
{
ptr = (int)((elv - min) / perColour);
}
Color colour = ca[ptr];
pixels[ix] = colour.B;
ix++;
pixels[ix] = colour.G;
ix++;
pixels[ix] = colour.R;
ix++;
pixels[ix] = 255;
ix++;
}
}
WBM.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * 4, 0);
WBM.Freeze();
return WBM;
Yeah, strict iterating through array helped me (at least for now). Thank you!
– Dmitry
Nov 24 '18 at 19:25
add a comment |
I use writeablebitmap to convert a 2d array of elevations into a hypsometric picture. Colour represents height.
I recommend working with a 2d array which represents your scene and just iterate through that.
There are 4 bytes per pixel for bgra32.
WriteableBitmap WBM = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
byte pixels = new byte[width * height * 4];
double perColour = (double)(max - min) / 254d;
Color ca = Application.Current.Resources["HypsoColours"] as Color;
int ix = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int elv = elevations[x, y];
int eff = elv - min;
int ptr = 0;
if (eff> 0)
{
ptr = (int)((elv - min) / perColour);
}
Color colour = ca[ptr];
pixels[ix] = colour.B;
ix++;
pixels[ix] = colour.G;
ix++;
pixels[ix] = colour.R;
ix++;
pixels[ix] = 255;
ix++;
}
}
WBM.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * 4, 0);
WBM.Freeze();
return WBM;
I use writeablebitmap to convert a 2d array of elevations into a hypsometric picture. Colour represents height.
I recommend working with a 2d array which represents your scene and just iterate through that.
There are 4 bytes per pixel for bgra32.
WriteableBitmap WBM = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
byte pixels = new byte[width * height * 4];
double perColour = (double)(max - min) / 254d;
Color ca = Application.Current.Resources["HypsoColours"] as Color;
int ix = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int elv = elevations[x, y];
int eff = elv - min;
int ptr = 0;
if (eff> 0)
{
ptr = (int)((elv - min) / perColour);
}
Color colour = ca[ptr];
pixels[ix] = colour.B;
ix++;
pixels[ix] = colour.G;
ix++;
pixels[ix] = colour.R;
ix++;
pixels[ix] = 255;
ix++;
}
}
WBM.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * 4, 0);
WBM.Freeze();
return WBM;
answered Nov 24 '18 at 18:46
AndyAndy
3,3071107
3,3071107
Yeah, strict iterating through array helped me (at least for now). Thank you!
– Dmitry
Nov 24 '18 at 19:25
add a comment |
Yeah, strict iterating through array helped me (at least for now). Thank you!
– Dmitry
Nov 24 '18 at 19:25
Yeah, strict iterating through array helped me (at least for now). Thank you!
– Dmitry
Nov 24 '18 at 19:25
Yeah, strict iterating through array helped me (at least for now). Thank you!
– Dmitry
Nov 24 '18 at 19:25
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53459044%2fpixels-shift-in-writeablebitmap%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
There is nothing wrong. The problem is you background it white and some of the cube sides are white. So you cannot see where the side of the cube end and the background starts. Make you background grey, and alternate the sides of the cube black and white and the problem will go away.
– jdweng
Nov 24 '18 at 14:44
@jdweng I tried this, but that doesn't help. My cube is black by default. I used cube with white sides for bitmap. Cause bitmap's background is black by default. I'll add picture with grey background to original question
– Dmitry
Nov 24 '18 at 14:56
Is you sides transparent. The cube with grey background (left) make the top side white so you can see it. How do you know where the top side ends and the background starts when both are grey?
– jdweng
Nov 24 '18 at 15:02
@jdweng No, sides are not transparant, all sides are black. And I have only one cube. Left cube is a missing part of a cube in the center. I also don't have any of unseen line removing algorithm. I've also added picture with what cube I expect
– Dmitry
Nov 24 '18 at 15:16
It doesn't look like it is missing to me except if the initialized cube doesn't have 6 faces. The rotation by 10 degrees show two faces. A black front face and a white rear faces. Where are the other 4 faces? The line on the left is the edge of one side. The 45 degrees view which you says is good you are only seeing 3 faces. The bottom, rear, and right. The front, top, and left are missing.
– jdweng
Nov 24 '18 at 20:29