制作立方体光照纹理模型

一、实验项目要求

1. 建立立方体类。
2. 背面剔除算法消隐。
3.PhongShader光照。
4.使用六张纹理图片。

二、理论分析或算法分析

1.建立立方体类:

在实验中,建立一个Cube类,在Cube类中定义立方体的八个顶点,六个面,为了可以方便后面绘制面,所以定义了一个Facet类,用来定义表面顶点和面的顶点索引号,为了绘制出这个立方体,在立方体类中,需要定义这八个顶点的坐标(void CCube::ReadPoint(void)),然后读入面表(void CCube::ReadFacet(void)//面表),在这个类中定义Draw函数(void CCube::Draw(CDC* pDC))用来绘制出立方体,在这个里面,利用循环来绘制出一个面(for (int nPoint = 0; nPoint < F[nFacet].Number; nPoint++)//顶点循环),然后在循环来绘制出六个面(for(int nFacet = 0; nFacet < 6; nFacet++)//面循环);

2.背面剔除算法消隐:

这个算法是针对凸多边形而设计的,其表面要么完全可见,要么不可见。背面剔除算法的的关键是给出测试其每个表面可见性的判别式,可以根据其外法向量N与视向量V(从表面上的一个顶点指向视点)的夹角@来进行可见性检测。在这个算法中,主要用到的就是三维向量类Vectors3,主要成员函数为点乘(数量积)函数和叉乘(向量积)函数。使用背面剔除算法对立方体进行消隐,主要是对条件的判定(if (DotProduct(ViewVector, FacetNormal)>=0)//背面剔除),满足此条件,就可以看见,从而达到了消隐的目的;

3.PhongShader光照:

这是一个着色算法,将一个四边形网格分为上三角形和下三角形,使用双线性插值来进行对像素点的着色,首先确定三角形类型,判断是属于“左三角形”还是属于“右三角形”,然后将每条边离散为标志点数组,最后对每个跨度两侧的标志点范围内的像素着色,对于左三角形来说:边的左边是TRUE,边为FALSE;但是对于右三角形来说:边是TRUE,右边是FALSE;(void CTriangle::PhongShader(CDC * pDC, CP3 ViewPoint, CLighting * pLight, CMaterial * pMaterial, CTexture * pTexture) ),PhongShader是对像素点进行着色,但是对于GroundShader来说:就是对向量进行着色,将一个顶点作为面的颜色填充;

4.使用六张纹理图片:

首先,得读入位图,所以建立了一个Texture类,在这个类中,根据ID号来读入资源中的位图,并将位图保存到一维数组中,(void PrepareBitmap(UINT nIDResource);//准备位图),准备位图,将位图信息保存到数组中(NewBitmap.GetBitmapBits(nbytesize, (LPVOID)image)),然就将纹理绑定在立方体的顶点上,(CT2 ScreenTexture[4];//二维纹理坐标),然后进行纹理颜色替换属性(CT2 Texture = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].t, SpanRight[n].t);),在PhongShader函数中,读取纹理位图的颜色数据(Texture.c = GetTexture(ROUND(Texture.u), ROUND(Texture.v), pTexture);),并将其设置为材质的漫反射率和环境反射率(pMaterial->SetDiffuse(Texture.c);pMaterial->SetAmbient(Texture.c);)。

三、实现方法

1.建立立方体类:

CCube.h:

#pragma once
#include"Projection.h"
#include"Facet.h"
#include"Triangle.h"
#include"Vector3.h"

class CCube
{
public:
	CCube(void);
	virtual ~CCube(void);
	CP3* GetVertexArrayName(void);//获得数组名
	void ReadPoint(void);//读入点表
	void ReadFacet(void);//读入面表	
	void SetScene(CLighting* pLight, CMaterial* pMaterial);//设置场景
	void SetTexture(CTexture* pTexture);//设置纹理
	void Draw(CDC* pDC);//绘制图形
private:
	CP3 P[8];//点表
	CFacet F[6];//面表
	CProjection projection;//投影
	CLighting* pLight;//光照
	CMaterial* pMaterial;//材质
	CTexture pTexture[6];
};

CCube.cpp:

#include "pch.h"
#include "Cube.h"
#include <math.h>//包含数学头文件

CCube::CCube(void)
{
}

CCube::~CCube(void)
{

}

CP3* CCube::GetVertexArrayName(void)//获得数组名
{
	return P;
}

void CCube::SetScene(CLighting* pLight, CMaterial* pMaterial)//设置场景
{
	this->pLight = pLight;
	this->pMaterial = pMaterial;
}

void CCube::SetTexture(CTexture* pTexture)
{
	this->pTexture[0] = pTexture[0];
	this->pTexture[1] = pTexture[1];
	this->pTexture[2] = pTexture[2];
	this->pTexture[3] = pTexture[3];
	this->pTexture[4] = pTexture[4];
	this->pTexture[5] = pTexture[5];
}

void CCube::ReadPoint(void)//点表
{
	P[0].x = 0, P[0].y = 0, P[0].z = 0;
	P[1].x = 1, P[1].y = 0, P[1].z = 0;
	P[2].x = 1, P[2].y = 1, P[2].z = 0;
	P[3].x = 0, P[3].y = 1, P[3].z = 0;
	P[4].x = 0, P[4].y = 0, P[4].z = 1;
	P[5].x = 1, P[5].y = 0, P[5].z = 1;
	P[6].x = 1, P[6].y = 1, P[6].z = 1;
	P[7].x = 0, P[7].y = 1, P[7].z = 1;
}



void CCube::ReadFacet(void)//面表
{
	F[0].Number = 4;F[0].Index[0] = 4;F[0].Index[1] = 5;F[0].Index[2] = 6;F[0].Index[3] = 7;//前面
	F[1].Number = 4;F[1].Index[0] = 0;F[1].Index[1] = 3;F[1].Index[2] = 2;F[1].Index[3] = 1;//后面
	F[2].Number = 4;F[2].Index[0] = 0;F[2].Index[1] = 4;F[2].Index[2] = 7;F[2].Index[3] = 3;//左面
	F[3].Number = 4;F[3].Index[0] = 1;F[3].Index[1] = 2;F[3].Index[2] = 6;F[3].Index[3] = 5;//右面
	F[4].Number = 4;F[4].Index[0] = 2;F[4].Index[1] = 3;F[4].Index[2] = 7;F[4].Index[3] = 6;//顶面
	F[5].Number = 4;F[5].Index[0] = 0;F[5].Index[1] = 1;F[5].Index[2] = 5;F[5].Index[3] = 4;//底面
}


void CCube::Draw(CDC* pDC)
{
	CP3 ScreenPoint[4];//三维屏幕点
	CT2 ScreenTexture[4];//二维纹理坐标
	CTriangle* pFill = new CTriangle;   //申请内存
	for(int nFacet = 0; nFacet < 6; nFacet++)//面循环
	{
		CP3 ViewPoint = projection.GetEye();//视点
		CVector3 ViewVector(P[F[nFacet].Index[0]], ViewPoint);// 面的视向量
		ViewVector = ViewVector.Normalize();//视向量单位化
		CVector3 Vector01(P[F[nFacet].Index[0]], P[F[nFacet].Index[1]]), Vector02(P[F[nFacet].Index[0]], P[F[nFacet].Index[2]]);//边向量
		CVector3 FacetNormal = CrossProduct(Vector01, Vector02);//面法向量
		FacetNormal = FacetNormal.Normalize();
		if (DotProduct(ViewVector, FacetNormal)>=0)//背面剔除
		{

			for (int nPoint = 0; nPoint < F[nFacet].Number; nPoint++)//顶点循环
				ScreenPoint[nPoint] = projection.OrthogonalProjection3(P[F[nFacet].Index[nPoint]]);
			pFill->SetPoint(ScreenPoint[0], ScreenPoint[2], ScreenPoint[3], FacetNormal, FacetNormal, FacetNormal, CT2(0, 0), CT2((pTexture[nFacet].bmp.bmWidth - 1), pTexture[nFacet].bmp.bmHeight - 1), CT2(0, pTexture[nFacet].bmp.bmHeight - 1));
			pFill->PhongShader(pDC, ViewPoint, pLight, pMaterial, &pTexture[nFacet]);
			pFill->SetPoint(ScreenPoint[0], ScreenPoint[1], ScreenPoint[2], FacetNormal, FacetNormal, FacetNormal, CT2(0, 0), CT2(pTexture[nFacet].bmp.bmWidth - 1, 0), CT2(pTexture[nFacet].bmp.bmWidth - 1, pTexture[nFacet].bmp.bmHeight - 1));
			pFill->PhongShader(pDC, ViewPoint, pLight, pMaterial, &pTexture[nFacet]);
		}
	}
}

2.背面剔除消隐算法:

Vector3.h:

#pragma once
#include "P3.h"

class CVector3
{
public:
	CVector3(void);
	virtual ~CVector3(void);
	CVector3(double x, double y, double z);//绝对向量
	CVector3(const CP3 &p);
	CVector3(const CP3 &p0, const CP3 &p1);//相对向量
	double Magnitude(void);//计算向量的模
	CVector3 Normalize(void);//规范化向量
	friend CVector3 operator + (const CVector3 &v0, const CVector3 &v1);//运算符重载
	friend CVector3 operator - (const CVector3 &v0, const CVector3 &v1);
	friend CVector3 operator * (const CVector3 &v, double scalar);
	friend CVector3 operator * (double scalar, const CVector3 &v);
	friend CVector3 operator / (const CVector3 &v, double scalar);
	friend double DotProduct(const CVector3 &v0, const CVector3 &v1);//计算向量的点积
	friend CVector3 CrossProduct(const CVector3 &v0, const CVector3 &v1);//计算向量的叉积
public:
	double x,y,z;
};
#include "pch.h"
#include "Vector3.h"
#include<math.h>


CVector3::CVector3(void)
{
	x = 0.0,y = 0.0, z = 1.0;//指向z轴正向
}


CVector3::~CVector3(void)
{
}

CVector3::CVector3(double x, double y, double z)//绝对向量
{
	this->x = x;
	this->y = y;
	this->z = z;	
}

CVector3::CVector3(const CP3 &p)
{
	x = p.x;
	y = p.y;
	z = p.z;
}

CVector3::CVector3(const CP3 &p0, const CP3 &p1)//相对向量
{
	x = p1.x - p0.x;
	y = p1.y - p0.y;
	z = p1.z - p0.z;
}

double CVector3::Magnitude(void)//向量的模
{
	return sqrt(x * x + y * y + z * z);
}

CVector3 CVector3::Normalize(void)//规范化为单位向量
{
	CVector3 vector;
	double magnitude = sqrt(x * x + y * y + z * z);
	if(fabs(magnitude) < 1e-4)
		magnitude  = 1.0;
	vector.x = x / magnitude;
	vector.y = y / magnitude;
	vector.z = z / magnitude;
	return vector;
}

CVector3 operator + (const CVector3 &v0, const CVector3 &v1)//向量的和
{
	CVector3 vector;
	vector.x = v0.x + v1.x;
	vector.y = v0.y + v1.y;
	vector.z = v0.z + v1.z;
	return vector;
}

CVector3 operator - (const CVector3 &v0, const CVector3 &v1)//向量的差
{
	CVector3 vector;
	vector.x = v0.x - v1.x;
	vector.y = v0.y - v1.y;
	vector.z = v0.z - v1.z;
	return vector;
}

CVector3 operator * (const CVector3 &v, double scalar)//向量与常量的积
{
	CVector3 vector;
	vector.x = v.x * scalar;
	vector.y = v.y * scalar;
	vector.z = v.z * scalar;
	return vector;
}

CVector3 operator * (double scalar, const CVector3 &v)//常量与向量的积
{
	CVector3 vector;
	vector.x = v.x * scalar;
	vector.y = v.y * scalar;
	vector.z = v.z * scalar;
	return vector;
}

CVector3 operator / (const CVector3 &v, double scalar)//向量数除
{
	if(fabs(scalar) < 1e-4)
		scalar = 1.0;
	CVector3 vector;
	vector.x = v.x / scalar;
	vector.y = v.y / scalar;
	vector.z = v.z / scalar;
	return vector;
}

double DotProduct(const CVector3 &v0, const CVector3 &v1)//向量的点积
{
	return(v0.x * v1.x + v0.y * v1.y + v0.z * v1.z);
}

CVector3 CrossProduct(const CVector3 &v0, const CVector3 &v1)//向量的叉积
{
	CVector3 vector;
	vector.x = v0.y * v1.z - v0.z * v1.y;
	vector.y = v0.z * v1.x - v0.x * v1.z;
	vector.z = v0.x * v1.y - v0.y * v1.x;
	return vector;
}

判定条件:
if (DotProduct(ViewVector, FacetNormal)>=0)//背面剔除

3.PhongShader光照:

CTriangle.h:

#pragma once
#include "P3.h"//带颜色的浮点数二维点类
#include "Point3.h"//带颜色的整数三维点类
#include"Lighting.h"
#include"Material.h"
#include"Texture.h"


class CTriangle//三角形填充类
{
public:
	CTriangle(void);
	virtual ~CTriangle(void);
	void SetPoint(CP3 P0, CP3 P1, CP3 P2, CVector3 N0, CVector3 N1, CVector3 N2, CT2 T0, CT2 T1, CT2 T2);
	/*void GouraudShader(CDC* pDC, CP3 ViewPoint, CLighting* pLight, CMaterial* pMaterial, CTexture* pTexture);*/
	void PhongShader(CDC* pDC, CP3 ViewPoint, CLighting* pLight, CMaterial* pMaterial, CTexture* pTexture);
private:
	void EdgeFlag(CPoint2 PStart, CPoint2 PEnd, BOOL bFeature);//边标记
	CVector3 LinearInterp(double t, double tStart, double tEnd, CVector3 vStart, CVector3 vEnd);//法向量线性插值
	CT2 LinearInterp(double t, double tStart, double tEnd, CT2 texStart, CT2 texEnd);
	void SortVertex(void);//三角形顶点排序
	CRGB GetTexture(int u, int v, CTexture* pTexture);//读取纹理
private:
	CP3 P0, P1, P2;//三角形的浮点数顶点
	CPoint3 point0, point1, point2;//三角形的整数顶点坐标
	CPoint2* SpanLeft; //跨度的起点数组标志
	CPoint2* SpanRight;//跨度的终点数组标志
	int nIndex;//扫描线索引
};

CTriangle.cpp:

#include "pch.h"
#include "Triangle.h"
#define ROUND(d) int(d + 0.5)

CTriangle::CTriangle(void)
{

}

CTriangle::~CTriangle(void)
{

}

void CTriangle::SetPoint(CP3 P0, CP3 P1, CP3 P2,CVector3 N0,CVector3 N1,CVector3 N2,CT2 T0,CT2 T1,CT2 T2)
{
	this->P0 = P0, this->P1 = P1, this->P2 = P2;

	point0.x = ROUND(P0.x);
	point0.y = ROUND(P0.y);
	point0.z = P0.z;
	point0.c = P0.c;
	point0.n = N0;
	point0.t = T0;

	point1.x = ROUND(P1.x);
	point1.y = ROUND(P1.y);
	point1.z = P1.z;
	point1.c = P1.c;
	point1.n = N1;
	point1.t = T1;

	point2.x = ROUND(P2.x);
	point2.y = ROUND(P2.y);
	point2.z = P2.z;
	point2.c = P2.c;
	point2.n = N2;
	point2.t = T2;
}

void CTriangle::PhongShader(CDC * pDC, CP3 ViewPoint, CLighting * pLight, CMaterial * pMaterial, CTexture * pTexture)
{
	double	CurrentDepth = 0.0;//当前扫描线的深度
	CVector3 Vector01(P0, P1), Vector02(P0, P2);
	CVector3 fNormal = CrossProduct(Vector01, Vector02);
	double A = fNormal.x, B = fNormal.y, C = fNormal.z;//平面方程Ax+By+Cz+D=0的系数
	double D = -A * P0.x - B * P0.y - C * P0.z;//当前扫描线随着x增长的深度步长
	if (fabs(C) < 1e-4)
		C = 1.0;
	double DepthStep = -A / C;//计算扫描线深度步长增量
	SortVertex();
	//定义三角形覆盖的扫描线条数
	int nTotalLine = point1.y - point0.y + 1;
	//定义span的起点与终点数组
	SpanLeft = new CPoint2[nTotalLine];
	SpanRight = new CPoint2[nTotalLine];
	//判断三角形与P0P1边的位置关系,0-1-2为右手系
	int nDeltz = (point1.x - point0.x) * (point2.y - point1.y) - (point1.y - point0.y) * (point2.x - point1.x);//点向量叉积的z坐标
	if (nDeltz > 0)//三角形位于P0P1边的左侧
	{
		nIndex = 0;
		EdgeFlag(point0, point2, TRUE);
		EdgeFlag(point2, point1, TRUE);
		nIndex = 0;
		EdgeFlag(point0, point1, FALSE);
	}
	else//三角形位于P0P1边的右侧
	{
		nIndex = 0;
		EdgeFlag(point0, point1, TRUE);
		nIndex = 0;
		EdgeFlag(point0, point2, FALSE);
		EdgeFlag(point2, point1, FALSE);
	}
	for (int y = point0.y; y < point1.y; y++)//下闭上开
	{
		int n = y - point0.y;
		BOOL bInFlag = FALSE;//跨度内外测试标志,初始值为假表示三角形外部
		for (int x = SpanLeft[n].x; x < SpanRight[n].x; x++)//左闭右开
		{
			if (bInFlag == FALSE)
			{
				CurrentDepth = -(A * x + B * y + D) / C;//z=-(Ax+By+D)/C
				bInFlag = TRUE;
				x -= 1;
			}
			else
			{
				CVector3 ptNormal = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].n, SpanRight[n].n);
				ptNormal = ptNormal.Normalize();
				/*-> 纹理颜色替换材质属性*/
				CT2 Texture = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].t, SpanRight[n].t);
				Texture.c = GetTexture(ROUND(Texture.u), ROUND(Texture.v), pTexture);
				pMaterial->SetDiffuse(Texture.c);
				pMaterial->SetAmbient(Texture.c);
				CRGB Intensity = pLight->Illuminate(ViewPoint, CP3(x, y, CurrentDepth), ptNormal, pMaterial);
				pDC->SetPixelV(x, y, RGB(Intensity.red * 255, Intensity.green * 255, Intensity.blue * 255));
				CurrentDepth += DepthStep;
			}
		}
	}
	if (SpanLeft)
	{
		delete[]SpanLeft;
		SpanLeft = NULL;
	}
	if (SpanRight)
	{
		delete[]SpanRight;
		SpanRight = NULL;
	}
}

