2011-09-07 34 views
0

我期望做的事听起来很简单,但是到目前为止,在互联网上没有找到一种方法可以在DotNet中做到这一点,也没有发现第三方组件可以做到这一点(无需花费数千个完全不必要的功能)。 这里有:如何在C#或VB.Net中进行3D变换(透视图)?

我有一个地板瓷砖(实际照片),我创建了棋盘格局的jpeg。 在dotnet中,很容易旋转和拼接照片,并将最终图像保存为jpeg。

接下来,我想拍摄最终的照片,并使其看起来好像“瓷砖”铺设在通用“房间场景”的地板上。基本上增加一个3D透视图,使其看起来好像它实际上在房间场景中。

继承人一个网站,做与地毯类似的东西,但我必须这样做的WinForms应用程序:基本上 Flor Website

,我需要创建一个JPEG的3D透视图,然后保存为一个新的jpeg(然后我可以放置一般的房间场景)。

任何人都知道在哪里可以获得第三方DotNet图像处理模块,可以做这看似简单的任务?

回答

4

这并不是那么简单,因为您需要一个3D转换,它比简单的2D转换(如旋转,缩放或剪切)更复杂且计算更昂贵。为了让您对数学的差异有所了解,2D变换需要2 x 2矩阵,而投影变换(比其他3D变换更复杂)需要4 x 4矩阵...

你需要的是一些3D渲染引擎,您可以在其中绘制多边形(在透视图中),并用纹理(如地毯)覆盖它们。对于.Net 2.0,我推荐使用SlimDX,它是DirectX的一个端口,可以让你渲染多边形,但是有一些学习曲线。如果您使用的是WPF(.Net 3.0及更高版本),则可以使用内置的3D画布,让您以透视的方式绘制纹理多边形。为了您的目的,这可能比SlimDX更容易/更好地学习。我相信有一种方法可以将3D画布的输出重定向到jpeg ...

如果您不需要很好的性能,并且如果限制纹理(例如,总是一个水平的地板或总是一个垂直的墙壁)。如果是这样,你可以使用.Net 2.0中的简单绘图循环自己渲染它。

+0

+1。 ,使用Direct3D或OpenGL几乎肯定会比试图手动编写自己的透视投影纹理渲染更容易(并给出更好的结果),这也使您可以选择稍后添加诸如照明和凹凸映射之类的东西t的感觉exture)。 –

3

如果你只是想要一个普通的地板,你的代码应该是这样的。警告:获得理想的结果需要花费大量的时间和精力,特别是如果你不太了解数学。但在另一方面,它总是充满乐趣与这种类型的代码打...(:

下面的一些样本图像

using System; 
using System.Collections.Generic; 
using System.Drawing; 
using System.Windows.Forms; 

namespace floorDrawer 
{ 
public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 

     ResizeRedraw = DoubleBuffered = true; 

     Width = 800; 
     Height = 600; 

     Paint += new PaintEventHandler(Form1_Paint); 

    } 

    void Form1_Paint(object sender, PaintEventArgs e) 
    { 

     // a few parameters that control the projection transform 
     // these are the parameters that you can modify to change 
     // the output 

     double cz = 10; // distortion 
     double m = 1000; // magnification, usually around 1000 (the pixel width of the monitor) 

     double y0 = -100; // floor height 

     string texturePath = @"c:\pj\Hydrangeas.jpg";//@"c:\pj\Chrysanthemum.jpg"; 


     // screen size 
     int height = ClientSize.Height; 
     int width = ClientSize.Width; 

     // center of screen 
     double cx = width/2; 
     double cy = height/2; 



     // render destination 
     var dst = new Bitmap(width, height); 

     // source texture 

     var src = Bitmap.FromFile(texturePath) as Bitmap; 

     // texture dimensions 
     int tw = src.Width; 
     int th = src.Height; 

     for (int y = 0; y < height; y++) 
      for (int x = 0; x < width; x++) 
      { 
       double v = m * y0/(y - cy) - cz; 
       double u = (x - cx) * (v + cz)/m; 

       int uu = ((int)u % tw + tw) % tw; 
       int vv = ((int)v % th + th) % th; 
       // The following .SetPixel() and .GetPixel() are painfully slow 
       // You can replace this whole loop with an equivalent implementation 
       // using pointers inside unsafe{} code to make it much faster. 
       // Note that by casting u and v into integers, we are performing 
       // a nearest pixel interpolation... It's sloppy but effective. 

       dst.SetPixel(x, y, src.GetPixel(uu, vv)); 
      } 

     // draw result on the form 
     e.Graphics.DrawImage(dst, 0, 0); 
    } 

} 
} 

This is a sample output using one of Windows 7 sample images.

Another example using another Windows 7 sample picture.

+0

而不是逐像素地做这个像素,你只需要计算角点,然后计算适当的2D矩阵并设置'Graphics.transform'来完成它并执行DrawImage()。甚至可能会有一个DrawImage()调用绘制成倾斜的矩形。对不起我的3D数学是20岁,我的Windows编程10. – NPAssoc

+0

@NPAssoc我在几年前写了这个解决方案,我想我只是炫耀我的“像素逐像素3D技能”。为了渲染一个3d投影,据我所知,你需要一个4乘4的仿射矩阵。我同意设置渲染矩阵是一般的方法,但我不认为System.Drawing.Graphics支持4x4变换矩阵。较新的WPF框架确实可以做到这一点。 –

+0

@NPAssoc我刚刚注意到“歪斜的矩形”的评论。对于倾斜的矩形,您可以使用“剪切”转换。剪切操作可以用2x2矩阵完成,并且可以通过System.Drawing.Graphics轻松处理。请注意,剪切操作与透视仿射投影不同,后者需要我上面的注释以及其他解决方案中提到的4x4变换。 –