⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 prender.cpp

📁 这是我做的一个VC++小程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/////////////////////////////////////////////////////////////////////////////////
//	
// PRender.cpp: implementation of the CPRender class.
//
////////////////////////////////////////////////////////////////////////////////
// 版权所有(2002)
// Copyright(2002)
// 编写者: 向世明
// Author: Xiang Shiming


#include "stdafx.h"
#include "PRender.h"

#include "ViewFinder.h"
#include "SVisibility.h"
#include "PLine.h"
#include "PTriangle.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPRender::CPRender()
{}

CPRender::~CPRender()
{}


//通用着色工具:  在此完成主要工作
//pDC---------设备描述表;
//pObj---------三维物体对象   (单个物体)
//viewer------视点(定义于世界坐标系)
//viewFinder--取景器
//dwRop-------着色模式
void CPRender::Render(CDC* pDC, CObject3d* pObj,  VERTEX3D viewer,  VIEWFINDER viewFinder,  DWORD dwRop)
{
	//第一步, 获取几何元素的个数
	
	//物体顶点的个数
	int nNumVertex = pObj->GetVertexListSize();
	

	//存储将世界坐标变换为观察坐标后的结果
	HOMOCOORD* pvInView = new HOMOCOORD[nNumVertex];

	if(pvInView == NULL)
	{
		::AfxMessageBox("内存分配失败!");
		exit(1);
	}
	
	//////////////////////////////////////////
	//第二步:完成从世界坐标到观察坐标的变换

	//观察矩阵(初始化为单位矩阵)
	CMatrix3d mWatch;

	//获取观察矩阵
	mWatch.Watch(viewer.x,  viewer.y,  viewer.z);

	int i;
	//将世界坐标系的点变换为观察坐标系的点
	for(i = 0; i < nNumVertex; i++)
	{
		//获取一个顶点的齐次坐标
		//将顶点变换至到获取观察坐标
		pvInView[i] = mWatch.Transform(pObj->m_vList[i].m_coord);
	}//end for i (1st)

	//
	//////////////////////////////////////////
	//第三步:完成从观察坐标到屏幕坐标的变换

	//中间省略了如下几个步骤:
	//其一, 透视剪切;其二, 设备坐标规格化
	
	//保存变换之结果
	POINT* pPtOnScrn = new POINT[nNumVertex];

	if(pPtOnScrn == NULL)
	{
		::AfxMessageBox("内存分配失败!");
		exit(1);
	}

	//设置视口变换工具.
	CViewFinder  vf(viewFinder);
	//执行缩减的透视变换和视口变换
	for(i = 0; i < nNumVertex; i++)
		pPtOnScrn[i] = vf.Perspective(pvInView[i]);
		
	//第四步, 绘制点模型
	if(dwRop == G3D_RENDER_VERTICES)
	{
		//所有点均绘制
		Vertexize(pDC,  pObj,  pPtOnScrn);

		delete[] pPtOnScrn;
		delete[] pvInView;
		return;
	}
	
	//第五步, 测试面的可见性
	//物体面的可见性将在这里获得改变
	
	//面的可见性测试, 该测试器仅能作用于凸体模型
	CSVisibility sv;
	
	//小面个数
	int nNumFacet = pObj->GetFacetListSize();
	
	//面的可见性, 
	for(i = 0; i < nNumFacet; i++)
	{
		ASSERT(pObj->m_sList[i].m_avIndex.GetSize() > 2);

		//这些点在世界坐标系中按右手规则排列
		
		//获取组成小面的基点序号, 取前三个点作测试
		int n1 = pObj->m_sList[i].m_avIndex[0];
		int n2 = pObj->m_sList[i].m_avIndex[1];
		int n3 = pObj->m_sList[i].m_avIndex[2];

		//计算小面的可见性, 并进行记录
		
		BOOL bVisible = sv.IsVisible(pvInView[n1],  pvInView[n2],  pvInView[n3]);
		
		pObj->m_sList[i].m_bVisibility = bVisible;

	}//end for i (3th)
	
	//第六步, 绘制实体型
	if(dwRop == G3D_RENDER_FLAT)
	{
		Flat(pDC,  pObj,  pPtOnScrn);
		delete[] pPtOnScrn;
		delete[] pvInView;
		return;
	}
	else if(dwRop == G3D_RENDER_GOURAUD_SMOOTH)
	{
		Gouraud(pDC,  pObj,  pPtOnScrn);
		delete[] pPtOnScrn;
		delete[] pvInView;
		return;
	}



	//第七步, 边的可见性(边的可见性得到改变)
	//判断隐藏线算法如下:
	//如果与该边相边的面中有一个是可见的, 则该边可见.

	//边数
	int nNumEdge = pObj->GetEdgeListSize();
	
	//计算边的可见性
	for(i = 0; i < nNumEdge; i++)
	{
		//注意, 我们只处理正则模型, 因为该类只能着色凸体模型
		//获取共享该边的小面个数
		int nNumInFacet = pObj->m_eList[i].m_asIndex.GetSize();
		
		//孤边
		if(nNumInFacet == 0)pObj->m_eList[i].m_bVisibility = TRUE;
		//边界边
		else if(nNumInFacet == 1)
		{
			int n1 = pObj->m_eList[i].m_asIndex[0];
			//对于边界边, 如果其所在的小面是可见的, 则该边也是可见的
			//如果不可见, 该边也不可见.
			pObj->m_eList[i].m_bVisibility = pObj->m_sList[n1].m_bVisibility;
		}
		else if(nNumInFacet == 2)
		{
			//获取边所在小面的序号
			int n1 = pObj->m_eList[i].m_asIndex[0];
			int n2 = pObj->m_eList[i].m_asIndex[1];
			
			//如果两个小面中有一个是可见的, 则该边是可见的
			pObj->m_eList[i].m_bVisibility = (pObj->m_sList[n1].m_bVisibility ||
											pObj->m_sList[n2].m_bVisibility);
		}
		
		//else
		//{
			//请按你自己的模型进行处理
		//}

	}// end for i 4th


	//第八步, 绘制线框模型
	if(dwRop == G3D_RENDER_WIRE)
	{
		FlatWirize(pDC,  pObj,  pPtOnScrn);

		delete[] pPtOnScrn;
		delete[] pvInView;
		return;
	}
	else if(dwRop == G3D_RENDER_WIRE_LIGHTED)
	{
		GouraudWirize(pDC,  pObj,  pPtOnScrn);
		delete[] pPtOnScrn;
		delete[] pvInView;
		return;
	}

	delete[] pPtOnScrn;
	delete[] pvInView;
}


