资料借鉴 OpenGL学习之路10----透视投影

这里我将不使用顶点着色器、片段着色等实现OpenGL的底层API

main.cpp

#include<windows.h>
#include<iostream>
#include<stdio.h>
#include <GL/glut.h>
#include<vector>
#include "opengl_pipeline.h"
#include "node.h"
using namespace std;
const float Width = 500, Height = 500;

//定义了一个环境光
DirectionalLight m_directionalLight;
//定义一个像素点颜色 为红色
Vector3f pixel_color = { 1.0f, 0.0f, 0.0f };
//定义了坐标数组集
vector<Vertex> G;
//定义了一个透视投影的结构体
PersProjInfo gPersProjInfo;




/*
	函数名:Draw_Point
	功能:根据颜色、坐标画点
*/
void Draw_Point(Vector3f Color, Vector3f Position)
{
	glColor3f(Color[0], Color[1], Color[2]);
	glVertex3f(Position[0], Position[1], Position[2]);
}
/*
	函数名:Check_Point
	功能:检查坐标是否超出窗口大小
*/
bool Check_Point(float x, float y, float z = 0)
{
	if (x > Width / 2 || x < -Width / 2 || y > Height / 2 || y < -Height / 2) {
		printf("ERROR:坐标超出窗口大小 坐标为:(%f, %f, %f), 窗口取值区间为x:[%f, %f], y:[%f, %f]", x, y, z, -Width / 2, Width / 2, -Height / 2, Height / 2);
		exit(0);
		return 0;
	}
	else {
		return 1;
	}
}



//顶点着色器,得到最终的坐标系result
void ShaderVs(Vector3f result, Matrix44f gWorld, Vector3f World_Position)
{
	
	Multiply_Matrix4andVector3(result, gWorld, World_Position);
}

//这个就相当于是片段着色器
void Get_Color(Vector3f reslut, Vector3f pixel_color)//result就是最终的颜色
{
	Multipl_Vector3and3(reslut, pixel_color, m_directionalLight.Color);//坐标像素*平行光颜色
	Multipl_Vector3and_num(reslut, reslut, m_directionalLight.AmbientIntensity);//*平行光强度
}


/*
	函数名:round1
	功能:四舍五入函数
*/
inline int round1(const float a) { return int(a + 0.5); }

/*
	函数名:lineDDA
	功能:lineDDA算法画线
*/
void lineDDA(int x0, int y0, int z0, int xEnd, int yEnd, int zEnd) {
	int dx = xEnd - x0, dy = yEnd - y0, dz = zEnd - z0, steps, k;
	float xIncrement, yIncrement, zIncrement, x = x0, y = y0, z = z0;
	steps = max(fabs(dx), fabs(dy), fabs(dz));

	xIncrement = float(dx) / float(steps);
	yIncrement = float(dy) / float(steps);
	zIncrement = float(dz) / float(steps);
	//cout << "xIncrement: " << xIncrement << " yIncrement: " << yIncrement << endl;
	int id = 1;
	Vertex tmp;
	tmp.m_pos[0] = round1(x);
	tmp.m_pos[1] = round1(y);
	tmp.m_pos[2] = round1(z);
	G.push_back(tmp);
	for (k = 0; k < steps; k++) {
		x += xIncrement;
		y += yIncrement;
		z += zIncrement;
		tmp.m_pos[0] = round1(x);
		tmp.m_pos[1] = round1(y);
		tmp.m_pos[2] = round1(z);
		G.push_back(tmp);
	}
}

/*
	函数名:Render
	功能:绘图
*/
void Render()
{
	m_directionalLight.AmbientIntensity *= 1.01f;
	glClear(GL_COLOR_BUFFER_BIT);
	//glPointSize(2.0f);
	glBegin(GL_POINTS);

	for (int i = 0; i < G.size(); ++i) {
		
		Vector3f tmp;
		LoadVector3(tmp, G[i].m_pos[0], G[i].m_pos[1], G[i].m_pos[2]);
		Vector3f FragColor;
		Get_Color(FragColor, pixel_color);
		//printf("颜色信息:%f %f %f\n", FragColor[0], FragColor[1], FragColor[2]);
		Draw_Point(FragColor, tmp);
	}
	glEnd();
	glFlush();
}

/*
	函数名:Create_Point_Buffer
	功能:预处理坐标数组
*/

void Create_Points_Buffer()
{
	/*lineDDA(0, 0, 200, 200);
	lineDDA(200, 200, 0, 200);
	lineDDA(0, 200, 0, 0);*/
	lineDDA(0, -100, 100, 50, 50, 200);
	lineDDA(0, -100, 100, 200, 100, 200);
	lineDDA(0, -100, 100, -100, 200, 200);
	lineDDA(50, 50, 200, 200, 100, 200);
	lineDDA(50, 50, 200, -100, 200, 200);
	lineDDA(200, 100, 200, -100, 200, 200);
	static float Scale = 0.0f;
	Scale += 0.1f;
	Pipeline p;
	p.Rotate(0.0f, 0.0f, 0.0f);
	p.WorldPos(0.0f, 0.0f, 0.0f);
	p.SetPerspectiveProj(gPersProjInfo);

	Matrix44f gl_position;
	//LoadIdentity44(gl_position);
	p.GetWPTrans();
	memcpy(gl_position, p.m_WPtransformation, sizeof(p.m_WPtransformation));
	//gl_position = p.m_WPtransformation;
	//p.Get_WPtransformation(gl_position);

	cout << "混合变换and投影矩阵: " << endl;
	cout<< gl_position[0] << " " << gl_position[1] << " " << gl_position[2] << " "<< gl_position[3]<<endl;
	cout<< gl_position[4] << " " << gl_position[5] << " " << gl_position[6] << " "<< gl_position[7]<<endl;
	cout<< gl_position[8] << " " << gl_position[9] << " " << gl_position[10] << " "<< gl_position[11]<<endl;
	cout<< gl_position[12] << " " << gl_position[13] << " " << gl_position[14] << " "<< gl_position[15]<<endl;


	//坐标标准化
	for (int i = 0; i < G.size(); ++i) {
		Check_Point(G[i].m_pos[0], G[i].m_pos[1]);
		Vector3f result;
		
		ShaderVs(result, gl_position, G[i].m_pos);

		//Transform_Coordinates(G[i].m_pos[0], G[i].m_pos[1], Width, Height);//到窗口坐标
		//G[i].m_pos[2] = 0.5;


		G[i].m_pos[0] = result[0];G[i].m_pos[1] = result[1];G[i].m_pos[2] = result[2];
		//cout << "投影后的变换: " << result[0] << " " << result[1] << " " << result[2] << endl;
		//printf("投影变换后:%f %f %f\n", gl_position[0], gl_position[1], gl_position[2]);
		/*printf("%f %f\n", G[i].x, G[i].y);*/
	}
}

void pre_work()
{
	
	/*
		光信息
		声明一个平行光结构体变量,并赋予初值,光线颜色为白色(1.0f,1.0f,1.0f),环境光强为0.1f,漫反射光强为0.75f,漫反射光方向为(1.0f,0.0,0.0)即射向X轴正方向
	*/
	LoadVector3(m_directionalLight.Color, 1.0f, 1.0f, 1.0f);
	m_directionalLight.AmbientIntensity = 1.0f;
	m_directionalLight.DiffuseIntensity = 0.75f;
	LoadVector3(m_directionalLight.Direction, 1.0f, 0.0, 0.0);
	/*
		透视投影
	*/
	gPersProjInfo.FOV = 90.0f;//视野90度
	gPersProjInfo.Height = 768;//屏幕高为768
	gPersProjInfo.Width = 1024;//屏幕宽为1024
	gPersProjInfo.zNear = 1.0f;//最近距离1
	gPersProjInfo.zFar = 100.0f;//最远距离100	



	//坐标数据
	Create_Points_Buffer();
}

void init(int argc, char* argv[])
{
	pre_work();
	glutInit(&argc, argv);
	
	glutInitDisplayMode(GLUT_RGB);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(Width, Height);
	glutCreateWindow("Windows");
}
void test()
{
	Matrix44f a;
	Vector3f b, c;
	b[0] = 1, b[1] = 2, b[2] = 3;
	LoadIdentity44(a);
	a[1] = 2;
	Multiply_Matrix4andVector3(c, a, b);
	printf("结果为 %f %f %f\n", c[0], c[1], c[2]);
}
int main(int argc, char* argv[])
{

	//test();
	init(argc, argv);
	
	glutDisplayFunc(&Render);

	glutMainLoop();
	return 0;
}

node.h

#ifndef __NODE_H
#define __NODE_H

#include "opengl_math.h"

/*
	坐标点的结构体
*/
struct Vertex
{
	Vector3f m_pos;//坐标
	Vector2f m_tex;//纹理映射用法
	Vector3f m_normal;//法向量

	Vertex() {}

	Vertex(Vector3f pos, Vector2f tex)
	{
		CopyVector3(m_pos, pos);
		CopyVector2(m_tex, tex);
		LoadVector3(m_normal, 0.0f, 0.0f, 0.0f);
	}
};

/*
	环境光(平行光)的结构体
*/
struct DirectionalLight
{
	Vector3f Color;//颜色
	float AmbientIntensity;//光强
	Vector3f Direction;//射入方向向量
	float DiffuseIntensity;//漫反射变量参数
};


#endif 

opengl_math.h

#ifndef __OPENGL_MATH_H
#define __OPENGL_MATH_H


#define PI (3.14159265358979323846)
#define PI_DIV_180 (0.017453292519943296)
#define INV_PI_DIV_180 (57.2957795130823229)

#define DegToRad(x)  ((x)*PI_DIV_180)
#define RadToDeg(x)  ((x)*INV_PI_DIV_180)

typedef float Vector4f[4];
typedef float Vector3f[3];
typedef float Vector2f[2];

//	3 * 3 矩阵:
typedef float   Matrix33f[9];

//  4 * 4 矩阵:
typedef float Matrix44f[16];

//透视投影矩阵
struct PersProjInfo
{
	float FOV;//视野(角度)
	float Width;//屏幕宽度
	float Height;//屏幕高度
	float zNear;//到近处平面的距离
	float zFar;//到远处平面的距离
};


/*
	函数名:LoadVector3
	功能:给三维坐标赋值
*/
inline void LoadVector3(Vector3f a, float x, float y, float z)
{
	a[0] = x, a[1] = y, a[2] = z;
}

/*
	函数名:Transform_Standard_Coordinates
	功能:将坐标大小转化为2 * 2 的坐标系内
*/
inline void Transform_Coordinates(float &x, float &y, const float Width, const float Height)
{
	x = x * 2 / Width;
	y = y * 2 / Height;
}
/*
	函数名:Multipl_Vector3and3
	功能:3维向量乘3维向量
*/
inline void Multipl_Vector3and3(Vector3f result, Vector3f a, Vector3f b)
{
	result[0] = a[0] * b[0];
	result[1] = a[1] * b[1];
	result[2] = a[2] * b[2];
}
/*
	函数名:PersProjectionMatrix44
	功能:透视投影矩阵初始化
*/
inline void PersProjectionMatrix44(Matrix44f m, PersProjInfo p)
{
	const float ar = p.Width / p.Height;
	const float zRange = p.zNear - p.zFar;
	const float tanHalfFOV = tanf(DegToRad(p.FOV / 2.0f));

	m[0] = 1.0f / (tanHalfFOV * ar); m[4] = 0.0f;                m[8] = 0.0f;                           m[12] = 0.0;
	m[1] = 0.0f;                     m[5] = 1.0f / tanHalfFOV;   m[9] = 0.0f;                           m[13] = 0.0;
	m[2] = 0.0f;                     m[6] = 0.0f;                m[10] = (-p.zNear - p.zFar) / zRange;  m[14] = 2.0f*p.zFar*p.zNear / zRange;
	m[3] = 0.0f;                     m[7] = 0.0f;                m[11] = 1.0f;                          m[15] = 0.0;

}
/*
	函数名Multipl_Vector3and_num
	功能:3维向量乘一个常数
*/
inline void Multipl_Vector3and_num(Vector3f result, Vector3f a, const float b)
{
	result[0] = a[0] * b;
	result[1] = a[1] * b;
	result[2] = a[2] * b;
}

//向量复制
inline void CopyVector2(Vector2f dst, const Vector2f src) { memcpy(dst, src, sizeof(Vector2f)); }
inline void CopyVector3(Vector3f dst, const Vector3f src) { memcpy(dst, src, sizeof(Vector3f)); }


//4*4单位矩阵初始化函数
inline void LoadIdentity44(Matrix44f m)
{
	m[0] = 1.0f; m[4] = 0.0f; m[8] = 0.0f;  m[12] = 0.0f;
	m[1] = 0.0f; m[5] = 1.0f; m[9] = 0.0f;  m[13] = 0.0f;
	m[2] = 0.0f; m[6] = 0.0f; m[10] = 1.0f; m[14] = 0.0f;
	m[3] = 0.0f; m[7] = 0.0f; m[11] = 0.0f; m[15] = 1.0f;
}
//4*4矩阵相乘
inline void MatrixMultiply44(Matrix44f product, const Matrix44f a, const Matrix44f b)
{
	unsigned int j, k;
	for (unsigned int i = 0; i < 16; i++) {
		j = i % 4;
		k = i / 4 * 4;
		product[i] = a[j] * b[k] + a[j + 4] * b[k + 1] + a[j + 8] * b[k + 2] + a[j + 12] * b[k + 3];
	}
}
//4*4矩阵乘3维向量坐标
inline void Multiply_Matrix4andVector3(Vector3f product, const Matrix44f a, const Vector3f b)
{
	Vector4f result, tmp;
	for (int i = 0; i < 4; ++i) result[i] = 0;
	for (int i = 0; i < 3; ++i)  tmp[i] = b[i];
	tmp[3] = 1;
	unsigned int j, k;
	for (unsigned int i = 0; i < 16; i++) {
		result[i / 4] += a[i] * tmp[i % 4];
	}
	for (int i = 0; i < 3; ++i) {
		product[i] = result[i] / result[3];
	}
}

//缩放变换
inline void ScaleMatrix44(Matrix44f m, float xScale, float yScale, float zScale)
{
	LoadIdentity44(m); m[0] = xScale; m[5] = yScale; m[10] = zScale;
}
//旋转变换
inline void RotationMatrix44(Matrix44f m, float angle, float x, float y, float z)
{
	LoadIdentity44(m);
	if (z == 1)//绕z轴
	{
		m[0] = cosf(angle); m[4] = -sinf(angle);
		m[1] = sinf(angle); m[5] = cosf(angle);
	}
	else if (y == 1)//绕y轴
	{
		m[0] = cosf(angle); m[8] = -sinf(angle);
		m[2] = sinf(angle); m[10] = cosf(angle);
	}
	else if (x == 1)//绕x轴
	{
		m[5] = cosf(angle); m[9] = -sinf(angle);
		m[6] = sinf(angle); m[10] = cosf(angle);
	}
}
inline void RotationMatrix44(Matrix44f m, float RotateX, float RotateY, float RotateZ)
{
	Matrix44f rx, ry, rz, temp;

	const float x = DegToRad(RotateX);
	const float y = DegToRad(RotateY);
	const float z = DegToRad(RotateZ);

	RotationMatrix44(rx, x, 1, 0, 0);
	RotationMatrix44(ry, y, 0, 1, 0);
	RotationMatrix44(rz, z, 0, 0, 1);

	MatrixMultiply44(temp, rz, ry);
	MatrixMultiply44(m, temp, rx);

}
//平移变换
inline void TranslationMatrix44(Matrix44f m, float x, float y, float z)
{
	LoadIdentity44(m); m[12] = x; m[13] = y; m[14] = z;
}