void CTriangle::EdgeFlag(CPoint2 PStart, CPoint2 PEnd, BOOL bFeature)
{
	int dx = PEnd.x - PStart.x;
	int dy = PEnd.y - PStart.y;
	double m = double(dx) / dy;
	double x = PStart.x;
	for(int y = PStart.y; y < PEnd.y; y++)
	{
		CVector3 ptNormal = LinearInterp(y, PStart.y, PEnd.y, PStart.n, PEnd.n);
		CT2 Texture = LinearInterp(y, PStart.y, PEnd.y, PStart.t, PEnd.t);
		if (bFeature)
			SpanLeft[nIndex++] = CPoint2(ROUND(x), y, ptNormal, Texture);
		else
			SpanRight[nIndex++] = CPoint2(ROUND(x), y, ptNormal, Texture);
		x += m;
	}
}

CVector3 CTriangle::LinearInterp(double t, double tStart, double tEnd, CVector3 vStart, CVector3 vEnd)
{
	CVector3 vector;
	vector = (tEnd - t) / (tEnd - tStart) * vStart + (t - tStart) / (tEnd - tStart) * vEnd;
	return vector;
}

CT2 CTriangle::LinearInterp(double t, double tStart, double tEnd, CT2 texStart, CT2 texEnd)
{
	CT2 texture;
	texture = (t - tEnd) / (tStart - tEnd) * texStart + (t - tStart) / (tEnd - tStart) * texEnd;
	return texture;
}

