SoftRender学习笔记

源码&参考:知乎 雪流星

阴影部分的知识打算看完games202后再完善

目录

一、在C++中创建一个窗口

Window类---负责开窗口并实时更新

二、需要的头文件

Color类---定义了颜色信息

Vector3类---三维向量

Matrix类---4x4矩阵

Vertex类---模型的顶点

MyMath类---关键定义了重心坐标的求法

Transform类---定义平移旋转缩放矩阵

Mesh类---用于创建模型

Buffer类---深度缓存

插入知识点 ---视图变换过程

 Light类---定义光源

Camera类---用于观测的摄像机

Input类---检测键盘输入

 Texture类---加载并存储纹理

插入知识点----shadow map算法

Uniform类

三、软光栅封装

Shader类

Renderer类

ObjFileReader类---读取模型文件,存入Mesh的Buffer中

四、主函数及测试效果


一、在C++中创建一个窗口

为了把渲染的图片放在窗口里,不用反复打开图片查看

不重要,以下代码实现了创建并显示一个窗口的功能,入口函数是WinMain

不过本项目中是用的main为入口函数,手动写了一个Window类

#include<Windows.h>

//自定义的窗口过程
LRESULT CALLBACK MyWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
	switch (Msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	default:
		return DefWindowProc(hWnd, Msg, wParam, lParam);
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR ICmdLine, int nCmdShow) {

	// 创建窗口类实例wnd
	WNDCLASS wnd = {
		CS_HREDRAW,
		MyWindowProc,          // 使用自定义的窗口过程函数
		0,0,hInstance,
		LoadIcon(NULL,IDI_APPLICATION),
		LoadCursor(NULL,IDC_ARROW),
		(HBRUSH)(GetStockObject(WHITE_BRUSH)),
		NULL, L"mic@Renderer"
	};
	// 注册窗口类
	RegisterClass(&wnd);
	// 创建窗口
	HWND hWnd = CreateWindow(L"mic@Renderer", L"mic@Renderer", WS_OVERLAPPEDWINDOW,
		100, 100, 500, 500, NULL, NULL, hInstance, NULL);
	// 显示窗口
	ShowWindow(hWnd, nCmdShow);
	// 更新窗口
	UpdateWindow(hWnd);
	//消息循环
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0)) {    // 循环获取消息
		TranslateMessage(&msg);               // 翻译消息
		DispatchMessage(&msg);                // 派发消息
	}
	return 0;
}

Window类---负责开窗口并实时更新

#pragma once
#include<Windows.h>


class Window {
public:
	HWND window; //HWND是一个基本类型--窗口句柄(句柄是Windows系统中对象或实例的标识)
	int windowWidth;
	int windowHeight;
	HDC hdc;
	HDC screenHDC; //HDC是指窗体、控件的句柄

	//构造和析构
	Window(int w, int h, const char* name);
	~Window();

};

#include "Window.h"
#include <iostream>
using namespace std;



LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	Window* window = static_cast<Window*>(GetPropA(hWnd, "Owner"));

	if (!window)
		return DefWindowProcA(hWnd, msg, wParam, lParam);

	switch (msg)
	{
	}

	return DefWindowProcA(hWnd, msg, wParam, lParam);
}



Window::Window(int w, int h, const char* name) :windowWidth(w), windowHeight(h)
{
	WNDCLASS wndClass = { CS_BYTEALIGNCLIENT, (WNDPROC)MsgProc, 0, 0, 0, NULL, NULL, NULL, NULL, TEXT("Test") };
	wndClass.hInstance = GetModuleHandle(NULL);

	if (!RegisterClass(&wndClass))
		return;

	window = CreateWindow(TEXT("Test"), TEXT("Test"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
		0, 0, 0, 0, NULL, NULL, wndClass.hInstance, NULL);
	if (window == NULL)
		return;

	hdc = GetDC((window));
	screenHDC = CreateCompatibleDC(hdc);
	//ReleaseDC(handler, hdc);

	BITMAPINFO bitmapInfo = { { sizeof(BITMAPINFOHEADER),windowWidth, windowHeight, 1, 32, BI_RGB, windowWidth * windowHeight * 4, 0, 0, 0, 0 } };
	LPVOID ptr;
	//创建设备无关的位图
	HBITMAP bitmapHandler = CreateDIBSection(screenHDC, &bitmapInfo, DIB_RGB_COLORS, &ptr, 0, 0);
	if (bitmapHandler == NULL)
		return;

	HBITMAP screenObject = (HBITMAP)SelectObject(screenHDC, bitmapHandler);

	SetWindowPos(window, NULL, 50, 50, windowWidth, windowHeight, (SWP_NOCOPYBITS | SWP_NOZORDER | SWP_SHOWWINDOW));

	ShowWindow(window, SW_NORMAL);
	UpdateWindow(window);

}

Window::~Window()
{
}



二、需要的头文件

Color类---定义了颜色信息

float r,g,b,a四个属性

重载了加减乘除运算符实现颜色间的运算

定义了颜色的插值函数

#pragma once


class Color {
	float r, g, b, a;

	Color(float cr, float cg, float cb, float ca);
	Color() {};
	~Color();

	//操作符重载---Color+Color
	Color operator+(const Color& right)const;

	//操作符重载---Color+常数
	Color operator+(const float c) {
		return Color(r + c, g + c, b + c, a);
	}

	//操作符重载---Color-Color
	Color operator-(const Color& right)const;
	//操作符重载---Color*Color
	Color operator*(const Color& right)const;
	//操作符重载---Color*常数
	Color operator*(float value)const;
	//操作符重载---Color/Color
	Color operator/(float value)const;

	//Color线性插值
	static Color Lerp(const Color& left, const Color& right, float t);

	//白色
	static Color white;
};
#include "Color.h"

Color::Color(float cr, float cg, float cb, float ca):r(cr),g(cg),b(cb),a(ca)
{

}

Color::~Color()
{
}

Color Color::operator+(const Color& right) const
{
	Color returnValue(r + right.r, g + right.g, b + right.b, a + right.a);
	return returnValue;
}

Color Color::operator-(const Color& right) const
{
	Color returnValue(r - right.r, g - right.g, b - right.b, a - right.a);
	return returnValue;
}

Color Color::operator*(const Color& right) const
{
	Color returnValue(r * right.r, g * right.g, b * right.b, a * right.a);
	return returnValue;
}

Color Color::operator*(float value) const
{
	Color returnValue(r * value, g * value, b * value, a * value);
	return returnValue;
}

Color Color::operator/(float value) const
{
	float rhvalue = 1.0f / value; //倒数,变除法为乘法
	Color returnValue(r * rhvalue, g * rhvalue, b * rhvalue, a * rhvalue);
	return returnValue;
}

Color Color::Lerp(const Color& left, const Color& right, float t)
{
	return left + (right - left) * t;
}

Color Color::white = Color(1, 1, 1, 1);

Vector3类---三维向量

注意:类模板的声明和定义应该放在一个文件内

float x,y,z,w四个属性

定义了点乘(对应位相乘,结果是数),叉乘(“求谁盖谁,+ - +”,结果是向量),求模等常见操作,定义了单位化(模长为1)和标准化(w为1)函数

此文件中顺便定义了Vector2类,有 float x y两个属性

#pragma once

template<class T>
class Vector3 {
public:
	T x, y, z, w;

	Vector3<T>(T fx, T fy, T fz);
	Vector3<T>(T fx, T fy, T fz, T fw);
	//默认构造参数(0,0,0,1)
	Vector3<T>() {
		x = y = z = 0;
		w = 1;
	}

	//向量+向量
	Vector3<T> operator+(const Vector3<T>& right)const;
	//向量-向量
	Vector3<T> operator-(const Vector3<T>& right)const;
	//向量*常数
	Vector3<T>operator*(float value)const;
	//向量/常数
	Vector3<T>operator/(float value)const;
	
	//求模长^2
	float SquareMagnitude();
	//求模长
	float Magnitude();
	//单位化
	Vector3<T>& Normalize();

	//点乘
	float static Dot(const Vector3<T>& left, const Vector3<T>& right);
	float Dot(const Vector3<T>& right);
	//叉乘
	Vector3<T> static Cross(const Vector3<T>& left, const Vector3<T>& right);

	//插值
	Vector3<T> static Lerp(const Vector3<T>& left, const Vector3<T>& right, float t);

	//标准化(w变成1)
	void standardization()
	{
		if (w == 0)
		{
			std::cout << "error w==0" << std::endl;
			return;
		}
		x /= w;
		y /= w;
		z /= w;
		w = 1;
	}

	void Print();
};

using Vector3f = Vector3<float>;
using Vector3i = Vector3<int>;

template<class T>
Vector3<T>::Vector3(T fx, T fy, T fz) {
	x = fx;
	y = fy;
	z = fz;
	w = 1;
}

template<class T>
Vector3<T> Vector3<T>::operator+(const Vector3<T>& right)const
{
	Vector3<T> returnValue(x + right.x, y + right.y, z + right.z);
	return returnValue;
}
template<class T>
Vector3<T> Vector3<T>::operator-(const Vector3<T>& right)const
{
	Vector3<T> returnValue(x - right.x, y - right.y, z - right.z);
	return returnValue;
}
template<class T>
Vector3<T> Vector3<T>::operator*(float value)const
{
	Vector3<T> returnValue(x * value, y * value, z * value);
	return returnValue;
}
template<class T>
Vector3<T> Vector3<T>::operator/(float value)const
{
	Vector3<T> returnValue(x / value, y / value, z / value);
	return returnValue;
}

template<class T>
float Vector3<T>::SquareMagnitude() {
	return Dot(*this, *this);
}

template<class T>
float Vector3<T>::Magnitude() {
	return sqrt(SquareMagnitude());
}

template<class T>
Vector3<T>& Vector3<T>::Normalize() {
	*this = *this / Magnitude();
	return *this;
}

//点乘返回一个值---对应位相乘后求和(没涉及w)
template<class T>
float Vector3<T>::Dot(const Vector3<T>& left, const Vector3<T>& right)
{
	return left.x * right.x + left.y * right.y + left.z * right.z;
}

template<class T>
float Vector3<T>::Dot(const Vector3<T>& right)
{
	return x * right.x + y * right.y + z * right.z;
}

//叉乘
template<class T>
Vector3<T> Vector3<T>::Cross(const Vector3<T>& left, const Vector3<T>& right) {
	float valueX = left.y * right.z - left.z * right.y;
	float valueY = left.z * right.x - left.x * right.z;
	float valueZ = left.x * right.y - left.y * right.x;
	Vector3<T> returnValue(valueX, valueY, valueZ);
	return returnValue;
}

template<class T>
Vector3<T> Vector3<T>::Lerp(const Vector3<T>& left, const Vector3<T>& right,float t) {
	return left + (right - left) * t;
}

template<class T>
void Vector3<T>::Print() {
	std::cout << "Vector3<T> x: " << x << " y: " << y << " z: " << z << std::endl;
}


//同时定义了二维向量
class Vector2 {
public:
	float x, y;

	Vector2() { x = y = 0; }
	Vector2(float fx,float fy) {
		x = fx;
		y = fy;
	}

	~Vector2() {};
	Vector2 operator + (const Vector2& right) const
	{
		return Vector2(x + right.x, y + right.y);
	}
	Vector2 operator - (const Vector2& right) const
	{
		return Vector2(x - right.x, y - right.y);
	}
	Vector2 operator * (float value) const
	{
		return Vector2(x * value, y * value);
	}
	Vector2 operator / (float value) const
	{
		return Vector2(x / value, y / value);
	}
};

Matrix类---4x4矩阵

成员变量是4*4的二维数组

定义了矩阵的运算,矩阵与向量的运算等

(特别记忆:矩阵的乘法:m.value[i][j] += this->value[i][k] *right.value[k][j];)

#pragma once
#include"Vector3.h"

class Matrix {
public:
	float value[4][4]; //4x4的矩阵

	Matrix();
	~Matrix();

	Matrix operator+(const Matrix& right)const;
	Matrix operator-(const Matrix& right)const;
	Matrix operator*(const Matrix& right)const;
	Matrix operator*(float k)const;

	//矩阵x向量
	Vector3f MutiplyVector3(const Vector3f& v)const;

	//正交化矩阵
	void Identity();

	//矩阵转置
	Matrix transpose()const {
		Matrix trans;
		for(int i=0;i<4;i++)
			for (int j = 0; j < 4; j++) {
				trans.value[i][j] = value[j][i];
			}
		return trans;
	}

	//打印
	void Print();
};
#include "Matrix.h"
#include <iostream>

Matrix::Matrix()
{
	Identity();
}

Matrix::~Matrix()
{
}

Matrix Matrix::operator+(const Matrix& right) const
{
	Matrix m;
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 4; j++) {
			m.value[i][j] = this->value[i][j] + right.value[i][j];
		}
	}
	return m;
}

