学习光线追踪(11)---纹理加载

0.简介

之前显示的图形中都是单一颜色的,这次我将纹理加上去,这样就可以显示更加丰富的元素了。

1.纹理

添加纹理功能需要对源程序多个地方修改,因为有了纹理就会增加纹理坐标的处理,所以在定义多边形的时候,就要在在原来顶点的基础上添加纹理坐标。然后根据光打在多边形上的位置,计算纹理坐标。

2.纹理坐标定位

为了能刚好的兼容各种i情况的纹理坐标,采用面积法来定位纹理坐标。

纹理坐标示意图

 

上图三角形就是纹理,P是纹理坐标中待计算的坐标,算法中利用A,B,C的坐标来表示P,所以就要计算A,B,C点对P点的作用分量,例如,三角形PAB,PCB,PCA,分别代表着三个顶点对P的作用大小,对应的面积越大,对P的位置影响就越大,利用这一原理,就能将P用A,B,C三个点组合起来表示,为什么不用向量来表示P呢?因为向量带有方向,而P被A,B,C组合是标量计算,所以带有方向计算就不是很方便。

至于计算面积,就用海伦公式,已知三角形三个变成计算面积的公式。设总面积是Area,那么A对于P的作用分量就是SPCB/Area,其中SPBC代表三角形PBC面积,以此类推计算出三个点的作用大小。

3.修改的代码

首先,三角形中输入的不再是三个点了,而是带了纹理坐标。因为总面积一直 不变,所以就计算一次。

Triangle(vec5 _A, vec5 _B, vec5 _C, Material * _m) :A(_A), B(_B), C(_C) 
	{
		m = _m; 
		normal = normalize(cross(A.position-B.position, B.position-C.position));
		lA = length(B.position-C.position);
		lB = length(A.position-C.position);
		lC = length(A.position-B.position);
		float P = (lA + lB + lC) / 2;
		area = sqrt(P*(P-lA)*(P-lB)*(P-lC));
	}

设置了vec5类型来做到适用当前情况。

struct vec5
{
	//物体坐标
	vec3 position;
	//纹理UV
	vec2 textureUV;
	vec5() {};
	vec5(vec3 _pos) :position(_pos) { textureUV = vec2(0, 0); }
	vec5(vec3 _pos, vec2 uv) :position(_pos), textureUV(uv) {}
	vec5(float x, float y, float z)
	{
		position.x = x;
		position.y = y;
		position.z = z;
		textureUV.x = 0;
		textureUV.y = 0;
	}
};

对于原来的材质类已经不够用了,所以在基础上拓展了新的材质类。

class HighMaterial : public Material
{
	Mat texture;
public:
	void setTexture(Mat _mat) { texture = _mat; }
	HighMaterial();
	vec3 getColor(vec2 uv);
	HighMaterial(float _light, float _specular, float _diffuse, float _refract, float _transparent, vec3 _color) 
	{
		light = _light;
		specular = _specular;
		transparent = _transparent;
		diffuse = _diffuse;
		refract = _refract;
		color = _color;
	}
	~HighMaterial();
};

高级材质类中可以实现纹理映射,其中getColor就是根据计算出来的纹理坐标来返回对应点的颜色。

vec3 HighMaterial::getColor(vec2 uv)
{
	if (texture.cols <= 0)
		return color;
	int j = abs((int(uv.x * texture.cols)) % texture.cols);
	int i = abs((int(uv.y * texture.rows)) % texture.rows);
	vec3 tcolor;
	tcolor.z = texture.at<Vec3b>(i, j)[0];
	tcolor.y = texture.at<Vec3b>(i, j)[1];
	tcolor.x = texture.at<Vec3b>(i, j)[2];
	return tcolor;
}

在物体颜色计算含税中,也适应了当前修改。

Ray Polygon::sample(Ray out, Ray reflect, Ray refract)
{
	Ray res(out.direction, out.position, 0, vec3(0, 0, 0), out.polygon);
	//out光线带的是对应物体的法向量值
	float cosa = abs(dot(out.normal,-out.direction));//光线入射角和面法向量的cos值
	//发光计算
	res.color = m->getColor(out.end.textureUV) * m->light * std::fmaxf(cosa,0);
	//反射颜色计算
	if(reflect.polygon)
		res.color += reflect.color * m->specular;
	return res;
}

这样一来,既可以适用原来的材质类,也可以适用现在的高级材质,原来多边形类中的材质对象编程指针,这样一来就可以实现多态了。

class Polygon
{
public:
	//位置
	vec3 position;
	//世界坐标矩阵
	mat3 transforms;
	//材质
	Material * m;
	virtual Ray intersect(Ray ray) { return Ray(vec3(0, 0, 0), vec3(0, 0, 0), 0, vec3(0, 0, 0), nullptr); }
	virtual Ray sample(Ray out, Ray reflect, Ray refract); 
	virtual vec3 getNormal(vec3 _vector) { return vec3(0, 0, 0); }
	Polygon();
	~Polygon();
};

最后,本次主要添加的代码就是纹理坐标计算函数,实现在了三角形类中。

vec2 Triangle::getUVCoord(vec5 A, vec5 B, vec5 C, vec5 T)
{
	//计算每个三角形需要的边长
	float la, lb, lc;
	la = length(T.position - wA.position);
	lb = length(T.position - wB.position);
	lc = length(T.position - wC.position);
	float pa = (lA + lb + lc) / 2;
	float pb = (lB + la + lc) / 2;
	//计算三个三角形的面积
	float area_a = sqrt(pa * (pa - lA) * (pa - lb) * (pa - lc));
	float area_b = sqrt(pb * (pb - lB) * (pb - la) * (pb - lc));
	float area_c = area - area_a - area_b;
	return (area_a * A.textureUV + area_b * B.textureUV + area_c * C.textureUV) / area;
}

还好之前设计的时候耦合性没那么大,不然得改不少东西。

4.显示效果

我加载了一个木箱子的纹理。

纹理图像

然后显示出来如下。

显示效果

5.源码

release0.06

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值