//绘制点模型
//pDC---------设备描述表;
//pObj---------三维物体对象
//pPtOnScrn---最终透视到屏幕上的点
void CPRender::Vertexize(CDC* pDC,  CObject3d* pObj,  POINT* pPtOnScrn)
{
	//顶点个数
	int nNumPt = pObj->GetVertexListSize();
	
	//绘制点模型
	for(int i = 0; i < nNumPt; i++)
	{
		//颜色(R, G, B)
		BYTE byR = (BYTE)(pObj->m_vList[i].m_clr.red * 255.0f);
		BYTE byG = (BYTE)(pObj->m_vList[i].m_clr.green * 255.0f);
		BYTE byB = (BYTE)(pObj->m_vList[i].m_clr.blue * 255.0f);

		//绘制单个点
		pDC->SetPixelV(pPtOnScrn[i], RGB(byR, byG, byB));
	}

}

//绘制单色线框模型(这里指, 一条边的颜色是相同的)
//pDC---------设备描述表;
//pObj---------三维物体对象
//pPtOnScrn---最终透视到屏幕上的点
void CPRender::FlatWirize(CDC* pDC,  CObject3d* pObj,  POINT* pPtOnScrn)
{
	//物体边数
	int nNumEdge = pObj->GetEdgeListSize();
	
	//由顶点决定边的颜色, 还是由外部决定边的颜色
	BOOL bAutoColor = pObj->GetAutoColorProperty();

	//绘制模型
	for(int i = 0; i < nNumEdge; i++)
	{
		//绘制边----单色线框模型
		if(pObj->m_eList[i].m_bVisibility)
		{
			//获取边的顶点索引
			int n1 = pObj->m_eList[i].m_nStart;
			int n2 = pObj->m_eList[i].m_nEnd;
			
			//边的颜色
			BYTE byR,  byG,  byB;
			//获取顶点颜色
			if(bAutoColor)
			{
				//用第一个顶点的颜色来代替整条边的颜色
				FLOATCOLORRGBA rgba = pObj->m_vList[n1].m_clr;

				//顶点颜色归一化应该在外部进行
				byR = (BYTE)(rgba.red * 255.0f); 
				byG = (BYTE)(rgba.green * 255.0f);
				byB = (BYTE)(rgba.blue * 255.0f);
			}
			
			//获取边的颜色

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -