学习光线追踪(14)---法线纹理

0.简介

如果想让上一次的墙面更加真实一些,就需要法线纹理来修饰一下了。

1.法线纹理

我这里简单介绍一下法线纹理,模型表变的法向量一般都比较单一,例如上一篇博客里的墙面,法向量都是朝向一面的,这就带来一个问题,墙面就很假,很光滑,跟瓷砖一样的感觉,但是实际的墙面并不是,而其根本原因就是表面的法向量导致光的反射方向一样,所以才像瓷砖一样反光,如果表面的法向量是接近于真实的,效果就会好很多,那么可以换一个更加真实的模型,模型中细节多了,自然就好了,但是模型中细节越多顶点就越多,计算量就越大,如果在模型表面加上类似纹理一样的法向量,这样,就可以避免用复杂的模型了,当然想法很好,那么就来实践一下。

具体讲解请见如下文章

https://www.jianshu.com/p/eea4d8582499

2.实现

我建议是要看看上面给出的文章链接,讲的很好,重复的东西我就不在花时间叙述了。

mat3 Triangle::getTBN(vec5 _A, vec5 _B, vec5 _C)
{
	//计算出三角形面的姿态矩阵
	vec2 u = _B.textureUV - _A.textureUV;
	vec2 v = _C.textureUV - _B.textureUV;
	vec3 AB = wB.position - wA.position;
	vec3 BC = wC.position - wB.position;
	mat2 uv = mat2(u, v);
	vec3 Eu1 = v.y * AB;
	vec3 Eu2 = -v.x * BC;
	float delta = 1.0 / (u.x * v.y - u.y * v.x);
	vec3 E1 = normalize(vec3(Eu1.x + Eu2.x, Eu1.y + Eu2.y, Eu1.z + Eu2.z))* delta;
	Eu1 = -u.y * AB;
	Eu2 = u.x * BC;
	vec3 E2 = normalize(vec3(Eu1.x + Eu2.x, Eu1.y + Eu2.y, Eu1.z + Eu2.z))* delta;
	
	vec3 N = cross(E1, E2);
	E2 = cross(E1,N);
	return (mat3(normalize(E1),normalize(E2),normalize(N)));//返回左乘变换矩阵
}

三角形类中添加的TBN矩阵计算功能。

Ray Triangle::intersect(Ray ray)
{
	Ray result(ray.direction, ray.position, ray.intensity, ray.color, nullptr);
	if ((result = Plane::intersect(ray)).polygon == nullptr)
		return Ray(ray.direction, ray.position, ray.intensity, vec3(0, 0, 0), nullptr);
	//这里说明点在三角面是上
	if (onTriangle0(wA.position, wB.position, wC.position, result.end.position))
	{
		//计算点所在的纹理坐标
		vec5 p_end;
		result.end.textureUV = getUVCoord(A, B, C, result.end);
		//如果纹理是带有法向量纹理
		if(m->hasNormalTexture)
			result.normal = getTBN(A,B,C) * m->getNormal(result.end.textureUV);
		return result;
	}
	return Ray(ray.direction, ray.position, ray.intensity, vec3(0, 0, 0), nullptr);
}

在光线碰撞计算的时候,加入了法向量获取,从法线纹理中获取。

3.效果

法线纹理效果

放大看看

局部放大

看起来效果还可以吧,虽然真实的墙面不会这样油汪汪的,但是法线纹理的感觉是出来了。后面的墙面块数目比较多,所以计算起来时间比较长,后面需要想办法加速一下了。

4.源码

release0.09

发布了64 篇原创文章 · 获赞 16 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/ARTELE/article/details/103970334