Pixels shift in WriteableBitmap












0















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:



Initialized cube



And that what's happening, when I am trying to rotate it by 45 degrees along x.
cube, rotated by 45 degrees along x



Problem appears for all kind of rotation, except y (rotation by 10 degrees along z)
cube, rotated 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



enter image description here



I think that problem can be with my writeableBitmap pixels setting algorithm (maybe problem with pixel offset?).



Second image with grey background:



Second image with grey background



What I am expecting from cube rotated by 45 deegres along x. Red line - edge. Text - facets
What I am expecting





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;
}









share|improve this question

























  • 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
















0















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:



Initialized cube



And that what's happening, when I am trying to rotate it by 45 degrees along x.
cube, rotated by 45 degrees along x



Problem appears for all kind of rotation, except y (rotation by 10 degrees along z)
cube, rotated 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



enter image description here



I think that problem can be with my writeableBitmap pixels setting algorithm (maybe problem with pixel offset?).



Second image with grey background:



Second image with grey background



What I am expecting from cube rotated by 45 deegres along x. Red line - edge. Text - facets
What I am expecting





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;
}









share|improve this question

























  • 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














0












0








0








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:



Initialized cube



And that what's happening, when I am trying to rotate it by 45 degrees along x.
cube, rotated by 45 degrees along x



Problem appears for all kind of rotation, except y (rotation by 10 degrees along z)
cube, rotated 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



enter image description here



I think that problem can be with my writeableBitmap pixels setting algorithm (maybe problem with pixel offset?).



Second image with grey background:



Second image with grey background



What I am expecting from cube rotated by 45 deegres along x. Red line - edge. Text - facets
What I am expecting





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;
}









share|improve this question
















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:



Initialized cube



And that what's happening, when I am trying to rotate it by 45 degrees along x.
cube, rotated by 45 degrees along x



Problem appears for all kind of rotation, except y (rotation by 10 degrees along z)
cube, rotated 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



enter image description here



I think that problem can be with my writeableBitmap pixels setting algorithm (maybe problem with pixel offset?).



Second image with grey background:



Second image with grey background



What I am expecting from cube rotated by 45 deegres along x. Red line - edge. Text - facets
What I am expecting





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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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



















  • 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












1 Answer
1






active

oldest

votes


















1














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;







share|improve this answer
























  • Yeah, strict iterating through array helped me (at least for now). Thank you!

    – Dmitry
    Nov 24 '18 at 19:25











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
});


}
});














draft saved

draft discarded


















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









1














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;







share|improve this answer
























  • Yeah, strict iterating through array helped me (at least for now). Thank you!

    – Dmitry
    Nov 24 '18 at 19:25
















1














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;







share|improve this answer
























  • Yeah, strict iterating through array helped me (at least for now). Thank you!

    – Dmitry
    Nov 24 '18 at 19:25














1












1








1







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;







share|improve this answer













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;








share|improve this answer












share|improve this answer



share|improve this answer










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



















  • 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




















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Create new schema in PostgreSQL using DBeaver

Deepest pit of an array with Javascript: test on Codility

Costa Masnaga