学习光线追踪(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;//纹理UVvec2 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(i, j)[0];tcolor.y = texture.at(i, j)[1];tcolor.x = texture.at(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


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部