void CTriangle::SortVertex(void)
{
	CPoint3 pt[3];
	pt[0] = point0;
	pt[1] = point1;
	pt[2] = point2;
	for (int i = 0; i < 2; i++)
	{
		int min = i;
		for (int j = i + 1; j < 3; j++)
			if (pt[j].y < pt[min].y)
				min = j;
		CPoint3 pTemp = pt[i];
		pt[i] = pt[min];
		pt[min] = pTemp;
	}
	point0 = pt[0];
	point1 = pt[2];
	point2 = pt[1];
}

CRGB CTriangle::GetTexture(int u, int v, CTexture * pTexture)
{
	v = pTexture->bmp.bmHeight -1- v;
	/*检测图片的边界,防止越界*/
	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;
	/*查找对应纹理空间的颜色值*/
	int position = v * pTexture->bmp.bmWidthBytes + 4 * u;//颜色分量位置	
	return  CRGB(pTexture->image[position + 2] / 255.0, pTexture->image[position + 1] / 255.0, pTexture->image[position] / 255.0);
}
PhongShader函数:
void CTriangle::PhongShader(CDC * pDC, CP3 ViewPoint, CLighting * pLight, CMaterial * pMaterial, CTexture * pTexture)
{
	double	CurrentDepth = 0.0;//当前扫描线的深度
	CVector3 Vector01(P0, P1), Vector02(P0, P2);
	CVector3 fNormal = CrossProduct(Vector01, Vector02);
	double A = fNormal.x, B = fNormal.y, C = fNormal.z;//平面方程Ax+By+Cz+D=0的系数
	double D = -A * P0.x - B * P0.y - C * P0.z;//当前扫描线随着x增长的深度步长
	if (fabs(C) < 1e-4)
		C = 1.0;
	double DepthStep = -A / C;//计算扫描线深度步长增量
	SortVertex();
	//定义三角形覆盖的扫描线条数
	int nTotalLine = point1.y - point0.y + 1;
	//定义span的起点与终点数组
	SpanLeft = new CPoint2[nTotalLine];
	SpanRight = new CPoint2[nTotalLine];
	//判断三角形与P0P1边的位置关系,0-1-2为右手系
	int nDeltz = (point1.x - point0.x) * (point2.y - point1.y) - (point1.y - point0.y) * (point2.x - point1.x);//点向量叉积的z坐标
	if (nDeltz > 0)//三角形位于P0P1边的左侧
	{
		nIndex = 0;
		EdgeFlag(point0, point2, TRUE);
		EdgeFlag(point2, point1, TRUE);
		nIndex = 0;
		EdgeFlag(point0, point1, FALSE);
	}
	else//三角形位于P0P1边的右侧
	{
		nIndex = 0;
		EdgeFlag(point0, point1, TRUE);
		nIndex = 0;
		EdgeFlag(point0, point2, FALSE);
		EdgeFlag(point2, point1, FALSE);
	}
	for (int y = point0.y; y < point1.y; y++)//下闭上开
	{
		int n = y - point0.y;
		BOOL bInFlag = FALSE;//跨度内外测试标志,初始值为假表示三角形外部
		for (int x = SpanLeft[n].x; x < SpanRight[n].x; x++)//左闭右开
		{
			if (bInFlag == FALSE)
			{
				CurrentDepth = -(A * x + B * y + D) / C;//z=-(Ax+By+D)/C
				bInFlag = TRUE;
				x -= 1;
			}
			else
			{
				CVector3 ptNormal = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].n, SpanRight[n].n);
				ptNormal = ptNormal.Normalize();
				/*-> 纹理颜色替换材质属性*/
				CT2 Texture = LinearInterp(x, SpanLeft[n].x, SpanRight[n].x, SpanLeft[n].t, SpanRight[n].t);
				Texture.c = GetTexture(ROUND(Texture.u), ROUND(Texture.v), pTexture);
				pMaterial->SetDiffuse(Texture.c);
				pMaterial->SetAmbient(Texture.c);
				CRGB Intensity = pLight->Illuminate(ViewPoint, CP3(x, y, CurrentDepth), ptNormal, pMaterial);
				pDC->SetPixelV(x, y, RGB(Intensity.red * 255, Intensity.green * 255, Intensity.blue * 255));
				CurrentDepth += DepthStep;
			}
		}
	}
	if (SpanLeft)
	{
		delete[]SpanLeft;
		SpanLeft = NULL;
	}
	if (SpanRight)
	{
		delete[]SpanRight;
		SpanRight = NULL;
	}
}

4.使用六张纹理照片:

CTexture.h:

#pragma once
#include"resource.h"

class CTexture
{
public:
	CTexture(void);
	virtual~CTexture(void);
	void PrepareBitmap(UINT nIDResource);//准备位图
	void DeleteObject(void);//释放位图
public:
	BYTE* image;
	BITMAP bmp;//BITMAP结构体变量
};

CTexture.cpp:

#include "pch.h"
#include "Texture.h"

CTexture::CTexture(void)
{
	image = NULL;
}

CTexture::~CTexture(void)
{
}

void CTexture::PrepareBitmap(UINT nIDResource)//准备位图
{
	CBitmap NewBitmap;
	NewBitmap.LoadBitmap(nIDResource);
	NewBitmap.GetBitmap(&bmp);//将CBitmap的信息保存到Bitmap结构体中
	int nbytesize = bmp.bmWidthBytes * bmp.bmHeight;
	image = new BYTE[nbytesize];
	NewBitmap.GetBitmapBits(nbytesize, (LPVOID)image);//将我们位图的信息复制到image数组中
}

void CTexture::DeleteObject(void)//释放位图
{
	if(NULL != image)
		delete []image;
}

在TestView.h中定义:

CCube cube;
	double Alpha, Beta;
	CTransform3 transform;
	BOOL bPlay;//动画按钮
	int	nLightSourceNumber;//光源数量
	CLighting* pLight;//光照环境
	CMaterial* pMaterial;//物体材质
	CTexture texture[6];//纹理

在TestView.cpp中定义:

bPlay = FALSE;
	double nEdge = 400;
	cube.ReadPoint();
	cube.ReadFacet();
	transform.SetMatrix(cube.GetVertexArrayName(), 8);
	transform.Scale(nEdge, nEdge, nEdge);
	transform.Translate(-nEdge / 2, -nEdge / 2, -nEdge / 2);//平移变换
	InitializeLightingScene();
	cube.SetScene(pLight, pMaterial);//设置场景
	texture[0].PrepareBitmap(IDB_BITMAP1);
	texture[1].PrepareBitmap(IDB_BITMAP2);
	texture[2].PrepareBitmap(IDB_BITMAP3);
	texture[3].PrepareBitmap(IDB_BITMAP4);
	texture[4].PrepareBitmap(IDB_BITMAP5);
	texture[5].PrepareBitmap(IDB_BITMAP6);
	cube.SetTexture(texture);

初始化光照:

void CTestView::InitializeLightingScene(void)//初始化光照环境
{
	//设置光源属性
	nLightSourceNumber = 1;//光源个数
	pLight = new CLighting(nLightSourceNumber);//一维光源动态数组
	pLight->LightSource[0].SetPosition(1000, 1000, 1000);//设置光源位置坐标
	for (int i = 0; i < nLightSourceNumber; i++)
	{
		pLight->LightSource[i].L_Diffuse = CRGB(1.0, 1.0, 1.0);//光源的漫反射颜色
		pLight->LightSource[i].L_Specular = CRGB(1.0, 1.0, 1.0);//光源镜面高光颜色
		pLight->LightSource[i].L_C0 = 1.0;//常数衰减因子
		pLight->LightSource[i].L_C1 = 0.0000001;//线性衰减因子
		pLight->LightSource[i].L_C2 = 0.00000001;//二次衰减因子
		pLight->LightSource[i].L_OnOff = TRUE;//光源开启
	}
	//设置材质属性
	pMaterial = new CMaterial;
	pMaterial->SetAmbient(CRGB(0.847, 0.10, 0.075));//环境反射率
	pMaterial->SetDiffuse(CRGB(0.852, 0.006, 0.026));//漫反射率
	pMaterial->SetSpecular(CRGB(0.3, 0.3, 0.3));//镜面反射率
	pMaterial->SetEmission(CRGB(0.0, 0.0, 0.0));//自身辐射的颜色
	pMaterial->SetExponent(50);//高光指数
}

