在VS2013 MFC下的光照球算法实验

计算机工程系

实 验 报 告

 

 

 


课程名称

计算机图形学

班级

1320541

实验日期

2015年6月11日星期四

姓    名

学号

37

实验成绩

 

实验名称

          实验五 光照球

1)      理解球边表和面表算法

2)      理解双缓冲的算法

3)      理解mfc作用原理

4)      理解光照球算法

VS2013基于MFC

               利用mfc绘制光照球球

 

 

 

 

 

 

 

 

部分重要代码截图:

 

(用适当的形式表达算法设计思想与算法实现步骤)

 

 

 

 

 

 

 

 

实验过程中没有出现太大的问题

实验结果展示如下:

                      双光源光照地理球

 

(详细记录在调试过程中出现的问题及解决方法。记录实验运行结果)

 

 

 

 

 

1)  通过本次实验,了解到了mfc的最基本知识,发现自己学习mfc任重而道远,在前行的路上还有很多学习的地方。

2)  实践是检验真理的唯一标准

3)  动手能力需要再次提高

4)  算法思想要与时俱进,要多学习算法

(对实验结果进行分析,实验心得体会及改进意见)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      录

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

        录

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

        录

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

       录

CDrawBallView::CDrawBallView()

: N(NULL)

, F(NULL), N1(0)

, N2(0)

, Alpha(0)

, Beta(0)

, V(NULL)

{

    // TODO:  在此处添加构造代码

    V = NULL; F = NULL;

    R = 1000.0, d = 800.0, Phi = 90.0, Theta = 0.0;//视点位于正前方

    Near = 200.0, Far = 1200.0;//近剪切面与远剪切面

    LightNum = 2;//光源个数

    pLight = new CLighting(LightNum);//一维光源动态数组

    pLight->Light[0].SetPosition(-800, 800, 800);//设置光源位置坐标

    pLight->Light[1].SetPosition(800, 800, 800);//设置光源位置坐标 

    for (int i = 0; i<LightNum; i++)

    {

        pLight->Light[i].L_Diffuse = CRGB(1.0, 1.0, 1.0);//光源的漫反射颜色

        pLight->Light[i].L_Specular = CRGB(1.0, 1.0, 1.0);//光源镜面高光颜色

        pLight->Light[i].L_C0 = 1.0;//常数衰减系数

        pLight->Light[i].L_C1 = 0.0000001;//线性衰减系数

        pLight->Light[i].L_C2 = 0.00000001;//二次衰减系数

        pLight->Light[i].L_OnOff = TRUE;//光源开启

    }

    pMaterial = new CMaterial;//一维材质动态数组

    pMaterial->SetAmbient(CRGB(0.175, 0.012, 0.012));//材质对环境光光的反射率

    pMaterial->SetDiffuse(CRGB(0.614, 0.041, 0.041));//材质对漫反射光的反射率

    pMaterial->SetSpecular(CRGB(1.0, 1.0, 1.0));//材质对镜面反射光的反射率

    pMaterial->SetEmit(CRGB(0.2, 0.2, 0.4));//材质自身发散的颜色

    pMaterial->SetExp(30);//高光指数   

}

 

// CDrawBallView 绘制

 

void CDrawBallView::OnDraw(CDC* pDC)

{

    CDrawBallDoc* pDoc = GetDocument();

    ASSERT_VALID(pDoc);

    if (!pDoc)

        return;

    // TODO:  在此处为本机数据添加绘制代

    pDC = GetDC();

    CRect rect;

    GetClientRect(&rect);

    //pDC->Rectangle(0, 0, rect.Width(), rect.Height());

    //pDC->FillSolidRect(&rect, RGB(0, 0, 0));

    pDC->SetTextColor(RGB(255, 0, 0));

    pDC->TextOutW(200, 200, _T("光源位置为:X:-800,Y:800,Z:800"));

    pDC->TextOutW(920, 200, _T("光源位置为:X:800,Y:800,Z:800"));

    DoubleBuffer();

    pDC->TextOutW(200, 200, _T("光源位置为:X:-800,Y:800,Z:800"));

    pDC->TextOutW(920, 200, _T("光源位置为:X:800,Y:800,Z:800"));

}

 

 

// CDrawBallView 打印

 

BOOL CDrawBallView::OnPreparePrinting(CPrintInfo* pInfo)

{

    // 默认准备

    return DoPreparePrinting(pInfo);

}

 

void CDrawBallView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

    // TODO:  添加额外的打印前进行的初始化过程

}

 

void CDrawBallView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

    // TODO:  添加打印后进行的清理过程

}

 

// CDrawBallView 诊断

 

#ifdef _DEBUG

void CDrawBallView::AssertValid() const

{

    CView::AssertValid();

}

 

void CDrawBallView::Dump(CDumpContext& dc) const

{

    CView::Dump(dc);

}

 

CDrawBallDoc* CDrawBallView::GetDocument() const // 非调试版本是内联的

{

    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(Cliuchuang46_DrawBallDoc)));

    return (Cliuchuang46_DrawBallDoc*)m_pDocument;

}

#endif //_DEBUG

 

 

// CDrawBallView 消息处理程序

void CDrawBallView::InitParameter()

{

    k[1] = sin(PI*Theta / 180);

    k[2] = sin(PI*Phi / 180);

    k[3] = cos(PI*Theta / 180);

    k[4] = cos(PI*Phi / 180);

    k[5] = k[2] * k[3];

    k[6] = k[2] * k[1];

    k[7] = k[4] * k[3];

    k[8] = k[4] * k[1];

    ViewPoint.x = R*k[6];

    ViewPoint.y = R*k[4];

    ViewPoint.z = R*k[5];

}

 

 

void CDrawBallView::PerProject(CP3 P)

{

    CP3 ViewP;

    ViewP.x = P.x*k[3] - P.z*k[1];//观察坐标系三维坐标

    ViewP.y = -P.x*k[8] + P.y*k[2] - P.z*k[7];

    ViewP.z = -P.x*k[6] - P.y*k[4] - P.z*k[5] + R;

    ViewP.c = P.c;

    ScreenP.x = d*ViewP.x / ViewP.z;//屏幕坐标系三维坐标

    ScreenP.y = Round(d*ViewP.y / ViewP.z);

    ScreenP.z = Far*(1 - Near / ViewP.z) / (Far - Near);

    ScreenP.c = ViewP.c;

}

 

void CDrawBallView::ReadVertex()//读入顶点

{

    int gAlpha = 5, gBeta = 5;//面片夹角

    N1 = 180 / gAlpha;

    N2 = 360 / gBeta;//N1为纬度区域,N2为经度区域

    V = new CP3[(N1 - 1)*N2 + 2];//V为球的顶点

    //纬度方向除南北极点外有"N1-1"个点,"2"代表南北极两个点

    double gAlpha1, gBeta1, r = 300;//r为球体半径

    //计算北极点坐标

    V[0].x = 0, V[0].y = r, V[0].z = 0;

    //按行循环计算球体上的点坐标

    for (int i = 0; i<N1 - 1; i++)

    {

        gAlpha1 = (i + 1)*gAlpha*PI / 180;

        for (int j = 0; j<N2; j++)

        {

            gBeta1 = j*gBeta*PI / 180;

            V[i*N2 + j + 1].x = r*sin(gAlpha1)*sin(gBeta1);

            V[i*N2 + j + 1].y = r*cos(gAlpha1);

            V[i*N2 + j + 1].z = r*sin(gAlpha1)*cos(gBeta1);

        }

    }

    //计算南极点坐标

    V[(N1 - 1)*N2 + 1].x = 0, V[(N1 - 1)*N2 + 1].y = -r, V[(N1 - 1)*N2 + 1].z = 0;

}

 

void CDrawBallView::ReadFace()//读入面表

