注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

简单代码

寻找代码的灵魂

 
 
 

日志

 
 
关于我

对于本博客内所有原创文章和代码的引用必须标明“来源:http://simplesource.blog.163.com/”。如需应用于商业目的必须经本人同意,本人对所有原创文章和代码保留一切权利。 PS:需要部分程序源代码的请留下邮箱地址

用CDC::PlgBlt实现三角形贴图  

2009-12-25 17:03:37|  分类: 技术文献 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

CDC::PlgBlt函数可以实现将资源设备中的一个方形区域映射到目标设备上的一个平行四边形区域中,而这个函数还提供了一个遮罩位图,利用这个功能再加上合适的计算可以实现将资源位图中的任意一个三角形区域映射到目标设备上的任意三角形区域。而这个功能正是3D绘图中最基本的“三角形贴图”。

算法简要思路:

我们要实现的功能是:将资源设备中ABC三角形映射到目标设备中的A’B’C’三角形区域,而我们可以使用的工具PlgBlt只能将资源设备中的方形区域映射到目标设备中的平行四边形区域,如图

用CDC::PlgBlt实现三角形贴图 - 简单代码 - 简单代码

注意到虽然PlgBlt的功能是复制方形区域到一个平行四边形区域,但是我们可以通过在遮罩位图上绘制一个三角形来实现只绘制特定的三角形区域,如图:

用CDC::PlgBlt实现三角形贴图 - 简单代码 - 简单代码

可是光这样做还不行,那会导致三角形的映射关系混乱,因为我们只能把资源中方形的的左上角映射到目标设备的A’点,而现在我们在资源设备中选中的A点已经偏离了方形的左上角。

所以我们要重新计算目标设备的映射点a’b’c’,使得资源设备上方形的三个角abc映射到目标设备的a’b’c’时可以保证资源设备的ABC三点可以映射到目标设备的A’B’C’点。如图

用CDC::PlgBlt实现三角形贴图 - 简单代码 - 简单代码

这是一个坐标系转换的过程,很容易联想到OpenGL中的矩阵,我们知道矩阵的作用之一就是坐标系的转换,所以这个过程可以利用矩阵来实现。

  于是我们需要计算一个转换矩阵T,使得ABC乘以T等于A’B’C’,可以写成如下形式

用CDC::PlgBlt实现三角形贴图 - 简单代码 - 简单代码

之所以加上1,是为了方便矩阵运算,这个与OpenGL中的矩阵是4维的是一个道理。

  利用选主元消去法解这个方程计算出T。得到T之后就可以计算出a’b’c’点的坐标,计算公式如下

  a’ = a×T

  b’ = b×T

  c’ = c×T

最后用a’b’c’点的坐标作为PlgBlt的参数就可以实现前面所说的“三角形贴图”功能了

程序截图:

用CDC::PlgBlt实现三角形贴图 - 简单代码 - 简单代码

根据以上原理写的三角形贴图函数:

    // 三角形贴图

    bool TriangleBlt(

        CDC & dc                                                 // 目标设备上下文

        , int x0, int y0, int x1, int y1, int x2, int y2         // 目标三角形

        , CDC & dcSource                                         // 资源设备上下文

        , int sx0, int sy0, int sx1, int sy1, int sx2, int sy2   // 资源三角形

        )

    {

        // 生成转换矩阵

        double A[3][3];

        double B[3][3];

        double T[3], m;

        int minx, miny, maxx, maxy;

        minx = sx0 < sx1 ? sx0 : sx1, miny = sy0 < sy1 ? sy0 : sy1;

        maxx = sx0 > sx1 ? sx0 : sx1, maxy = sy0 > sy1 ? sy0 : sy1;

        if(minx > sx2)

        {

            minx = sx2;

        }

        if(maxx < sx2)

        {

            maxx = sx2;

        }

        if(miny > sy2)

        {

            miny = sy2;

        }

        if(maxy < sy2)

        {

            maxy = sy2;

        }

        if(maxx == minx || maxy == miny)

        {

            return false;

        }

        A[0][0] = sx0, A[0][1] = sy0, A[0][2] = 1;

        A[1][0] = sx1, A[1][1] = sy1, A[1][2] = 1;

        A[2][0] = sx2, A[2][1] = sy2, A[2][2] = 1;

 

        B[0][0] = x0, B[0][1] = y0, B[0][2] = 1;

        B[1][0] = x1, B[1][1] = y1, B[1][2] = 1;

        B[2][0] = x2, B[2][1] = y2, B[2][2] = 1;

        int i, j, k;

        for(i = 0; i < 3; i++)

        {

            k = i;

            for(j = i + 1; j < 3; j++)

            {

                if(A[k][i] < A[j][i])

                {

                    k = j;

                }

            }

            if(A[k][i] == 0)

            {

                return false;

            }

            // 换行

            memcpy(T, A[k], sizeof(T));

            memcpy(A[k], A[i], sizeof(T));

            memcpy(A[i], T, sizeof(T));

            memcpy(T, B[k], sizeof(T));

            memcpy(B[k], B[i], sizeof(T));

            memcpy(B[i], T, sizeof(T));

            // 消去

            m = A[i][i];

            for(j = 0; j < 3; j++)

            {

                A[i][j] /= m;

                B[i][j] /= m;

            }

            for(j =0; j < 3; j++)

            {

                if(j != i)

                {

                    m = A[j][i];

                    for(k = 0; k < 3; k++)

                    {

                        A[j][k] -= A[i][k] * m;

                        B[j][k] -= B[i][k] * m;

                    }

                }

            }

        }

        // 生成遮罩位图

        CBitmap bmpMask;

        int w = maxx - minx, h = maxy - miny;

        bmpMask.CreateBitmap(w, h, 1, 1, NULL);

        CDC dcMask;

        dcMask.CreateCompatibleDC(&dc);

        dcMask.SelectObject(&bmpMask);

        CPen pen(PS_SOLID, 1, RGB(255, 255, 255));

        dcMask.SelectObject(&pen);

        dcMask.FillSolidRect(0, 0, w, h, RGB(0, 0, 0));

        CPoint pts[3];

        pts[0].x = sx0 - minx;

        pts[0].y = sy0 - miny;

        pts[1].x = sx1 - minx;

        pts[1].y = sy1 - miny;

        pts[2].x = sx2 - minx;

        pts[2].y = sy2 - miny;

        dcMask.Polygon(pts, 3);

        // 绘制

        pts[0].x = int(minx * B[0][0] + miny * B[1][0] + B[2][0]);

        pts[0].y = int(minx * B[0][1] + miny * B[1][1] + B[2][1]);

        pts[1].x = int(maxx * B[0][0] + miny * B[1][0] + B[2][0]);

        pts[1].y = int(maxx * B[0][1] + miny * B[1][1] + B[2][1]);

        pts[2].x = int(minx * B[0][0] + maxy * B[1][0] + B[2][0]);

        pts[2].y = int(minx * B[0][1] + maxy * B[1][1] + B[2][1]);

        dc.PlgBlt(pts, &dcSource, minx, miny, w, h, bmpMask, 0, 0);

        return true;

    }

PS:函数只是随手写写的,可能会有很多BUG

PPS:具体程序和源代码将在下一篇博客中给出

  评论这张
 
阅读(2896)| 评论(1)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018