绘制:

void CTestView::OnDraw(CDC* pDC)
{
	CTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	DoubleBuffer(pDC);
}
DoubelBuffer函数:
void CTestView::DoubleBuffer(CDC* pDC)//双缓冲
{
	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
	memDC.CreateCompatibleDC(pDC);//创建一个与显示pDC兼容的内存memDC
	CBitmap NewBitmap, *pOldBitmap;//内存中承载的临时位图 
	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);
	rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);
	DrawObject(&memDC);//向memDC绘制图形
	pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, -rect.Width() / 2, -rect.Height() / 2, SRCCOPY);//将内存memDC中的位图拷贝到显示pDC中
	memDC.SelectObject(pOldBitmap);//恢复位图
	NewBitmap.DeleteObject();//删除位图
}
按钮动画:
void CTestView::OnGraphAnimation()
{
	// TODO: Add your command handler code here
	bPlay = !bPlay;
	if (bPlay)//设置定时器
		SetTimer(1, 150, NULL);
	else
		KillTimer(1);
}

void CTestView::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: Add your message handler code here and/or call default
	Alpha = 5, Beta = 5;
	transform.RotateX(Alpha);
	transform.RotateY(Beta);
	Invalidate(FALSE);
	CView::OnTimer(nIDEvent);
}