{

    //设置二维动态数组

    F = new CFace *[N1];//设置行

    for (int n = 0; n<N1; n++)

        F[n] = new CFace[N2];//设置列

    for (int j = 0; j<N2; j++)//构造北极三角形面片

    {

        int tempj = j + 1;

        if (tempj == N2) tempj = 0;//面片的首尾连接

        int NorthIndex[3];//北极三角形面片索引号数组

        NorthIndex[0] = 0;

        NorthIndex[1] = j + 1;

        NorthIndex[2] = tempj + 1;

        F[0][j].SetNum(3);

        for (int k = 0; k<F[0][j].vN; k++)

            F[0][j].vI[k] = NorthIndex[k];

    }

    for (int i = 1; i<N1 - 1; i++)//构造球面四边形面片

    {

        for (int j = 0; j<N2; j++)

        {

            int tempi = i + 1;

            int tempj = j + 1;

            if (tempj == N2) tempj = 0;

            int BodyIndex[4];//球面四边形面片索引号数组

            BodyIndex[0] = (i - 1)*N2 + j + 1;

            BodyIndex[1] = (tempi - 1)*N2 + j + 1;

            BodyIndex[2] = (tempi - 1)*N2 + tempj + 1;

            BodyIndex[3] = (i - 1)*N2 + tempj + 1;

            F[i][j].SetNum(4);

            for (int k = 0; k<F[i][j].vN; k++)

                F[i][j].vI[k] = BodyIndex[k];

        }

    }

    for (int j = 0; j<N2; j++)//构造南极三角形面片

    {

        int tempj = j + 1;

        if (tempj == N2) tempj = 0;

        int SouthIndex[3];//南极三角形面片索引号数组

        SouthIndex[0] = (N1 - 2)*N2 + j + 1;

        SouthIndex[1] = (N1 - 1)*N2 + 1;

        SouthIndex[2] = (N1 - 2)*N2 + tempj + 1;

        F[N1 - 1][j].SetNum(3);

        for (int k = 0; k<F[N1 - 1][j].vN; k++)

            F[N1 - 1][j].vI[k] = SouthIndex[k];

    }

}

 

 

void CDrawBallView::DoubleBuffer()

{

    CDC* pDC = GetDC();

    CRect rect;//定义客户区

    GetClientRect(&rect);//获得客户区的大小

    pDC->SetMapMode(MM_ANISOTROPIC);//pDC自定义坐标系

    pDC->SetWindowExt(rect.Width(), rect.Height());//设置窗口范围

    pDC->SetViewportExt(rect.Width(), -rect.Height());//x轴水平向右,y轴垂直向上

    pDC->SetViewportOrg(rect.Width() / 2, rect.Height() / 2);//屏幕中心为原点

    CDC MemDC;//内存DC

    CBitmap NewBitmap, *pOldBitmap;//内存中承载图像的临时位图

    MemDC.CreateCompatibleDC(pDC);//建立与屏幕pDC兼容的MemDC

    NewBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());//创建兼容位图

    pOldBitmap = MemDC.SelectObject(&NewBitmap); //将兼容位图选入MemDC

    //MemDC.FillSolidRect(&rect, pDC->GetBkColor());//按原来背景填充客户区,否则是黑色

    MemDC.SetMapMode(MM_ANISOTROPIC);//MemDC自定义坐标系

    MemDC.SetWindowExt(rect.Width(), rect.Height());

    MemDC.SetViewportExt(rect.Width(), -rect.Height());

    MemDC.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);

    DrawObject(&MemDC);

    pDC->BitBlt(-rect.Width() / 2, -rect.Height() / 2, rect.Width(), rect.Height(), &MemDC, -rect.Width() / 2, -rect.Height() / 2, SRCCOPY);//将内存位图拷贝到屏幕

    MemDC.SelectObject(pOldBitmap);//恢复位图

    NewBitmap.DeleteObject();//删除位图

 

    ReleaseDC(pDC);//释放DC

}

 

void CDrawBallView::CalVertexColor()//计算顶点颜色

{

    for (int nVertex = 0; nVertex<(N1 - 1)*N2 + 2; nVertex++)//遍历所有点

    {

        CVector VNormal(V[nVertex]);//点的位置矢量代表共享该点的所有面的平均法矢量

        V[nVertex].c = pLight->Lighting(ViewPoint, V[nVertex], VNormal, pMaterial);//调用光照函数

    }

}

 

void CDrawBallView::DrawObject(CDC* pDC)

{

    CalVertexColor();

    CZBuffer *zbuf = new CZBuffer;//申请内存

    zbuf->InitDeepBuffer(800, 800, 1000);//初始化深度缓冲器

    CPi3 Point3[3];//南北极顶点数组

    CPi3 Point4[4];//球体顶点数组  

    for (int i = 0; i<N1; i++)

    {

        for (int j = 0; j<N2; j++)

        {

            CVector ViewVector(V[F[i][j].vI[0]], ViewPoint);//面的视矢量

            ViewVector = ViewVector.Normalize();//单位化视矢量

            F[i][j].SetFaceNormal(V[F[i][j].vI[0]], V[F[i][j].vI[1]], V[F[i][j].vI[2]]);

            F[i][j].fNormal.Normalize();//单位化法矢量

            if (Dot(ViewVector, F[i][j].fNormal) >= 0)//背面剔除

            {

                if (3 == F[i][j].vN)//三角形面片

                {

                    for (int m = 0; m<F[i][j].vN; m++)

                    {

                        PerProject(V[F[i][j].vI[m]]);

                        Point3[m] = ScreenP;

                    }

                    zbuf->SetPoint(Point3, 3);//设置顶点           

                    zbuf->CreateBucket();//建立桶表

                    zbuf->CreateEdge();//建立边表

                    zbuf->Gouraud(pDC);//填充三角形

                    zbuf->ClearMemory();//内存清理                 

                }

                else//四边形面片

                {

                    for (int m = 0; m<F[i][j].vN; m++)

                    {

                        PerProject(V[F[i][j].vI[m]]);

                        Point4[m] = ScreenP;

                    }

                    zbuf->SetPoint(Point4, 4);//设置顶点           

                    zbuf->CreateBucket();//建立桶表

                    zbuf->CreateEdge();//建立边表

                    zbuf->Gouraud(pDC);//填充四边形

                    zbuf->ClearMemory();//内存清理

                }

            }

        }

    }

    delete zbuf;//释放内存

 

}

 

 

void C_DrawBallView::OnInitialUpdate()

{

   

    ReadVertex();

    ReadFace();

    tran.SetMat(V, (N1 - 1)*N2 + 2);

    InitParameter();

}

 

void CDrawBallView::OnDrawView()

{

    // TODO:  在此添加命令处理程序代码

    SetTimer(1, 100, NULL);

}

 

 

void Cliuchuang46_DrawBallView::OnTimer(UINT_PTR nIDEvent)

{

    // TODO:  在此添加消息处理程序代码和/或调用默认值

 

    CView::OnTimer(nIDEvent);

    Alpha = 5; Beta = 5;

    tran.RotateX(Alpha);

    tran.RotateY(Beta);

    Invalidate(FALSE);

}

 

 

void CDrawBallView::OnExit()

{

    // TODO:  在此添加命令处理程序代码

    exit(1);

 

}

 

void CDrawBallView::OnPause()

{

    // TODO:  在此添加命令处理程序代码

    KillTimer(1);

}

 

 

int CDrawBallView::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

    if (CView::OnCreate(lpCreateStruct) == -1)

        return -1;

 

    // TODO:  在此添加您专用的创建代码

    return 0;

}

 

 

BOOL CDrawBallView::OnEraseBkgnd(CDC* pDC)

{

    // TODO:  在此添加消息处理程序代码和/或调用默认值

    /*CBrush   brush(RGB(0, 0, 0));

    CBrush*   pOldOne = pDC->SelectObject(&brush);

    CRect   rc;

    pDC->GetClipBox(&rc);

    pDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATCOPY);

    pDC->SelectObject(pOldOne);*/

    return TRUE;

 

}

 

BOOL CDrawBallView::PreCreateWindow(CREATESTRUCT& cs)

{

 

    return CView::PreCreateWindow(cs);

 

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值