/*
	函数名:CalcNormals
	功能:计算顶点法线的代码

	先根据索引取出每个三角形的三个顶点计算其法向量
	每个三角形法向量都是从第一个顶点到其他两个顶点两条边向量进行差积
	差积之后得到的三角形法向量进行单位化
	把单位化后的三角形法向量与顶点法向量累加
	最后再把所有顶点的顶点法向量单位化
*/
//
//static void CalcNormals(const unsigned int* pIndices, unsigned int IndexCount, Vertex* pVertices, unsigned int VertexCount)
//{
//	for (unsigned int i = 0; i < IndexCount; i += 3) {
//		unsigned int Index0 = pIndices[i];
//		unsigned int Index1 = pIndices[i + 1];
//		unsigned int Index2 = pIndices[i + 2];
//		Vector3f v1, v2;
//		SubVector3(v1, pVertices[Index1].m_pos, pVertices[Index0].m_pos);
//		SubVector3(v2, pVertices[Index2].m_pos, pVertices[Index0].m_pos);
//		Vector3f Normal;
//		CrossProduct3(Normal, v1, v2);
//		NormalizeVector3(Normal);
//
//		AddVector3(pVertices[Index0].m_normal, pVertices[Index0].m_normal, Normal);
//		AddVector3(pVertices[Index1].m_normal, pVertices[Index1].m_normal, Normal);
//		AddVector3(pVertices[Index2].m_normal, pVertices[Index2].m_normal, Normal);
//	}
//	for (unsigned int i = 0; i < VertexCount; i++) {
//		NormalizeVector3(pVertices[i].m_normal);
//	}
//}
#endif // DEBUG

opengl_pipeline.h

#ifndef __OPENGL_PIPELINE_H
#define __OPENGL_PIPELINE_H

#include<iostream>
#include "node.h"


class Pipeline
{
private:
	Vector3f m_scale;//尺度,控制放缩变换
	Vector3f m_worldPos;//控制平移变换
	Vector3f m_rotateInfo;//旋转,控制旋转变换

	PersProjInfo m_persProjInfo;//透视投影结构体

	Matrix44f m_transformation;//复杂变换矩阵
	Matrix44f m_Wtransformation;//三种基础的混合转换
	Matrix44f m_ProjTransformation;//透视投影矩阵
	

public:
	Matrix44f m_WPtransformation;//先进行混合变换再进行透视投影操作后的矩阵
	Pipeline() {
		LoadVector3(m_scale, 1.0f, 1.0f, 1.0f);
		LoadVector3(m_worldPos, 0.0f, 0.0f, 0.0f);
		LoadVector3(m_rotateInfo, 0.0f, 0.0f, 0.0f);
	}
	
	/*
		函数名:Scale
		功能:m_scale向量赋值
	*/
	void Scale(float ScaleX, float ScaleY, float ScaleZ)
	{
		LoadVector3(m_scale, ScaleX, ScaleY, ScaleZ);
	}
	/*
		函数名:WorldPos
		功能:m_worldPos向量赋值
	*/
	void WorldPos(float x, float y, float z)
	{
		LoadVector3(m_worldPos, x, y, z);
	}
	/*
		函数名:Rotate
		功能:m_rotateInfo向量赋值
	*/
	void Rotate(float RotateX, float RotateY, float RotateZ)
	{
		LoadVector3(m_rotateInfo, RotateX, RotateY, RotateZ);
	}
	/*
		函数名:SetPerspectiveProj
		功能:投影信息赋值
	*/
	void SetPerspectiveProj(const PersProjInfo& p)
	{
		m_persProjInfo = p;
	}


	const Matrix44f * Pipeline::GetWorldTrans();
	const Matrix44f * Pipeline::GetProjTrans();
	const Matrix44f * Pipeline::GetWPTrans();


	/*const Matrix44f * Pipeline::GetWVPTrans()
	{
		GetWorldTrans();
		GetVPTrans();

		MatrixMultiply44(m_WVPtransformation, m_VPtransformation, m_Wtransformation);
		return &m_WVPtransformation;;
	}

	const Matrix44f * Pipeline::GetVPTrans()
	{
		GetViewTrans();
		GetProjTrans();

		MatrixMultiply44(m_VPtransformation, m_ProjTransformation, m_Vtransformation);
		return &m_VPtransformation;
	}*/
};

#endif 

opengl_pipeline.cpp