void CTestView::OnUpdateGraphAnimation(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	if (bPlay)
		pCmdUI->SetCheck(TRUE);
	else
		pCmdUI->SetCheck(FALSE);
}
方向键动画:
void CTestView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: Add your message handler code here and/or call default
	switch (nChar)
	{
	case VK_UP:
		Alpha = -5;
		transform.RotateX(Alpha);
		break;
	case VK_DOWN:
		Alpha = +5;
		transform.RotateX(Alpha);
		break;
	case VK_LEFT:
		Beta = -5;
		transform.RotateY(Beta);
		break;
	case VK_RIGHT:
		Beta = +5;
		transform.RotateY(Beta);
		break;
	default:
		break;
	}
	Invalidate(FALSE);
	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}

四、实验结果分析

实验结果

实验总结

在这次实验中,对于纹理的贴图的个数要搞清楚,否则就会出现异常,关键是还找不到,就是提示异常,所以要注意这块的问题;在进行PhongShader函数的时候,要注意纹理那块的结合,否则又会出现异常;背面剔除算法,如果进行不当,就会发现少了1那个贴图;在背面剔除算法中,要注意最多只能看见三个面,因为这里都是单位化,所以这里要注意角度的正负就说明了哪些面可以看见,哪些面是不可以看见哒,本次实验,由于立方体是一个封闭结构,可以使用背面剔除算法,如果遇见非封闭的结构就不可以使用背面剔除算法。

参考文献

计算机图形学书;

在这个实验中,周围同学的帮助是很大哒。

  • 21
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值