Matrix Matrix::operator-(const Matrix& right) const
{
	Matrix m;
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			m.value[i][j] = this->value[i][j] - right.value[i][j];
		}
	}
	return m;
}

Matrix Matrix::operator*(const Matrix& right) const
{
	Matrix m;
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 4; j++) {
			for (int k = 0; k < 4; k++) {
				m.value[i][j] += this->value[i][k] *right.value[k][j];
			}
		}
	}
	return m;
}

Matrix Matrix::operator*(float k) const
{
	Matrix m;
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			m.value[i][j] = this->value[i][j] * k;
		}
	}
	return m;
}

Vector3f Matrix::MutiplyVector3(const Vector3f& v) const
{
	float x = v.x * value[0][0] + v.y * value[0][1] + v.z * value[0][2] + v.w * value[0][3];
	float y = v.x * value[1][0] + v.y * value[1][1] + v.z * value[1][2] + v.w * value[1][3];
	float z = v.x * value[2][0] + v.y * value[2][1] + v.z * value[2][2] + v.w * value[2][3];
	float w = v.x * value[3][0] + v.y * value[3][1] + v.z * value[3][2] + v.w * value[3][3];

	Vector3f returnValue(x, y, z);
	returnValue.w = w;
	return returnValue;
}

void Matrix::Identity()
{
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 4; j++) {
			if (i == j)
				value[i][j] = 1;
			else
				value[i][j] = 0;
		}
	}
}

void Matrix::Print()
{
	std::cout << "-----------------Matrix Begin--------------" << std::endl;
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			std::cout << "[" << value[i][j] << "]   ";
		}
		std::cout << std::endl;
	}
	std::cout << "-----------------Matrix End----------------" << std::endl;
}

Vertex类---模型的顶点

顶点信息记录了:Vector3f 顶点坐标、Vector3f 法线方向、颜色信息,Vector2 uv坐标

定义了顶点信息插值(深度插值 颜色插值 uv坐标插值)、顶点与矩阵相乘等方法(只有pos和normal成员需要乘上矩阵)

#pragma once
#include"Color.h"
#include"Matrix.h"

class Vertex {
public:
	Vector3f pos;	//顶点坐标
	Vector3f normal;//法线向量
	Color color;    //颜色信息
	Vector2 uv;		//uv坐标

	Vertex() {};
	Vertex(const Vector3f& p, const Color& c, Vector2 uv);
	Vertex(const Vector3f& p, const Color& c, const Vector3f& normal, Vector2 uv);
	~Vertex();

	//对顶点信息进行插值
	void LerpVertexData(Vertex& left, const Vertex& right, float t);
	//打印顶点坐标和RGB颜色信息
	void Print();
	//顶点*矩阵
	Vertex& operator*(const Matrix& m);
	static float LerpFloat(float v1, float v2, float t) { return v1 + (v2 - v1) * t; }
};

#include"Vertex.h"
#include"Vector3.h"
#include <iostream>

Vertex::Vertex(const Vector3f& p, const Color& c, Vector2 uv)
	: pos(p), color(c), uv(uv)
{

}

Vertex::Vertex(const Vector3f& p, const Color& c, const Vector3f& normal, Vector2 uv) : pos(p), color(c), normal(normal), uv(uv)
{
}

Vertex::~Vertex()
{

}

void Vertex::LerpVertexData(Vertex& left, const Vertex& right, float t)
{
	pos.z = LerpFloat(left.pos.z, right.pos.z, t); //深度插值
	color = Color::Lerp(left.color, right.color, t);//颜色信息插值
	uv.x = LerpFloat(left.uv.x, right.uv.x, t); //uv坐标插值
	uv.y = LerpFloat(left.uv.y, right.uv.y, t);
	
}

void Vertex::Print()
{
	std::cout << "Vector3f: " << pos.x << " " << pos.y << " " << pos.z;
	std::cout << " Color: " << color.r << " " << color.g << " " << color.b << std::endl;
}

Vertex& Vertex::operator*(const Matrix& m)
{
	//顶点乘一个变换矩阵时,只有顶点和法线进行操作
	pos.x = pos.x * m.value[0][0] + pos.y * m.value[0][1] + pos.z * m.value[0][2] + pos.w * m.value[0][3];
	pos.y = pos.x * m.value[1][0] + pos.y * m.value[1][1] + pos.z * m.value[1][2] + pos.w * m.value[1][3];
	pos.z = pos.x * m.value[2][0] + pos.y * m.value[2][1] + pos.z * m.value[2][2] + pos.w * m.value[2][3];
	pos.w = pos.x * m.value[3][0] + pos.y * m.value[3][1] + pos.z * m.value[3][2] + pos.w * m.value[3][3];

	//注意,只有旋转+平移才能直接使用MVP矩阵,如果产生了变形,法线再这样乘就是错的
	normal.x = normal.x * m.value[0][0] + normal.y * m.value[0][1] + normal.z * m.value[0][2] + normal.w * m.value[0][3];
	normal.y = normal.x * m.value[1][0] + normal.y * m.value[1][1] + normal.z * m.value[1][2] + normal.w * m.value[1][3];
	normal.z = normal.x * m.value[2][0] + normal.y * m.value[2][1] + normal.z * m.value[2][2] + normal.w * m.value[2][3];
	normal.w = normal.x * m.value[3][0] + normal.y * m.value[3][1] + normal.z * m.value[3][2] + normal.w * m.value[3][3];

	return *this;
}

MyMath类---关键定义了重心坐标的求法

作者在此定义了一个clamp方法来限制x的大小

同时定义了重要的方法——求重心坐标

#pragma once
#include"Vector3.h"
#define PI 3.1415926535

//将x限制在mi~ma的范围内
float clamp(float x, float mi, float ma);

//已知p,求其在v1,v2,v3组成的三角形内的重心坐标
Vector3f centerOfGravity(Vector3f v1, Vector3f v2, Vector3f v3, Vector2 p);
#include"MyMath.h"

float clamp(float x, float mi, float ma)
{
	if (x < mi)x = mi;
	if (x > ma)x = ma;
	return x;
}

Vector3f centerOfGravity(Vector3f v1, Vector3f v2, Vector3f v3, Vector2 p)
{
	//这两种情况说明三角形面积为0
	if ((-(v1.x - v2.x) * (v3.y - v2.y) + (v1.y - v2.y) * (v3.x - v2.x)) == 0)
		return Vector3f(1, 0, 0);
	if (-(v2.x - v3.x) * (v1.y - v3.y) + (v2.y - v3.y) * (v1.x - v3.x) == 0)
		return Vector3f(1, 0, 0);

	//重心坐标
	float alpha = (-(p.x - v2.x) * (v3.y - v2.y) + (p.y - v2.y) * (v3.x - v2.x)) / (-(v1.x - v2.x) * (v3.y - v2.y) + (v1.y - v2.y) * (v3.x - v2.x));
	float beta = (-(p.x - v3.x) * (v1.y - v3.y) + (p.y - v3.y) * (v1.x - v3.x)) / (-(v2.x - v3.x) * (v1.y - v3.y) + (v2.y - v3.y) * (v1.x - v3.x));
	float gamma = 1 - alpha - beta;
	return Vector3f(alpha, beta, gamma);
}


Transform类---定义平移旋转缩放矩阵

封装了平移,旋转,缩放所需的参数

定义了成员ObjectToWorld矩阵

定义了根据传参构造T,R,S矩阵的方法

#pragma once
#include"Matrix.h"
#include"MyMath.h"

class Transform {
public:
	//平移、旋转缩放参数
	Vector3f position; 
	Vector3f rotation; 
	Vector3f scale;	   

	Matrix objectToWorld;

	//(不仅要构造出矩阵,还要把参数赋值给对应的成员变量)
	Matrix Translate(const Vector3f& v); //平移(根据传的参数v构造平移矩阵)
	//根据angle构造绕X/Y/Z轴旋转的矩阵
	Matrix RotateX(float angle);
	Matrix RotateY(float angle);
	Matrix RotateZ(float angle);

	//封装了RotateX Y Z,根据传进来的三个角去旋转
	Matrix Rotate(const Vector3f& rotAngle);

	//缩放(根据传的参数s构造缩放矩阵)
	Matrix Scale(const Vector3f& s);

	Transform(Vector3f pos, Vector3f rot, Vector3f s) :position(pos), rotation(rot), scale(s) {}
	Transform() { objectToWorld.Identity(); }
};
#include"Transform.h"
#include <cmath>

Matrix Transform::Translate(const Vector3f& v) {
	position = v;
	Matrix m;
	m.Identity();

	//每行的第四列负责平移
	m.value[0][3] = v.x;
	m.value[1][3] = v.y;
	m.value[2][3] = v.z;
	return m;
}

Matrix Transform::RotateX(float angle)
{
	rotation.x = angle;
	Matrix m;
	m.Identity();

	float radian = angle / 360.0f * PI;
	float cosValue = cos(radian);
	float sinValue = sin(radian);
	m.value[1][1] = cosValue;
	m.value[1][2] = -sinValue;
	m.value[2][1] = sinValue;
	m.value[2][2] = cosValue;
	return m;
}

Matrix Transform::RotateY(float angle)
{
	rotation.y = angle;
	Matrix m;
	m.Identity();
	float radian = angle / 360.0f * PI;
	float cosValue = cos(angle);
	float sinValue = sin(angle);
	m.value[0][0] = cosValue;
	m.value[0][2] = sinValue;
	m.value[2][0] = -sinValue;
	m.value[2][2] = cosValue;
	return m;
}

Matrix Transform::RotateZ(float angle)
{
	rotation.z = angle;
	Matrix m;
	m.Identity();
	float radian = angle / 360.0f * PI;
	float cosValue = cos(angle);
	float sinValue = sin(angle);
	m.value[0][0] = cosValue;
	m.value[0][1] = -sinValue;
	m.value[1][0] = sinValue;
	m.value[1][1] = cosValue;
	return m;
}

Matrix Transform::Rotate(const Vector3f& rotAngle)
{
	rotation = rotAngle;
	Matrix rotX = RotateX(rotAngle.x);
	Matrix rotY = RotateY(rotAngle.y);
	Matrix rotZ = RotateZ(rotAngle.z);

	return rotX * rotY * rotZ; //同时执行三种变换
}

Matrix Transform::Scale(const Vector3f& s)
{
	Matrix m;
	scale = s;
	m.Identity();
	m.value[0][0] = s.x;
	m.value[1][1] = s.y;
	m.value[2][2] = s.z;
	return m;
}

Mesh类---用于创建模型

含成员变量Transform transform

数组vertexBuffer                顶点

        positionBuffer            顶点坐标

        normalBuffer              法线

        uvBuffer                      uv坐标

        indexBuffer                f中三个下标

        以上这些除了顶点都读取自.obj模型文件

#pragma once
#include"Vertex.h"
#include"Transform.h"
#include<vector>

class Mesh {
public:
	Transform transform;

	std::vector<Vertex> vertexBuffer;
	std::vector<Vector3f>positionBuffer;
	std::vector<Vector3f>normalBuffer;
	std::vector<Vector2>uvBuffer;
	std::vector<Vector3i>indexBuffer;

	Mesh();
	~Mesh();

	Transform GetTransform() { return transform; }
	int GetIndexBufferLength() { return indexBuffer.size(); }
	void SetTransform(Transform& t) { transform = t;}
	Matrix GetObjectToWorld() { return transform.objectToWorld; }
	void SetObjectToWorld(const Matrix& m) { transform.objectToWorld = m; }

	void AddVertexData(const Vector3f  pos, float u, float v, const Color color = Color::white);
	void AddVertexData(float posx, float posy, float posz, float u, float v, const Color color = Color::white);
	void AddVertexData(float posx, float posy, float posz, float u, float v, Vector3f nor, const Color color = Color::white);
};
#include "Mesh.h"

Mesh::Mesh()
{

}

Mesh::~Mesh()
{
}

void Mesh::AddVertexData(const Vector3f pos, float u, float v, const Color color)
{
	Vertex p(pos, color, Vector2(u, v));
	vertexBuffer.push_back(p);
}

void Mesh::AddVertexData(float posx, float posy, float posz, float u, float v, const Color color)
{
	AddVertexData(Vector3f(posx, posy, posz), u, v, color);
}

void Mesh::AddVertexData(float posx, float posy, float posz, float u, float v, Vector3f nor, const Color color)
{
	Vertex p(Vector3f(posx, posy, posz), color, nor, Vector2(u, v));
	vertexBuffer.push_back(p);
}

Buffer类---深度缓存

定义了二维数组depthBuffer

定义了Sample方法

#pragma once
struct Buffer {
	int height, width;
};

struct DepthBuffer :Buffer {
	float** depthBuffer; //深度缓存(二维数组)
	DepthBuffer(int width, int height) {
		this->height = height;
		this->width = width;
		//为depthBuffer分配空间
		depthBuffer = new float* [height];
		for (int i = 0; i < height; i++) {
			depthBuffer[i] = new float[width];
		}
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				depthBuffer[i][j] = 1; //深度缓存初始化为1
			}
		}
	}

	//将value限制在min和max内
	float Clamp(float min, float max, float value)
	{
		if (value > max)
			value = max;
		if (value < min)
			value = min;
		return value;
	}

	//采样
	float Sample(float u, float v) {
		int y = Clamp(0, height - 1, u);
		int x = Clamp(0, width - 1, v);
		return depthBuffer[y][x];
	}

	~DepthBuffer() {
		for (int i = 0; i < height; i++)
		{
			delete[] depthBuffer[i];
		}
	}
};

插入知识点 ---视图变换过程

避免之后产生混淆,在此复习一下视图变换的过程

 Light类---定义光源

定义了两种光的类——平行光和点光源(现在主要只看了平行光)

属性光照强度、光源位置、光源方向

一个bool变量来控制着色方式——逐顶点or逐像素

方法----Matrix LookAt(const Vector3f& upAxis)    这个和相机那个类似

#pragma once
#include"Matrix.h"

//平行光
class DirectionLight {
private:
	Vector3f direction; //光照方向
	Vector3f position;  //光源位置
public:
	float intensity; //光照强度
	bool forVertex; //逐顶点或逐像素光照着色

	//默认构造:光照强度为1,逐顶点着色
	DirectionLight() { intensity = 1;  forVertex = true; }

	DirectionLight(const Vector3f& dir, const Vector3f& pos, float Intensity = 1, bool forV = true)
	{
		direction = dir;
		position = pos;
		intensity = Intensity;
		forVertex = forV;
	}
};

//点光源
class PointLight
{
public:
	PointLight() { intensity = 1.0; }
	PointLight(const Vector3f& pos, float inten) :position(pos), intensity(inten) {}
	~PointLight() {}
	Vector3f position;
	float intensity;

};
#include"Light.h"

Matrix DirectionLight::LookAt(const Vector3f& upAxis)
{
	Vector3f lookDir = direction;
	lookDir.Normalize(); 

	Vector3f rightDir = Vector3f::Cross(upAxis, lookDir);
	rightDir.Normalize();

	Vector3f upDir = Vector3f::Cross(lookDir, rightDir);
	upDir.Normalize();

	Matrix m;
	m.value[0][0] = rightDir.x;  m.value[1][0] = upDir.x;  m.value[2][0] = lookDir.x;  m.value[3][0] = 0;
	m.value[0][1] = rightDir.y;	 m.value[1][1] = upDir.y;  m.value[2][1] = lookDir.y;  m.value[3][1] = 0;
	m.value[0][2] = rightDir.z;  m.value[1][2] = upDir.z;  m.value[2][2] = lookDir.z;  m.value[3][2] = 0;

	m.value[0][3] = -position.x;		 m.value[1][3] = -position.y;   m.value[2][3] = -position.z;	   m.value[3][3] = 1;

	return m;
}

Camera类---用于观测的摄像机

Transform类transform,矩阵v,矩阵p成员

定义了三个方法:透视矩阵(两种定义方法),正交矩阵,摄像机变换LookAt矩阵

透视投影矩阵的推导结论

#pragma once
#include"Transform.h"

class Camera {
public:
	Transform transform; //相当于M矩阵
	Matrix v, p;

	Camera(Transform t):transform(t){}
	Camera() {}

	//LookAt矩阵
	Matrix LookAt(const Vector3f& eyePos, const Vector3f& lookat, const Vector3f& upAxis);
	//透视和正交矩阵
	Matrix Perspective(float fov, float aspect, float nearPanel, float farPanel);
	Matrix Perspective(float l, float r, float n, float f, float t, float b);
	Matrix Orthographic(float l, float r, float n, float f, float t, float b);
};
#include"Camera.h"
#include <cmath>

Matrix Camera::LookAt(const Vector3f& eyePos, const Vector3f& lookat, const Vector3f& upAxis)
{
	Vector3f lookDir = lookat;
	lookDir.Normalize();

	Vector3f rightDir = Vector3f::Cross(upAxis, lookDir);
	rightDir.Normalize();

	Vector3f upDir = Vector3f::Cross(lookDir, rightDir);
	upDir.Normalize();

	//自此,获得了相机的坐标系
	Matrix m;
	//原坐标系变换到相机坐标系的 逆 矩阵(也就是相机到原点)
	m.value[0][0] = rightDir.x;  m.value[1][0] = upDir.x;  m.value[2][0] = lookDir.x;  m.value[3][0] = 0;
	m.value[0][1] = rightDir.y;	 m.value[1][1] = upDir.y;  m.value[2][1] = lookDir.y;  m.value[3][1] = 0;
	m.value[0][2] = rightDir.z;  m.value[1][2] = upDir.z;  m.value[2][2] = lookDir.z;  m.value[3][2] = 0;
	m.value[0][3] = -eyePos.x;		 m.value[1][3] = -eyePos.y;   m.value[2][3] = -eyePos.z;	   m.value[3][3] = 1;


	v = m; //给成员v赋值
	return v;
}

//https://zhuanlan.zhihu.com/p/122411512
//视锥角,宽高比,远近平面定义的投影转正交->正交
Matrix Camera::Perspective(float fov, float aspect, float nearPanel, float farPanel)
{
	float tanValue = tan(0.5f * fov * PI / 180);

	Matrix proj;
	proj.value[0][0] = 1 / (tanValue * aspect);
	proj.value[1][1] = 1/tanValue;
	proj.value[2][2] = (nearPanel + farPanel) / (nearPanel - farPanel);
	proj.value[2][3] = -2 * nearPanel * farPanel / (nearPanel - farPanel);
	proj.value[3][2] = 1;
	proj.value[3][3] = 0;
	p = proj;

	return proj;

}


//几个面定义的投影转正交-->正交
Matrix Camera::Perspective(float l, float r, float n, float f, float t, float b)
{
	Matrix m;
	m.value[0][0] = 2 * n / (r - l);  m.value[0][1] = 0;                m.value[0][2] = (l + r) / (l - r);                     m.value[0][3] = 0;
	m.value[1][0] = 0;	             m.value[1][1] = 2 * n / (t - b);  m.value[1][2] = (b + t) / (b - t);                    m.value[1][3] = 0;
	m.value[2][0] = 0;                m.value[2][1] = 0;                 m.value[2][2] = (n + f) / (n - f);                m.value[2][3] = 2 * n * f / (f - n);
	m.value[3][0] = 0;		         m.value[3][1] = 0;                 m.value[3][2] = 1;	                                m.value[3][3] = 0;
	
	p = m;
	return m;
}


//正交投影(缩放*平移矩阵得到的总矩阵)
Matrix Camera::Orthographic(float l, float r, float n, float f, float t, float b)
{
	Matrix m;
	m.value[0][0] = 2 / (r - l);  m.value[0][1] = 0;           m.value[0][2] = 0;            m.value[0][3] = -(r + l) / (r - l);
	m.value[1][0] = 0;	      m.value[1][1] = 2 / (t - b);  m.value[1][2] = 0;             m.value[1][3] = -(t + b) / (t - b);
	m.value[2][0] = 0;         m.value[2][1] = 0;          m.value[2][2] = 2 / (n - f);    m.value[2][3] = -(n + f) / (n - f);
	m.value[3][0] = 0;		  m.value[3][1] = 0;          m.value[3][2] = 0;	          m.value[3][3] = 1;
	p = m;

	return m;
}

Input类---检测键盘输入

负责检测键盘的输入

#pragma once

#define IS_KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define IS_KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

 Texture类---加载并存储纹理

用于加载纹理

定义了成员变量---二维数组textureData到时候就是要通过textureData[u][v]来访问纹理

定义成员方法---Sample(和Buffer里的Sample思想一样儿)和LoadTexture(存到textureData里)

#pragma once
#include"Color.h"

class Color;
class Texture {
private:
	int width;
	int height;
	Color textureData[1024][1024];
public:
	Texture();
	~Texture();

	//根据路径打开纹理图
	void LoadTexture(const char*path);
	Color Sample(float u, float v);
	float Clamp(float min, float max, float value);
};
#include "Texture.h"
#include<Windows.h>

Texture::Texture()
{
	width = 512;
	height = 512;
}

Texture::~Texture()
{
}

void Texture::LoadTexture(const char* path)
{
	//加载位图
	HBITMAP bitmap = (HBITMAP)LoadImage(NULL, path, IMAGE_BITMAP, width, height, LR_LOADFROMFILE);

	//hdc可标识这张图
	HDC hdc = CreateCompatibleDC(NULL);
	SelectObject(hdc, bitmap);

	//获取到纹理图的颜色,赋值给textureData成员
	for (int i = 0; i < width; i++)
	{
		for (int j = 0; j < height; j++)
		{
			//RGB转为int
			COLORREF color = GetPixel(hdc, i, j);
			int r = color % 256;
			int g = (color >> 8) % 256;
			int b = (color >> 16) % 256;
			Color c((float)r / 256, (float)g / 256, (float)b / 256, 1);
			textureData[i][j] = c;
		}
	}
}

Color Texture::Sample(float u, float v)
{
	//把u v限制在0,1
	u = Clamp(0, 1.0f, u);
	v = Clamp(0, 1.0f, v);
	int intu = width * u;
	int intv = height * v;
	return textureData[intu][intv];
}

float Texture::Clamp(float min, float max, float value)
{
	if (value > max)
		value = max;
	if (value < min)
		value = min;
	return value;
}

插入知识点----shadow map算法

将物体顶点通过矩阵运算转移到灯光空间下

在灯光坐标下渲染物体阴影:

        创建一张深度贴图,用于保存物体在灯光空间下的深度信息。

        创建过程:如果某个顶点的深度值比原来深度贴图中的值更小,就更新深度贴图,反之则丢弃。

        获取到深度贴图后,如果某个点在光源视角下深度值大于深度贴图中对应位置的深度值,说明它在阴影中。那么就对该顶点乘上阴影的颜色

Uniform类

一致性变量 

三个类:

  • PhongVert
    • ​​​​​​​光照的数组
    • cameraPos观测位置
    • mvp矩阵
    • 三个顶点
    • shadow map要用的lp0,1,2   lightV lightP矩阵
  • PhongFrag
    • ​​​​​​​纹理指针
    • 深度缓存指针
  • ShadowVert
    • ​​​​​​​​​​​​​​mvp矩阵
#pragma once
#include <vector>
#include "Light.h"
#include "Vector3.h"
#include "Texture.h"
#include "Matrix.h"
#include "Buffer.h"

struct PhongVert {
	std::vector<DirectionLight>dirlights; //直射光数组
	std::vector<PointLight>pointlights; //点光源数组

	Vector3f cameraPos;	//相机观测位置
	Vector3f lp0, lp1, lp2; //站在光位置的坐标-用于计算shadow map

	Matrix m, v, p;		//视图变换矩阵
	Vertex v0, v1, v2;  //三个顶点信息
	Matrix lightV, lightP;	//站在光位置的VP矩阵-用于计算shadow map
};

struct PhongFrag {
	Texture* baseTex;	//基础纹理
	DepthBuffer* depthBuffer; //深度缓存

	PhongFrag(Texture* baseTex, DepthBuffer* depthBuffer) :baseTex(baseTex), depthBuffer(depthBuffer) {}
	~PhongFrag() {
		
	}
};


struct ShadowVert {
	Matrix lightV, lightP;    //灯光视角的MVP矩阵
	Matrix m;
};

接下来是最核心的两个类

三、软光栅封装

Shader类

两个类(其中都含有函数顶点着色器VS和片元着色器FS):

  • PhongShader
    • ​​​​​​​PhongVert v2f
    • PhongFrag frag
    • CalcuteShadow函数
  • ShadowShader
    • ​​​​​​​ShadowVert v2f
#pragma once
#include"MyMath.h"
#include"Vertex.h"
#include"Uniform.h"

//抽象类IShader
struct IShader {
public:
	//顶点着色器
	virtual void VS(Vertex& v0, Vertex& v1, Vertex& v2) = 0;
	//片元着色器
	virtual bool FS(Vertex& v, Vector3f g) = 0;
};

struct PhongShader :public IShader {
public:
	PhongVert v2f; //vertex to fragment
	PhongFrag frag;
public:
	PhongShader(PhongVert v2f,PhongFrag frag):v2f(v2f),frag(frag){}
	~PhongShader(){}
	//自IShader继承
	virtual void VS(Vertex& v0, Vertex& v1, Vertex& v2) override;
	virtual bool FS(Vertex& v, Vector3f g) override;
	float CalcuteShadow(Vector3f posLightSpace, double bias);
};

class ShadowShader :public IShader
{
public:
	ShadowShader() {}
	~ShadowShader() {}
	// 通过 IShader 继承
	virtual void VS(Vertex& v0, Vertex& v1, Vertex& v2) override;

	virtual bool FS(Vertex& v, Vector3f g) override;

	ShadowVert v2f;
};
#include "Shader.h"
using namespace std;
void PhongShader::VS(Vertex& v0, Vertex& v1, Vertex& v2)
{
	//phongvert获取到参数的顶点
	v2f.v0 = v0;
	v2f.v1 = v1;
	v2f.v2 = v2;
	Vertex* v = &v0; //v用来遍历三个顶点
	for (int i = 0; i < 3; i++)
	{
		switch (i)
		{
			//从顶点pos获取lp,并进行MVP变换
		case 0:
			v = &v0;
			v2f.lp0 = v0.pos;
			v2f.lp0 = v2f.m.MultiplyVector3(v2f.lp0);
			v2f.lp0 = v2f.lightV.MultiplyVector3(v2f.lp0);
			v2f.lp0 = v2f.lightP.MultiplyVector3(v2f.lp0);
			break;
		case 1:
			v = &v1;
			v2f.lp1 = v1.pos;
			v2f.lp1 = v2f.m.MultiplyVector3(v2f.lp1);
			v2f.lp1 = v2f.lightV.MultiplyVector3(v2f.lp1);
			v2f.lp1 = v2f.lightP.MultiplyVector3(v2f.lp1);
			break;
		case 2:
			v = &v2;
			v2f.lp2 = v2.pos;
			v2f.lp2 = v2f.m.MultiplyVector3(v2f.lp2);
			v2f.lp2 = v2f.lightV.MultiplyVector3(v2f.lp2);
			v2f.lp2 = v2f.lightP.MultiplyVector3(v2f.lp2);

			break;
		}

		//顶点的M变换
		v->pos = v2f.m.MultiplyVector3(v->pos);

		//此处和transform中的法线处理存疑
		Matrix nm = v2f.m;
		//去掉平移.不考虑变形缩放的情况下使用,正常情况下使用逆的转置
		nm.value[0][3] = 0;
		nm.value[1][3] = 0;
		nm.value[2][3] = 0;
		v->normal = nm.MultiplyVector3(v->normal).Normalize();
		

		//可选着色

		float diffuse = 0;	//漫反射
		float specular = 0; //镜面反射
		float ambient = 0.1;//环境光
		//直射光
		for (auto light : v2f.dirlights)
		{
			Vector3f l = light.GetDirection().Normalize();
		
			diffuse += max(0.f, l.Dot(v->normal)) * light.intensity;

			Vector3f h = ((v2f.cameraPos - v->pos).Normalize() + l).Normalize();

			specular += pow(max(0.f, v->normal.Dot(h)), 1) * light.intensity;
			//diffuse+ specular超过1会出现渲染错误
		}
		//点光源
// 		for (auto light : v2f.pointlights)
// 		{
// 			Vector3f l = (light.position-v->pos).Normalize();
// 			diffuse += max(0, l.Dot(v->normal))*light.intensity*min(1, 1 / (light.position - v->pos).Magnitude());
// 
// 			Vector3f h = ((v2f.cameraPos - v->pos).Normalize() + (light.position-v->pos).Normalize()).Normalize();
// 			//h.Normalize();
// 
// 			specular += pow(max(0, v->normal.Dot(h)), 1)*light.intensity*min(1, 1 / (light.position - v->pos).Magnitude());
// 			//float k = (specular + diffuse) *light.intensity*min(1, 1 / (light.position - v.pos).Magnitude());
// 			//cout << k << endl;
// 			//cout << diffuse <<" "<< specular << endl;  Color::white+
// 			// v.color + specular + diffuse;
// 				//diffuse+ specular超过1会出现渲染错误
// 			//v.color =v.color*(min(1, k));// Color(specular + diffuse, specular + diffuse, specular + diffuse, 1);
// 				//Color(diffuse+specular, diffuse + specular, diffuse + specular, 1);
// 			//cout << v.color.r << " "<<v.color.g << " " << v.color.b << " " << endl;
// 		}

		v->color = v->color * (min(1.f, specular + diffuse + ambient)); //颜色乘上光照
		
		//VP变换
		v->pos = v2f.v.MultiplyVector3(v->pos);

		v->pos = v2f.p.MultiplyVector3(v->pos);

		v->pos.standardization();
	
	}

	//保证v0.y  v1.y  v2.y的顺序
	if (v1.pos.y < v0.pos.y)
	{
		std::swap(v2f.lp0, v2f.lp1);
		std::swap(v1, v0);

	}

	if (v2.pos.y < v0.pos.y)
	{
		std::swap(v2f.lp0, v2f.lp2);
		std::swap(v2, v0);
	}

	if (v2.pos.y < v1.pos.y)
	{
		std::swap(v2f.lp1, v2f.lp2);
		std::swap(v2, v1);

	}

}

bool PhongShader::FS(Vertex& v, Vector3f g)
{
	//颜色乘上纹理信息
	v.color = v.color * frag.baseTex->Sample(v.uv.x, v.uv.y);

	//法线插值
	Vector3f normal = v2f.v0.normal * g.x + v2f.v1.normal * g.y + v2f.v2.normal * g.z;

	//光照空间下的插值
	Vector3f posLightSpace = v2f.lp0 * g.x + v2f.lp1 * g.y + v2f.lp2 * g.z;

	//阴影
	//https://juejin.cn/post/7021462579859947527
	float bias = 0.005;  //引入偏移量bias的原因:避免Shadow ance
	if (v2f.dirlights.size() > 0)
	{
		bias = max(0.02 * (1.0 - abs(Vector3f::Dot(normal.Normalize(), v2f.dirlights[0].GetDirection().Normalize()))), 0.005);
		//Slope Scale Based Depth Bias
	}
	
	float depth = CalcuteShadow(posLightSpace, bias);
	
	v.color = v.color * (1 - depth);

	return v.color.a > 0;
}


//bias可以通过角度计算
float PhongShader::CalcuteShadow(Vector3f posLightSpace, double bias)
{
	float reciprocalW = 1.0f / posLightSpace.w;
	//加0.5做之后的四舍五入
	posLightSpace.x = (posLightSpace.x * reciprocalW + 1.0f) * 0.5f * (frag.depthBuffer->width - 1) + 0.5;
	posLightSpace.y = (posLightSpace.y * reciprocalW + 1.0f) * 0.5f * (frag.depthBuffer->height - 1) + 0.5;

	float depth = (posLightSpace.z + 1.0) / 2.0;


	//此处可以有PCF优化
	float shadow = 0.0;
	
	//普通阴影
	float closestDepth = frag.depthBuffer->Sample(posLightSpace.y, posLightSpace.x);
	shadow = depth - bias > closestDepth ? 1 : 0;

	return shadow;
}

void ShadowShader::VS(Vertex& v0, Vertex& v1, Vertex& v2)
{
	Vertex* v = &v1;
	for (int i = 0; i < 3; i++)
	{
		switch (i)
		{
		case 0:
			v = &v0;
			break;
		case 1:
			v = &v1;
			break;
		case 2:
			v = &v2;
			break;
		}
		//MVP矩阵
		v->pos = v2f.m.MultiplyVector3(v->pos);
		v->pos = v2f.lightV.MultiplyVector3(v->pos);
		v->pos = v2f.lightP.MultiplyVector3(v->pos);
		v->pos.standardization();

	}
	if (v1.pos.y < v0.pos.y)
	{
		std::swap(v1, v0);

	}

	if (v2.pos.y < v0.pos.y)
	{
		std::swap(v2, v0);

	}

	if (v2.pos.y < v1.pos.y)
	{
		std::swap(v2, v1);

	}
}

bool ShadowShader::FS(Vertex& v, Vector3f g)
{
	//啥都不做
	return false;
}

Renderer类

texture指针

和开窗口有关的变量

光照数组

相机

#pragma once

#include "Vertex.h"
#include "Light.h"
#include "Texture.h"
#include "Camera.h"
#include"Shader.h"
#include "Mesh.h"
#include "Buffer.h"
#include<Windows.h>
using namespace std;
class Renderer
{
private:
	int deviceWidth;
	int deviceHeight;
	HDC screenHDC;
	Texture* tex;

public:
	vector<DirectionLight> directionlights;
	vector<PointLight> pointlights;
	Camera* camera;
public:
	Renderer(HDC hdc, int screenWidth, int screenHeight, Camera* cam);
	~Renderer();

	//每渲染一次,都要清除深度缓存
	void Clear(DepthBuffer* zbuffer);
	//根据indexBuffer绘制
	void DrawByIndex(Mesh* m, IShader* shader, DepthBuffer* zbuffer);
	//根据顶点绘制
	void DrawByArray(Mesh* m, IShader* shader, DepthBuffer* zbuffer);
	void DrawMesh(Mesh* m, IShader* shader, DepthBuffer* zbuffer);
	void DrawPrimitive(Vertex v0, Vertex v1, Vertex v2, IShader* shader, DepthBuffer* zbuffer);
	void RasterizeTrangle(Vertex v0, Vertex v1, Vertex v2, IShader* shader, DepthBuffer* zbuffer);
	//swapIndex代表第几个点是插值出来的
	void DrawTopFlatTrangle(Vertex v0, Vertex v1, Vertex v2, IShader* shader, DepthBuffer* zbuffer, Vertex v3, int swapIndex);
	void DrawBottomFlatTrangle(Vertex v0, Vertex v1, Vertex v2, IShader* shader, DepthBuffer* zbuffer, Vertex v3, int swapIndex);
	void DrawLine(Vertex v0, Vertex v1, IShader* shader, DepthBuffer* zbuffer, Vector3f p0, Vector3f p1, Vector3f p2);
	void DrawPixel(int x, int y, const Color& color);

	bool ZTestAndWrite(int x, int y, float depth, DepthBuffer* zbuffer);

	//准备光栅化,透视投影除法,视口映射,三角形数据准备
	void PrepareRasterization(Vertex& vertex, Buffer* buffer);


	//简单CVV剔除,只考虑三顶点均不在的情况,未做边界三角形重新构建
	bool SimpleCVVCullCheck(const Vertex& vertex);

};

#include "Renderer.h"
#include "Matrix.h"
#include <iostream>
#include <Windows.h>
using namespace std;
Renderer::Renderer(HDC hdc, int screenWidth, int screenHeight, Camera* cam)
{
	screenHDC = hdc;
	deviceWidth = screenWidth;
	deviceHeight = screenHeight;
	camera = cam;


	tex = new Texture();
	tex->LoadTexture("gezi.bmp");
}


Renderer::~Renderer()
{
}


void Renderer::DrawByIndex(Mesh* m, IShader* shader, DepthBuffer* zbuffer)
{

	for (int i = 0; i < m->indexBuffer.size(); i = i + 3)
	{
		Vertex p1;
		p1.pos = m->positionBuffer[m->indexBuffer[i].x - 1];
		p1.uv = m->uvBuffer[m->indexBuffer[i].y - 1];
		p1.normal = m->normalBuffer[m->indexBuffer[i].z - 1];
		Vertex p2;
		p2.pos = m->positionBuffer[m->indexBuffer[i + 1].x - 1];
		p2.uv = m->uvBuffer[m->indexBuffer[i + 1].y - 1];
		p2.normal = m->normalBuffer[m->indexBuffer[i + 1].z - 1];
		Vertex p3;
		p3.pos = m->positionBuffer[m->indexBuffer[i + 2].x - 1];
		p3.uv = m->uvBuffer[m->indexBuffer[i + 2].y - 1];
		p3.normal = m->normalBuffer[m->indexBuffer[i + 2].z - 1];



		DrawPrimitive(p1, p2, p3, shader, zbuffer);
	
	}
}

void Renderer::DrawByArray(Mesh* m, IShader* shader, DepthBuffer* zbuffer)
{
	for (int i = 0; i < m->vertexBuffer.size(); i = i + 3)
	{
		Vertex p1 = m->vertexBuffer[i];
		Vertex p2 = m->vertexBuffer[i + 1];
		Vertex p3 = m->vertexBuffer[i + 2];

		DrawPrimitive(p1, p2, p3, shader, zbuffer);
	}
}

void Renderer::DrawMesh(Mesh* m, IShader* shader, DepthBuffer* zbuffer)
{
	if (m->indexBuffer.size() > 0)
		DrawByIndex(m, shader, zbuffer);
	else
		DrawByArray(m, shader, zbuffer);
}


void Renderer::DrawPrimitive(Vertex v1, Vertex v2, Vertex v3, IShader* shader, DepthBuffer* zbuffer)
{

	shader->VS(v1, v2, v3);

	//进行CVV简单剔除判断
	// 	if (SimpleCVVCullCheck(v1) && SimpleCVVCullCheck(v2) && SimpleCVVCullCheck(v3))
	// 		return;

	//透视除法,视口映射,数据准备(全部改为1/z)
	PrepareRasterization(v1, zbuffer);
	PrepareRasterization(v2, zbuffer);
	PrepareRasterization(v3, zbuffer);
	//三角形三个点重合明显存在问题,直接不渲染,或者两个
	if (((int)v1.pos.y == (int)v2.pos.y && abs(v2.pos.y - v3.pos.y) <= 1) ||
		((int)v3.pos.y == (int)v2.pos.y && abs(v2.pos.y - v1.pos.y) <= 1) ||
		((int)v1.pos.y == (int)v3.pos.y && abs(v2.pos.y - v3.pos.y) <= 1))
		return;
	
	RasterizeTrangle(v1, v2, v3, shader, zbuffer);
}

void Renderer::RasterizeTrangle(Vertex v0, Vertex v1, Vertex v2, IShader* shader, DepthBuffer* zbuffer)
{
	int ty0 = v0.pos.y;
	int ty1 = v1.pos.y;
	int ty2 = v2.pos.y;
	if (ty0 == ty1)	//上三角形
	{

		DrawTopFlatTrangle(v0, v1, v2, shader, zbuffer, Vertex(), -1);
	}
	else if (ty1 == ty2) //下三角形
	{

		DrawBottomFlatTrangle(v0, v1, v2, shader, zbuffer, Vertex(), -1);

	}
	else//拆分为一个平顶三角形和一个平底三角形
	{
		//中心点为直线(x0, y0),(x2, y2)上取y1的点
		float x3 = (v1.pos.y - v0.pos.y) * (v2.pos.x - v0.pos.x) / (v2.pos.y - v0.pos.y) + v0.pos.x;
		float y3 = v1.pos.y;
		float t = (y3 - v0.pos.y) / (v2.pos.y - v0.pos.y);

		Vertex v3(Vector3f(x3, y3, 0), Color(0, 0, 0, 0), Vector2(0, 0));
		v3.LerpVertexData(v0, v2, t);
		DrawBottomFlatTrangle(v0, v1, v3, shader, zbuffer, v2, 3);
		DrawTopFlatTrangle(v3, v1, v2, shader, zbuffer, v0, 1);
	}
}

void Renderer::DrawTopFlatTrangle(Vertex v0, Vertex v1, Vertex v2, IShader* shader, DepthBuffer* zbuffer, Vertex v3, int swapIndex)
{
	float x0 = v0.pos.x;
	float y0 = v0.pos.y;
	float x1 = v1.pos.x;
	float y1 = v1.pos.y;
	float x2 = v2.pos.x;
	float y2 = v2.pos.y;
	for (float y = y0; y <= y2; y++)
	{
		float t = (y - y0) / (y2 - y0);
		//用int,不然会有断线
		int xl = (y - y0) * (x2 - x0) / (y2 - y0) + x0;
		Vertex vl(Vector3f(xl, y, 0), Color(0, 0, 0, 0), Vector2(0, 0));
		vl.LerpVertexData(v0, v2, t);
		int xr = (y - y1) * (x2 - x1) / (y2 - y1) + x1;
		Vertex vr(Vector3f(xr, y, 0), Color(0, 0, 0, 0), Vector2(0, 0));
		vr.LerpVertexData(v1, v2, t);
		switch (swapIndex)
		{
		case -1:
			DrawLine(vl, vr, shader, zbuffer, v0.pos, v1.pos, v2.pos);
			break;
		case 1:
			DrawLine(vl, vr, shader, zbuffer, v3.pos, v1.pos, v2.pos);
			break;
		case 2:
			DrawLine(vl, vr, shader, zbuffer, v0.pos, v3.pos, v2.pos);
			break;
		case 3:
			DrawLine(vl, vr, shader, zbuffer, v0.pos, v1.pos, v3.pos);
			break;
		default:
			DrawLine(vl, vr, shader, zbuffer, v0.pos, v1.pos, v2.pos);
			break;
		}

	}
}

void Renderer::DrawBottomFlatTrangle(Vertex v0, Vertex v1, Vertex v2, IShader* shader, DepthBuffer* zbuffer, Vertex v3, int swapIndex)
{
	float x0 = v0.pos.x;
	float y0 = v0.pos.y;
	float x1 = v1.pos.x;
	float y1 = v1.pos.y;
	float x2 = v2.pos.x;
	float y2 = v2.pos.y;
	for (float y = y0; y <= y1; y++)
	{
		float t = (y - y0) / (y2 - y0);

		int xl = ((y - y1) * (x0 - x1) / (y0 - y1) + x1);
		Vertex vl(Vector3f(xl, y, 0), Color(0, 0, 0, 0), Vector2(0, 0));
		vl.LerpVertexData(v0, v1, t);
		int xr = ((y - y2) * (x0 - x2) / (y0 - y2) + x2);
		Vertex vr(Vector3f(xr, y, 0), Color(0, 0, 0, 0), Vector2(0, 0));
		vr.LerpVertexData(v0, v2, t);
		switch (swapIndex)
		{
		case -1:
			DrawLine(vl, vr, shader, zbuffer, v0.pos, v1.pos, v2.pos);
			break;
		case 1:
			DrawLine(vl, vr, shader, zbuffer, v3.pos, v1.pos, v2.pos);
			break;
		case 2:
			DrawLine(vl, vr, shader, zbuffer, v0.pos, v3.pos, v2.pos);
			break;
		case 3:
			DrawLine(vl, vr, shader, zbuffer, v0.pos, v1.pos, v3.pos);
			break;
		default:
			DrawLine(vl, vr, shader, zbuffer, v0.pos, v1.pos, v2.pos);
			break;
		}
	}
}


//y值永远相等的线
void Renderer::DrawLine(Vertex v0, Vertex v1, IShader* shader, DepthBuffer* zbuffer, Vector3f p0, Vector3f p1, Vector3f p2)
{

	//std::cout << v0.color.r ;
	float x0 = v0.pos.x;
	float x1 = v1.pos.x;
	float y0 = v0.pos.y;
	float y1 = v1.pos.y;
	//只考虑x方向扫描线即可
	int dx = x1 - x0;

	int stepx = 1;
	

	if (dx < 0)
	{
		stepx = -1;
		dx = -dx;
	}


	int x = x0;
	int y = y0;

	Vertex frag;
	if (x1 == x0)
	{
		if (ZTestAndWrite(x, y, (v0.pos.z + 1) / 2.0, zbuffer))
		{
	
			Vector3f g = centerOfGravity(p0, p1, p2, Vector2(x, y));
			if (shader->FS(v0, g))
			{
				DrawPixel(x, y, v0.color);
			}
		}
		return;
	}
	for (int i = 0; i <= dx; i++)
	{
		float s = (x - x0) / (x1 - x0);
		//透视矫正,https://zhuanlan.zhihu.com/p/144331875
		float t = s * v0.pos.z / (s * v0.pos.z + (1 - s) * v1.pos.z);
		float z = Vertex::LerpFloat(v0.pos.z, v1.pos.z, t);
		z = (z + 1) / 2.0;
		
		if (ZTestAndWrite(x, y, z, zbuffer))
		{
			
			Color c = Color::Lerp(v0.color, v1.color, t);
			float u = Vertex::LerpFloat(v0.uv.x, v1.uv.x, t);
			float v = Vertex::LerpFloat(v0.uv.y, v1.uv.y, t);
			frag.pos = Vector3f(x, y, z);
			frag.color = c;
			frag.uv = Vector2(u, v);
			
			Vector3f g = centerOfGravity(p0, p1, p2, Vector2(x, y));
	
			if (shader->FS(frag, g))
			{
				DrawPixel(x, y, frag.color);
			}

		}

		x += stepx;
	}
}

bool Renderer::ZTestAndWrite(int x, int y, float depth, DepthBuffer* zbuffer)
{

	if (x >= 0 && x < zbuffer->width && y >= 0 && y < zbuffer->height)
	{
		if (zbuffer->depthBuffer[y][x] >= depth)
		{
			zbuffer->depthBuffer[y][x] = depth;
			return true;
		}
	}
	return false;
}

inline void Renderer::DrawPixel(int x, int y, const Color& color)
{
	//cout << color.r << " " << color.g << " " << color.b << " " << endl;
	//color值超过1会自动进行tonemapping
	SetPixel(screenHDC, x, y, RGB(255 * color.r, 255 * color.g, 255 * color.b));
}




void Renderer::Clear(DepthBuffer* zbuffer)
{
	BitBlt(screenHDC, 0, 0, deviceWidth, deviceHeight, NULL, NULL, NULL, BLACKNESS);
	//ClearZ
	for (int i = 0; i < zbuffer->height; i++)
	{
		for (int j = 0; j < zbuffer->width; j++)
		{
			zbuffer->depthBuffer[i][j] = 1;
		}
	}
}




inline void Renderer::PrepareRasterization(Vertex& vertex, Buffer* buffer)
{

	float reciprocalW = 1.0f / vertex.pos.w;
	//最后加0.5是为了后面取证做四舍五入
	vertex.pos.x = (vertex.pos.x * reciprocalW + 1.0f) * 0.5f * (buffer->width - 1) + 0.5;
	vertex.pos.y = (vertex.pos.y * reciprocalW + 1.0f) * 0.5f * (buffer->height - 1) + 0.5;

}

inline bool Renderer::SimpleCVVCullCheck(const Vertex& vertex)
{
	float w = vertex.pos.w;
	if (vertex.pos.x < -w || vertex.pos.x > w)
		return true;
	if (vertex.pos.y < -w || vertex.pos.y > w)
		return true;
	if (vertex.pos.z < 0.0f || vertex.pos.z > w)
		return true;
	return false;
}



一切准备就绪,接下来就可以读取模型文件

ObjFileReader类---读取模型文件,存入Mesh的Buffer中

#pragma once
#include <vector>
#include <string>
#include <fstream>
#include"Mesh.h"
using namespace std;

//切分字符串
void StringSplit(string s, char splitchar,vector<string>& vec);

void ReadObjFile(string path, Mesh* obj);
#include "ObjFileReader.h"
#include<stdlib.h>

//根据splitchar去切分字符串,存到vec里
void StringSplit(string s, char splitchar, vector<string>& vec)
{
	if (vec.size() > 0)//保证vec是空的  
		vec.clear();
	int length = s.length();
	int start = 0;
	for (int i = 0; i < length; i++) {
		if (s[i] == splitchar && i == 0)//第一个就遇到分割符  
		{
			start += 1;
		}
		else if (s[i] == splitchar) {
			//遇到分隔符
			vec.push_back(s.substr(start, i - start));
			start = i + 1;
		}
		else if (i == length - 1)//到达尾部  
		{
			vec.push_back(s.substr(start, i + 1 - start));
		}
	}
}

void ReadObjFile(string path, Mesh* obj)
{
	ifstream in(path);
	string txt = "";

	//能找到该文件
	if (in) {
		while (getline(in, txt)) {
			//读取顶点坐标
			if (txt[0] == 'v' && txt[1] == ' ') {
				vector<string>num;
				txt.erase(0, 2);
				StringSplit(txt, ' ', num);
				Vector3f pos;
				pos = Vector3f((float)atof(num[0].c_str()), (float)atof(num[1].c_str()), (float)atof(num[2].c_str()));
				obj->positionBuffer.push_back(pos);
			}

			//读取顶点法线
			else if (txt[0] == 'v' && txt[1] == 'n') {
				vector<string>num;
				txt.erase(0, 3);
				StringSplit(txt, ' ', num);
				Vector3f n;
				n = Vector3f((float)atof(num[0].c_str()), (float)atof(num[1].c_str()), (float)atof(num[2].c_str()));
				obj->normalBuffer.push_back(n);
			}
			//读取uv坐标
			else if (txt[0] == 'v' && txt[1] == 't')
			{
				vector<string> num;
				txt.erase(0, 3);
				StringSplit(txt, ' ', num);
				Vector2 uv;
				uv=Vector2((float)atof(num[0].c_str()), (float)atof(num[1].c_str()));
				obj->uvBuffer.push_back(uv);

			}
			//读取索引编号,'/'分隔的分别是每个面的顶点 该顶点uv坐标和法线坐标
			else if (txt[0] == 'f' && txt[1] == ' ') {
				vector<string>num;
				txt.erase(0, 2);
				StringSplit(txt, ' ', num);
				for (int i = 0; i < num.size(); i++) {
					vector<string> threeIndex;
					StringSplit(num[i], '/', threeIndex);
					Vector3i indexes = { atoi(threeIndex[0].c_str()), atoi(threeIndex[1].c_str()), atoi(threeIndex[2].c_str()) };
					obj->indexBuffer.push_back(indexes);
				}
			}
		}
	}
	else {
		cout << "no file" << endl;
	}
}

四、主函数及测试效果

 

#include "Renderer.h"
#include "ObjFileReader.h"
#include "Window.h"
#include "Input.h"
#include <iostream>
#include <cmath>
#pragma comment( lib,"winmm.lib" )
using namespace std;

static const int windowWidth = 500;
static const int windowHeight = 500;

Renderer* device = NULL;
Camera* camera = new Camera(Transform(Vector3f(0,0, 100), Vector3f(0, 0, 0), Vector3f(0, 0, 0))); //右边是相机的位置
Mesh* currentMesh = new Mesh();
Mesh* m = new Mesh();
Mesh* plane = new Mesh();
Vector3f moveVector, rotateVector; //根据键盘输入去变换
PhongShader* phongShader;
PhongShader* planeShader;
ShadowShader* depthShader = new ShadowShader();
DepthBuffer* depthBuffer = new DepthBuffer(windowWidth * 2, windowHeight * 2);
DepthBuffer* zBuffer = new DepthBuffer(windowWidth, windowHeight);

Matrix M;
void UpdateInput(Mesh* m)
{

	if (IS_KEY_DOWN('A'))
	{
		moveVector.x -= 0.01f;
	}
	if (IS_KEY_DOWN('D'))
	{
		moveVector.x += 0.01f;
	}
	if (IS_KEY_DOWN('W'))
	{
		moveVector.y += 0.01f;
	}
	if (IS_KEY_DOWN('S'))
	{
		moveVector.y -= 0.01f;
	}
	if (IS_KEY_DOWN('E'))
	{
		moveVector.z -= 0.1f; 
	}
	if (IS_KEY_DOWN('Q'))
	{
		moveVector.z += 0.1f; 
	}
	if (IS_KEY_DOWN('I'))
	{
		rotateVector.y += 0.1f;
	}
	if (IS_KEY_DOWN('K'))
	{
		rotateVector.y -= 0.1f;
	}
	if (IS_KEY_DOWN('L'))
	{
		rotateVector.x += 0.5f;
	}
	if (IS_KEY_DOWN('J'))
	{
		rotateVector.x -= 0.5f;
	}
	if (IS_KEY_DOWN('U'))
	{
		rotateVector.z -= 0.1f;
	}
	if (IS_KEY_DOWN('O'))
	{
		rotateVector.z += 0.1f;
	}

	Matrix s = m->GetTransform().Scale(Vector3f(1, 1, 1));
	Matrix r = m->GetTransform().Rotate(rotateVector);
	Matrix t = m->GetTransform().Translate(moveVector);
	//注意矩阵乘法顺序!!

	M = t * r * s;
	phongShader->v2f.m = M;
	depthShader->v2f.m = M;

}
void Update(Window* w);
void DoRender(Window* w);
void ShowFPS(Window* w);
void CreateCube();
void CreatePlane();

int main()
{

	Window* w = new Window(windowWidth, windowHeight, "Test");
	device = new Renderer(w->screenHDC, windowWidth, windowHeight, camera);
	//规定相机永远往-z方向看,这决定zbuffer初始化为最大值还是最小值(最大值,因为深度值为负数)
	//视口的范围应该是0-负无穷,相反,如果往z轴方向看,视口的范围应该是0-正无穷
	Matrix cameraV = camera->LookAt(camera->transform.position, Vector3f(0, 0, -1), Vector3f(0, 1, 0));
	//这里远近平面的值相对于物体变换到相机坐标系的位置,范围从相机位置-1到-120,此时物体的位置在-100左右,近平面越靠近-100,深度值越趋近于1,,相反越趋近于-1
	//Matrix cameraP = camera->Perspective(0.1, 0.1, -1, -120, 0.1, -0.1);
	//Matrix cameraP = camera->Perspective(90, 1, 1, 10);
	Matrix cameraP = camera->Orthographic(-10, 10, 0, -120, 10, -10);
	Matrix lightP = camera->Orthographic(-10, 10, 0, -120, 10, -10);
	DirectionLight light(Vector3f(0.2, 0.2, -1), Vector3f(0, 0, 100));
	//PointLight poingt(Vector3f(5, 5, -5), 2);
	Texture* gezi = new Texture();
	gezi->LoadTexture("gezi.bmp");
	phongShader = new PhongShader(PhongVert(), PhongFrag(gezi, depthBuffer));
	phongShader->v2f.cameraPos = camera->transform.position;
	phongShader->v2f.dirlights.push_back(light);
	//phongShader->v2f.pointlights.push_back(poingt);
	phongShader->v2f.v = cameraV;
	phongShader->v2f.p = cameraP;
	phongShader->v2f.lightV = light.LookAt(Vector3f(0, 1, 0));
	phongShader->v2f.lightP = lightP;


	depthShader->v2f.lightV = light.LookAt(Vector3f(0, 1, 0));
	depthShader->v2f.lightP = lightP;

	planeShader = new PhongShader(PhongVert(), PhongFrag(gezi, depthBuffer));;
	planeShader->v2f.cameraPos = camera->transform.position;
	planeShader->v2f.dirlights.push_back(light);
	//planeShader->v2f.pointlights.push_back(poingt);
	planeShader->v2f.v = cameraV;
	planeShader->v2f.p = lightP;
	planeShader->v2f.lightV = light.LookAt(Vector3f(0, 1, 0));
	planeShader->v2f.lightP = lightP;

	//ReadObjFile("cube.obj", m);
	CreateCube();
	CreatePlane();


	device->directionlights.push_back(light);
	//device->pointlights.push_back(poingt);
	Update(w);
	system("pause");
	return 0;
}




void Update(Window* w)
{

	MSG msg = { 0 };
	while (msg.message != WM_QUIT)
	{
		UpdateInput(currentMesh);

		if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			DoRender(w);
			ShowFPS(w);
		}
	}
}

void DoRender(Window* w)
{
	device->Clear(depthBuffer);
	device->Clear(zBuffer);

	device->DrawMesh(currentMesh, depthShader, depthBuffer);
	device->DrawMesh(plane, depthShader, depthBuffer);
	device->DrawMesh(currentMesh, phongShader, zBuffer);
	device->DrawMesh(plane, planeShader, zBuffer);

		//双缓冲
	BitBlt(w->hdc, 0, 0, windowWidth, windowHeight, w->screenHDC, 0, 0, SRCCOPY);
}


void ShowFPS(Window* w)
{
	static float  fps = 0;
	static int    frameCount = 0;
	static float  currentTime = 0.0f;
	static float  lastTime = 0.0f;

	frameCount++;
	currentTime = timeGetTime() * 0.001f;

	if (currentTime - lastTime > 1.0f)
	{
		fps = (float)frameCount / (currentTime - lastTime);
		lastTime = currentTime;
		frameCount = 0;
	}

	char strBuffer[20];
	sprintf_s(strBuffer, 20, "%0.3f", fps);
	TextOut(w->hdc, 0, 0, strBuffer, 6);
}

void CreateCube()
{
	currentMesh->AddVertexData(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, Vector3f(0, 0, -1), Color(1, 0, 0, 1));
	currentMesh->AddVertexData(1.0f, -1.0f, -1.0f, 1.0f, 0.0f, Vector3f(0, 0, -1), Color(1, 0, 0, 1));
	currentMesh->AddVertexData(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vector3f(0, 0, -1), Color(1, 0, 0, 1));
	currentMesh->AddVertexData(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vector3f(0, 0, -1), Color(1, 0, 0, 1));
	currentMesh->AddVertexData(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, Vector3f(0, 0, -1), Color(1, 0, 0, 1));
	currentMesh->AddVertexData(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, Vector3f(0, 0, -1), Color(1, 0, 0, 1));
	//前
	currentMesh->AddVertexData(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, Vector3f(0, 0, 1), Color(0, 1, 0, 1));
	currentMesh->AddVertexData(1.0f, -1.0f, 1.0f, 1.0f, 0.0f, Vector3f(0, 0, 1), Color(0, 1, 0, 1));
	currentMesh->AddVertexData(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, Vector3f(0, 0, 1), Color(0, 1, 0, 1));
	currentMesh->AddVertexData(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, Vector3f(0, 0, 1), Color(0, 1, 0, 1));
	currentMesh->AddVertexData(-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, Vector3f(0, 0, 1), Color(0, 1, 0, 1));
	currentMesh->AddVertexData(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, Vector3f(0, 0, 1), Color(0, 1, 0, 1));
	//左
	currentMesh->AddVertexData(-1.0f, 1.0f, 1.0f, 1.0f, 0.0f, Vector3f(-1, 0, 0));
	currentMesh->AddVertexData(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vector3f(-1, 0, 0));
	currentMesh->AddVertexData(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f, Vector3f(-1, 0, 0));
	currentMesh->AddVertexData(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f, Vector3f(-1, 0, 0));
	currentMesh->AddVertexData(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, Vector3f(-1, 0, 0));
	currentMesh->AddVertexData(-1.0f, 1.0f, 1.0f, 1.0f, 0.0f, Vector3f(-1, 0, 0));
	//右
	currentMesh->AddVertexData(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, Vector3f(1, 0, 0), Color(0, 0, 1, 1));
	currentMesh->AddVertexData(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vector3f(1, 0, 0), Color(0, 0, 1, 1));
	currentMesh->AddVertexData(1.0f, -1.0f, -1.0f, 0.0f, 1.0f, Vector3f(1, 0, 0), Color(0, 0, 1, 1));
	currentMesh->AddVertexData(1.0f, -1.0f, -1.0f, 0.0f, 1.0f, Vector3f(1, 0, 0), Color(0, 0, 1, 1));
	currentMesh->AddVertexData(1.0f, -1.0f, 1.0f, 0.0f, 0.0f, Vector3f(1, 0, 0), Color(0, 0, 1, 1));
	currentMesh->AddVertexData(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, Vector3f(1, 0, 0), Color(0, 0, 1, 1));
	//下
	currentMesh->AddVertexData(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f, Vector3f(0, -1, 0), Color(1, 1, 0, 1));
	currentMesh->AddVertexData(1.0f, -1.0f, -1.0f, 1.0f, 1.0f, Vector3f(0, -1, 0), Color(1, 1, 0, 1));
	currentMesh->AddVertexData(1.0f, -1.0f, 1.0f, 1.0f, 0.0f, Vector3f(0, -1, 0), Color(1, 1, 0, 1));
	currentMesh->AddVertexData(1.0f, -1.0f, 1.0f, 1.0f, 0.0f, Vector3f(0, -1, 0), Color(1, 1, 0, 1));
	currentMesh->AddVertexData(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, Vector3f(0, -1, 0), Color(1, 1, 0, 1));
	currentMesh->AddVertexData(-1.0f, -1.0f, -1.0f, 0.0f, 1.0f, Vector3f(0, -1, 0), Color(1, 1, 0, 1));
	//上
	currentMesh->AddVertexData(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, Vector3f(0, 1, 0));
	currentMesh->AddVertexData(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vector3f(0, 1, 0));
	currentMesh->AddVertexData(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, Vector3f(0, 1, 0));
	currentMesh->AddVertexData(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, Vector3f(0, 1, 0));
	currentMesh->AddVertexData(-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, Vector3f(0, 1, 0));
	currentMesh->AddVertexData(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, Vector3f(0, 1, 0));
}


void CreatePlane()
{
	plane->AddVertexData(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, Vector3f(0, 0, 1), Color(1, 1, 1, 1));
	plane->AddVertexData(1.0f, -1.0f, -1.0f, 1.0f, 0.0f, Vector3f(0, 0, 1), Color(1, 1, 1, 1));
	plane->AddVertexData(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vector3f(0, 0, 1), Color(1, 1, 1, 1));
	plane->AddVertexData(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, Vector3f(0, 0, 1), Color(1, 1, 1, 1));
	plane->AddVertexData(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, Vector3f(0, 0, 1), Color(1, 1, 1, 1));
	plane->AddVertexData(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, Vector3f(0, 0, 1), Color(1, 1, 1, 1));

	Matrix M;
	Matrix s = m->GetTransform().Scale(Vector3f(5, 5, 5));
	Matrix r = m->GetTransform().Rotate(Vector3f(0, 0, 0));
	Matrix t = m->GetTransform().Translate(Vector3f(0, 0, -5));
	//注意矩阵乘法顺序!!
	M = t * r * s;
	planeShader->v2f.m = M;
	plane->SetObjectToWorld(M);
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值