MFC实现三维图像绘制(4)面的绘制

阅读: 评论:0

MFC实现三维图像绘制(4)面的绘制

MFC实现三维图像绘制(4)面的绘制

绘制物体的面时考虑两个问题:

1. 如何绘制?

2. 如何消隐不可见面?

针对这两个问题,分别采取有效边表算法和Z-Buffer缓冲器算法。

有效边表:

#include "Pi3.h"
#include "T2.h"class CAET
{
public:CAET();virtual ~CAET();
public:double  x;//当前扫描线与有效边交点的x坐标int     yMax;//边的最大y值double  k;//斜率的倒数(x的增量)CPi3    ps;//边的起点CPi3    pe;//边的终点CAET   *pNext;CT2 ts;//起点纹理坐标CT2 te;//终点纹理坐标
};

桶表:

#include "AET.h"
class CBucket
{
public:CBucket();virtual ~CBucket();
public:int     ScanLine;     //扫描线CAET    *pET;         //桶上的边表指针CBucket *pNext;
};

具体绘制实现(这里涉及到物体的光照和纹理模型):

#include "Bucket.h"
#include "Vector3.h"
#include "Lighting.h"
#include "Pi3.h"
#include "Texture.h"
#include "T2.h"class CFill
{
public:CFill(void);virtual ~CFill(void);void SetPoint(CPi3 *p, int, CT2*);//类的初始化void SetPoint(CPi3* p, int);//类的初始化void CreateBucket();//创建桶void CreateEdge();//边表void AddEt(CAET *);//合并ET表void EtOrder();//ET表排序void Gouraud(CDC *, int,CLighting, CMaterial*,CP3, CTexture*,BOOL);//填充多边形void Gouraud(CDC*, int, CLighting, CMaterial*, CP3);//填充多边形CRGB Interpolation(double, double, double, CRGB, CRGB);//颜色线性插值double Interpolation(double, double, double, double, double);//深度线性插值CVector3 Interpolation(double, double, double, CVector3, CVector3);//法向量线性插值CT2 Interpolation(double m, double m0, double m1, CT2 T0, CT2 T1);//纹理地址线性插值void ClearMemory();//清理内存void DeleteAETChain(CAET* pAET);//删除边表CRGB GetTextureColor(double u, double v, CTexture* pTexture);//获得纹理颜色void InitialDepthBuffer(int nWidth, int nHeight, double zDepth);//初始化深度缓冲器
public:int     PNum;//顶点个数CT2* T;//纹理动态数组CPi3    *P;//顶点坐标动态数组CAET    *pHeadE, *pCurrentE, *pEdge; //有效边表结点指针CBucket *pHeadB, *pCurrentB;        //桶表结点指针double** zBuffer;//深度缓冲器int nWidth, nHeight;//缓冲区宽度与高度
};
#include "pch.h"
#include "Fill.h"
#include "math.h"
#define ROUND(f) int(floor(f+0.5))//四舍五入宏定义CFill::CFill(void)
{PNum = 0;P = NULL;pEdge = NULL;pHeadB = NULL;pHeadE = NULL;
}CFill::~CFill(void)
{if (P != NULL){delete[] P;P = NULL;}for (int i = 0;i < nWidth;i++){delete[] zBuffer[i];zBuffer[i] = NULL;}if (zBuffer != NULL){delete zBuffer;zBuffer = NULL;}ClearMemory();
}void CFill::SetPoint(CPi3 *p, int m, CT2* t)
{if (P != NULL){delete[] P;P = NULL;}P = new CPi3[m];//创建一维动态数组T = new CT2[m];for (int i = 0; i < m; i++){P[i] = p[i];P[i].y = ROUND(P[i].y);T[i] = t[i];}PNum = m;
}void CFill::SetPoint(CPi3* p, int m)
{if (P != NULL){delete[] P;P = NULL;}P = new CPi3[m];//创建一维动态数组for (int i = 0; i < m; i++){P[i] = p[i];P[i].y = ROUND(P[i].y);}PNum = m;
}void CFill::CreateBucket()//创建桶表
{int yMin, yMax;yMin = yMax = P[0].y;for (int i = 0; i < PNum; i++)//查找多边形所覆盖的最小和最大扫描线{if (P[i].y < yMin){yMin = P[i].y;//扫描线的最小值}if (P[i].y > yMax){yMax = P[i].y;//扫描线的最大值}}for (int y = yMin; y <= yMax; y++){if (yMin == y)//如果是扫描线的最小值{pHeadB = new CBucket;//建立桶的头结点pCurrentB = pHeadB;//pCurrentB为CBucket当前结点指针pCurrentB->ScanLine = yMin;pCurrentB->pET = NULL;//没有链接边表pCurrentB->pNext = NULL;}else//其他扫描线{pCurrentB->pNext = new CBucket;//建立桶的其他结点pCurrentB = pCurrentB->pNext;pCurrentB->ScanLine = y;pCurrentB->pET = NULL;pCurrentB->pNext = NULL;}}
}void CFill::CreateEdge()//创建边表
{for (int i = 0; i < PNum; i++){pCurrentB = pHeadB;int j = (i + 1) % PNum;//边的第2个顶点,P[i]和P[j]点对构成边if (P[i].y < P[j].y)//边的终点比起点高{pEdge = new CAET;pEdge->x = P[i].x;//计算ET表的值pEdge->yMax = P[j].y;pEdge->k = (P[j].x - P[i].x) / (P[j].y - P[i].y);//代表1/kpEdge->ps = P[i];//绑定顶点和颜色pEdge->pe = P[j];pEdge->ts= T[i];//绑定纹理	pEdge->te = T[j];pEdge->pNext = NULL;while (pCurrentB->ScanLine != P[i].y)//在桶内寻找当前边的yMin{pCurrentB = pCurrentB->pNext;//移到yMin所在的桶结点}}if (P[j].y < P[i].y)//边的终点比起点低{pEdge = new CAET;pEdge->x = P[j].x;pEdge->yMax = P[i].y;pEdge->k = (P[i].x - P[j].x) / (P[i].y - P[j].y);pEdge->ps = P[i];pEdge->pe = P[j];pEdge->ts = T[i];//绑定纹理	pEdge->te = T[j];pEdge->pNext = NULL;while (pCurrentB->ScanLine != P[j].y){pCurrentB = pCurrentB->pNext;}}if (P[i].y != P[j].y){pCurrentE = pCurrentB->pET;if (pCurrentE == NULL){pCurrentE = pEdge;pCurrentB->pET = pCurrentE;}else{while (pCurrentE->pNext != NULL){pCurrentE = pCurrentE->pNext;}pCurrentE->pNext = pEdge;}}}
}void CFill::Gouraud(CDC *pDC, int light_type,CLighting light, CMaterial* material, CP3 EyePoint, CTexture* pTexture,BOOL IfBump)//填充多边形
{CAET *pT1 = NULL, *pT2 = NULL;pHeadE = NULL;for (pCurrentB = pHeadB; pCurrentB != NULL; pCurrentB = pCurrentB->pNext){for (pCurrentE = pCurrentB->pET; pCurrentE != NULL; pCurrentE = pCurrentE->pNext){pEdge = new CAET;pEdge->x = pCurrentE->x;pEdge->yMax = pCurrentE->yMax;pEdge->k = pCurrentE->k;pEdge->ps = pCurrentE->ps;pEdge->pe = pCurrentE->pe;pEdge->pNext = NULL;pEdge->ts = pCurrentE->ts;pEdge->te = pCurrentE->te;pEdge->pNext = NULL;AddEt(pEdge);}EtOrder();pT1 = pHeadE;if (pT1 == NULL){return;}while (pCurrentB->ScanLine >= pT1->yMax)//下闭上开{CAET * pAETTEmp = pT1;pT1 = pT1->pNext;delete pAETTEmp;pHeadE = pT1;if (pHeadE == NULL)return;}if (pT1->pNext != NULL){pT2 = pT1;pT1 = pT2->pNext;}while (pT1 != NULL){if (pCurrentB->ScanLine >= pT1->yMax)//下闭上开{CAET* pAETTemp = pT1;pT2->pNext = pT1->pNext;pT1 = pT2->pNext;delete pAETTemp;}else{pT2 = pT1;pT1 = pT2->pNext;}}CRGB Ca, Cb, Cf;//Ca、Cb代表边上任意点的颜色,Cf代表面上任意点的颜色double za, zb, zf;CVector3 va, vb, vf;CT2 ta, tb, tf;//ta和tb代表边上任意点的纹理地址,tf代表面上任意点的纹理地址ta = Interpolation(pCurrentB->ScanLine, pHeadE->ps.y, pHeadE->pe.y, pHeadE->ts, pHeadE->te);tb = Interpolation(pCurrentB->ScanLine, pHeadE->pNext->ps.y, pHeadE->pNext->pe.y, pHeadE->pNext->ts, pHeadE->pNext->te);Ca = Interpolation(pCurrentB->ScanLine, pHeadE->ps.y, pHeadE->pe.y, pHeadE->ps.c, pHeadE->pe.c);Cb = Interpolation(pCurrentB->ScanLine, pHeadE->pNext->ps.y, pHeadE->pNext->pe.y, pHeadE->pNext->ps.c, pHeadE->pNext->pe.c);za = Interpolation(pCurrentB->ScanLine, pHeadE->ps.y, pHeadE->pe.y, pHeadE->ps.z, pHeadE->pe.z);zb = Interpolation(pCurrentB->ScanLine, pHeadE->pNext->ps.y, pHeadE->pNext->pe.y, pHeadE->pNext->ps.z, pHeadE->pNext->pe.z);va = Interpolation(pCurrentB->ScanLine, pHeadE->ps.y, pHeadE->pe.y, pHeadE->ps.v, pHeadE->pe.v);vb = Interpolation(pCurrentB->ScanLine, pHeadE->pNext->ps.y, pHeadE->pNext->pe.y, pHeadE->pNext->ps.v, pHeadE->pNext->pe.v);BOOL Flag = FALSE;double xb, xe;//扫描线和有效边相交区间的起点和终点坐标for (pT1 = pHeadE; pT1 != NULL; pT1 = pT1->pNext){if (Flag == FALSE){xb = pT1->x;Flag = TRUE;}else{xe = pT1->x;for (double x = xb; x < xe; x++)//左闭右开{if (ROUND(x) + nWidth / 2 < nWidth && ROUND(x) + nWidth / 2 > 0 && pCurrentB->ScanLine + nHeight / 2 < nHeight && pCurrentB->ScanLine + nHeight / 2 > 0) {zf = Interpolation(x, xb, xe, za, zb);if (zf >= zBuffer[ROUND(x) + nWidth / 2][pCurrentB->ScanLine + nHeight / 2])//如果当前采样点的深度小于帧缓冲器中原采样点的深度){tf = Interpolation(x, xb, xe, ta, tb);tf.c = GetTextureColor(ROUND(tf.u), ROUND(tf.v), pTexture);material->SetDiffuse(tf.c);//用纹理颜色作为材质的漫反射光反射率material->SetAmbient(tf.c);//用纹理颜色作为材质的环境光反射率if (light_type == 1) {Cf = Interpolation(x, xb, xe, Ca, Cb);}else if (light_type == 2) {vf = Interpolation(x, xb, xe, va, vb);// 凹凸纹理if (IfBump) {CRGB frontU = GetTextureColor(ROUND(tf.u - 1), ROUND(tf.v), pTexture);CRGB backU = GetTextureColor(ROUND(tf.u + 1), ROUND(tf.v), pTexture);double Bu = (frontU.blue - backU.blue) / 2;CRGB frontV = GetTextureColor(ROUND(tf.u), ROUND(tf.v - 1), pTexture);CRGB backV = GetTextureColor(ROUND(tf.u), ROUND(tf.v + 1), pTexture);double Bv = (frontV.blue - backV.blue) / 2;CVector3 DNormal = CVector3(Bu, Bv, 0);double BumpScale = 100.0;vf = vf + BumpScale * DNormal;vf = vf.Normalize();}Cf = light.Illuminate(EyePoint, CP3(ROUND(x), pCurrentB->ScanLine, zf), vf, material);}zBuffer[ROUND(x) + nWidth / 2][pCurrentB->ScanLine + nHeight / 2] = zf;//使用当前采样点的深度更新深度缓冲器pDC->SetPixelV(ROUND(x), pCurrentB->ScanLine, d * 255, Cf.green * 255, Cf.blue * 255));}}}Flag = FALSE;}}for (pT1 = pHeadE; pT1 != NULL; pT1 = pT1->pNext)//边的连续性{pT1->x = pT1->x + pT1->k;}}
}void CFill::AddEt(CAET *pNewEdge)//合并ET表
{CAET *pCE = pHeadE;if (pCE == NULL){pHeadE = pNewEdge;pCE = pHeadE;}else{while (pCE->pNext != NULL){pCE = pCE->pNext;}pCE->pNext = pNewEdge;}
}
void CFill::EtOrder()//边表的冒泡排序算法
{CAET *pT1 = NULL, *pT2 = NULL;int Count = 1;pT1 = pHeadE;if (NULL == pT1){return;}if (NULL == pT1->pNext)//如果该ET表没有再连ET表{return;//桶结点只有一条边,不需要排序}while (NULL != pT1->pNext)//统计结点的个数{Count++;pT1 = pT1->pNext;}for (int i = 1; i < Count; i++)//冒泡排序{pT1 = pHeadE;if (pT1->x > pT1->pNext->x)//按x由小到大排序{pT2 = pT1->pNext;pT1->pNext = pT1->pNext->pNext;pT2->pNext = pT1;pHeadE = pT2;}else{if (pT1->x == pT1->pNext->x){if (pT1->k > pT1->pNext->k)//按斜率由小到大排序{pT2 = pT1->pNext;pT1->pNext = pT1->pNext->pNext;pT2->pNext = pT1;pHeadE = pT2;}}}pT1 = pHeadE;while (pT1->pNext->pNext != NULL){pT2 = pT1;pT1 = pT1->pNext;if (pT1->x > pT1->pNext->x)//按x由小到大排序{pT2->pNext = pT1->pNext;pT1->pNext = pT1->pNext->pNext;pT2->pNext->pNext = pT1;pT1 = pT2->pNext;}else{if (pT1->x == pT1->pNext->x){if (pT1->k > pT1->pNext->k)//按斜率由小到大排序{pT2->pNext = pT1->pNext;pT1->pNext = pT1->pNext->pNext;pT2->pNext->pNext = pT1;pT1 = pT2->pNext;}}}}}
}CRGB CFill::GetTextureColor(double u, double v, CTexture* pTexture)//获得纹理颜色
{/*检测图片的边界,防止越界*/if (u < 0) u = 0; if (v < 0) v = 0;if (u > pTexture->bmp.bmWidth - 1) 	u = pTexture->bmp.bmWidth - 1;if (v > pTexture->bmp.bmHeight - 1)	v = pTexture->bmp.bmHeight - 1;/*查找对应纹理空间的颜色值*/v = pTexture->bmp.bmHeight - 1 - v;int position = ROUND(v * pTexture->bmp.bmWidthBytes + 4 * u);//颜色分量位置COLORREF color = RGB(pTexture->image[position + 2], pTexture->image[position + 1], pTexture->image[position]);//获取颜色值return  CRGB(GetRValue(color) / 255.0, GetGValue(color) / 255.0, GetBValue(color) / 255.0);
}CRGB CFill::Interpolation(double t, double t1, double t2, CRGB c1, CRGB c2)//颜色线性插值
{CRGB c;c = (t - t2) / (t1 - t2)*c1 + (t - t1) / (t2 - t1)*c2;return c;
}double CFill::Interpolation(double t, double t1, double t2, double z1,double z2)//线性插值
{double z;z = (t - t2) / (t1 - t2) * z1 + (t - t1) / (t2 - t1) * z2;return z;
}CVector3 CFill::Interpolation(double x, double xa, double xb, CVector3 va, CVector3 vb)//法向量线性插值
{CVector3 v;v = (x - xb) / (xa - xb) * va + (x - xa) / (xb - xa) * vb;return v;
}CT2 CFill::Interpolation(double m, double m0, double m1, CT2 T0, CT2 T1)//纹理地址线性插值
{CT2 Texture;Texture = (m1 - m) / (m1 - m0) * T0 + (m - m0) / (m1 - m0) * T1;return Texture;
}void CFill::ClearMemory()//安全删除所有桶和桶上面的边
{DeleteAETChain(pHeadE);CBucket *pBucket = pHeadB;while (pBucket != NULL)// 针对每一个桶{CBucket * pBucketTemp = pBucket->pNext;DeleteAETChain(pBucket->pET);delete pBucket;pBucket = pBucketTemp;}pHeadB = NULL;pHeadE = NULL;
}void CFill::DeleteAETChain(CAET* pAET)
{while (pAET != NULL){CAET* pAETTemp = pAET->pNext;delete pAET;pAET = pAETTemp;}
}void CFill::InitialDepthBuffer(int nWidth, int nHeight, double zDepth)//初始化深度缓冲
{this->nWidth = nWidth, this->nHeight = nHeight;zBuffer = new double* [nWidth];for (int i = 0;i < nWidth;i++)zBuffer[i] = new double[nHeight];for (int i = 0;i < nWidth;i++)//初始化深度缓冲for (int j = 0;j < nHeight;j++)zBuffer[i][j] = zDepth;
}

本文发布于:2024-02-03 03:46:48,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170690320948442.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:三维图像   MFC
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23