#include "opengl_pipeline.h"
/*
	函数名:GetWorldTrans
	功能:GetTrans()方法用来计算混合变换矩阵的值(在opengl_pipeline.c中实现)
*/
const Matrix44f * Pipeline::GetWorldTrans()
{
	Matrix44f ScaleTrans, RotateTrans, TranslationTrans, temp;
	LoadIdentity44(ScaleTrans);
	LoadIdentity44(RotateTrans);
	LoadIdentity44(TranslationTrans);

	ScaleMatrix44(ScaleTrans, m_scale[0], m_scale[1], m_scale[2]);//放缩

	RotationMatrix44(RotateTrans, m_rotateInfo[0], m_rotateInfo[1], m_rotateInfo[2]);//旋转

	TranslationMatrix44(TranslationTrans, m_worldPos[0], m_worldPos[1], m_worldPos[2]);//平移

	MatrixMultiply44(temp, TranslationTrans, RotateTrans);//temp = TranslationTrans * RotateTrans
	MatrixMultiply44(m_Wtransformation, temp, ScaleTrans); //m_Wtransformation = temp * ScaleTrans
	//m_Wtransformation=TranslationTrans * RotateTrans * ScaleTrans //先缩放,再旋转 最后平移
	return &m_Wtransformation;
}

/*
	函数名:GetProjTrans
	功能:投影矩阵m_ProjTransformation的赋值
*/
const Matrix44f * Pipeline::GetProjTrans()
{
	PersProjectionMatrix44(m_ProjTransformation, m_persProjInfo);
	return &m_ProjTransformation;
}
/*
	函数名:GetWPTrans
	功能:混合变换=>投影变换
*/
const Matrix44f * Pipeline::GetWPTrans()
{
	Matrix44f PersProjTrams;

	GetWorldTrans();

	PersProjectionMatrix44(PersProjTrams, m_persProjInfo);

	MatrixMultiply44(m_WPtransformation, PersProjTrams, m_Wtransformation);
	/*cout << "混合变换:" << endl;
	cout << m_Wtransformation[0] << " " << m_Wtransformation[1] << " " << m_Wtransformation[2] << " " << m_Wtransformation[3] << endl;
	cout << m_Wtransformation[4] << " " << m_Wtransformation[5] << " " << m_Wtransformation[6] << " " << m_Wtransformation[7] << endl;
	cout << m_Wtransformation[8] << " " << m_Wtransformation[9] << " " << m_Wtransformation[10] << " " << m_Wtransformation[11] << endl;
	cout << m_Wtransformation[12] << " " << m_Wtransformation[13] << " " << m_Wtransformation[14] << " " << m_Wtransformation[15] << endl;
	cout << "投影矩阵:" << endl;
	cout << PersProjTrams[0] << " " << PersProjTrams[1] << " " << PersProjTrams[2] << " " << PersProjTrams[3] << endl;
	cout << PersProjTrams[4] << " " << PersProjTrams[5] << " " << PersProjTrams[6] << " " << PersProjTrams[7] << endl;
	cout << PersProjTrams[8] << " " << PersProjTrams[9] << " " << PersProjTrams[10] << " " << PersProjTrams[11] << endl;
	cout << PersProjTrams[12] << " " << PersProjTrams[13] << " " << PersProjTrams[14] << " " << PersProjTrams[15] << endl;

	cout << "混合变换and投影矩阵111: " << endl;
	cout << m_WPtransformation[0] << " " << m_WPtransformation[1] << " " << m_WPtransformation[2] << " " << m_WPtransformation[3] << endl;
	cout << m_WPtransformation[4] << " " << m_WPtransformation[5] << " " << m_WPtransformation[6] << " " << m_WPtransformation[7] << endl;
	cout << m_WPtransformation[8] << " " << m_WPtransformation[9] << " " << m_WPtransformation[10] << " " << m_WPtransformation[11] << endl;
	cout << m_WPtransformation[12] << " " << m_WPtransformation[13] << " " << m_WPtransformation[14] << " " << m_WPtransformation[15] << endl;



	cout << "透视投影矩阵:" << endl;
	cout << m_persProjInfo.FOV << endl;
	cout << m_persProjInfo.Height << endl;
	cout << m_persProjInfo.Width << endl;
	cout << m_persProjInfo.zFar << endl;
	cout << m_persProjInfo.zNear << endl;*/

	//m_WPtransformation = PersProjTrams * TranslationTrans * RotateTrans * ScaleTrans //先缩放,然后旋转,平移,最后投影

	return &m_WPtransformation;
}

【效果图】

通过更改main.cpp的角度会有不同的显示效果

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