当前位置:网站首页>GAMES101作业7提高-微表面材质的实现过程
GAMES101作业7提高-微表面材质的实现过程
2022-06-27 03:12:00 【flashinggg】
目录
提高部分作业要求:

看之前可以结合我的另一篇博客一起看:GAMES101作业7提高-实现微表面模型你需要了解的知识
我们要做什么?主要操作是在Material.hpp里完成的。
补充Material.hpp
补充计算着色函数-eval()
提高部分要实现的微表面模型,其实跟DIFFUSE一样,也是一种材质,需要通过一系列计算得到BRDF的值,即路径Scene.cpp -> castRay()函数代码中,直接光照和间接光照计算公式中f_r的值:
dir = L_i * f_r * cos_theta * cos_theta_l / dis2 / pdf_light;indir = castRay(r, depth + 1) * f_r * cos_theta / pdf_hemi / RussianRoulette;赋值分别是:
//dir
Vector3f f_r = inter.m->eval(wo, -ws, N);
//indir
Vector3f f_r = obj_to_scene.m->eval(wo, wi, N);那我们的目光就锁定在eval()这个函数,这个函数是Material.hpp中class Material定义的,用以计算材质返回颜色值。
class Material{
public:
...
//计算光线的贡献
inline Vector3f eval(const Vector3f &wi, const Vector3f &wo, const Vector3f &N);
...
}Vector3f Material::eval(const Vector3f &wi, const Vector3f &wo, const Vector3f &N){
switch(m_type){
case DIFFUSE:
{
//计算DIFFUSE贡献 -> kd
float cosalpha = dotProduct(N, wo);//只看半球,另一半不看,所以要判断一下wo和N的夹角
if (cosalpha > 0.0f) {
Vector3f diffuse = Kd / M_PI;
return diffuse;
}
else
return Vector3f(0.0f);
break;
}
}
}那就先在eval()里定义好MICROFACET这个材质,已经尽量很详细的注释了:
Vector3f Material::eval(const Vector3f &wi, const Vector3f &wo, const Vector3f &N){
switch(m_type){
case DIFFUSE:
{
...
}
case MICROFACET:
{
float cosalpha = dotProduct(N, wo);//只看半球,另一半不看,所以要判断一下wo和N的夹角
if (cosalpha > 0.0f) {
//参数的计算
//注意:wi这里是入射光线的方向,因此计算需要变成-wi
float roughness = 0.8;
Vector3f H = (-wi + wo).normalized();
float NdotH = std::max(dotProduct(N, H), 0.0f);
float NdotV = std::max(dotProduct(N, wo), 0.0f);
float NdotL = std::max(dotProduct(N, -wi), 0.0f);
//计算法线密度函数 D
float D = DistributionGGX(NdotH, roughness);
//计算阴影遮挡函数 G
//Disney Way
float G = GeometrySmith_Disney(N, wo, -wi, roughness);
//UE4 way
//float G = GeometrySmith_UE4(N, wo, -wi, roughness);
//菲涅尔项 F
float ior = 1.5;
float F;
fresnel(wi, N, ior, F);
//计算镜面反射的BRDF
float m = 4 * std::max(NdotL * NdotL, 0.00001f);
float Specular = D * G * F / m;
//计算反射和折射光占比
//反射ks
float ks = F;
float kd = 1 - F;
//漫反射的BRDF
float rou = 1.0f;//定义漫反射材质反射率,大小在(0,1),直接给1
float Diffuse = rou / M_PI;
//值得注意的是,这里的Kd和Ks才是对应的颜色,而Specular已经乘过F了(已经考虑了反射光的占比),这里就不用再乘以ks了
return Kd * Diffuse * kd + Ks * Specular;
}
else
return Vector3f(0.0f);
break;
}
}
}补充计算公式-private:
与上述代码使用到的fresnel()函数相同,我们还需要定义计算G、D值的函数,这些函数跟fresnel()一样,都是在Material类的private里定义的,在private里添加就行。
private:
...
float DistributionGGX(float NdotH, float roughness) {
float a = roughness * roughness;
float a2 = a * a;
float m = NdotH * NdotH * (a2 - 1) + 1;
return a2 / std::max(M_PI * m * m, 0.000001f);
}
//定义阴影遮挡函数G
//Disney way:
//对G1的实现
float SmithG_GGX(float NdotV, float roughness) {
float r = 0.5 + roughness / 2.0f;
float m = r * r + (1 - r * r) * NdotV * NdotV;
return 2.0f * NdotV / (NdotV + std::sqrt(m));
}
//光源方向和观察方向分别计算ggx1和ggx2,相乘得到G
float GeometrySmith_Disney(Vector3f N, Vector3f V, Vector3f L, float roughness) {
float NdotV = std::max(dotProduct(N, V), 0.0f);
float NdotL = std::max(dotProduct(N, L), 0.0f);
float ggx1 = SmithG_GGX(NdotL, roughness);
float ggx2 = SmithG_GGX(NdotV, roughness);
return ggx1 * ggx2;
}
//UE4 way
//G1
float GeometrySchlickGGX(float NdotV, float roughness) {
float r = roughness + 1;
float k = r * r / 8;
float m = NdotV / NdotV * (1.f - k) + k;
return NdotV / m;
}
//光源方向和观察方向分别计算ggx1和ggx2,相乘得到G
float GeometrySmith_UE4(Vector3f N, Vector3f V, Vector3f L, float roughness) {
float NdotV = std::max(dotProduct(N, V), 0.0f);
float NdotL = std::max(dotProduct(N, L), 0.0f);
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
return ggx1 * ggx2;
}补充材质剩下的属性-pdf&sample
这里直接贴代码就行,完全是copyDIFFUSE材质的。
Vector3f Material::sample(const Vector3f &wi, const Vector3f &N){
switch(m_type){
case DIFFUSE:
{
// 均匀地对半球采样
//半球z轴值z∈[0,1]
// r -> 以法线为旋转轴的半径,x²+y²+z²=1,r²=x²+y²
//phi∈[0,2Π],旋转角度
float x_1 = get_random_float(), x_2 = get_random_float();//随机[0,1]取值
float z = std::fabs(1.0f - 2.0f * x_1);//不是很理解为什么不直接取[0,1]随机数
float r = std::sqrt(1.0f - z * z), phi = 2 * M_PI * x_2;
Vector3f localRay(r*std::cos(phi), r*std::sin(phi), z);//半球面上随机光线的方向
//接着需要把半球上的局部光线坐标转换成世界坐标
return toWorld(localRay, N);
break;
}
case MICROFACET:
{
float x_1 = get_random_float(), x_2 = get_random_float();
float z = std::fabs(1.0f - 2.0f * x_1);
float r = std::sqrt(1.0f - z * z), phi = 2 * M_PI * x_2;
Vector3f localRay(r * std::cos(phi), r * std::sin(phi), z);
return toWorld(localRay, N);
break;
}
}
}
//计算概率密度函数pdf
float Material::pdf(const Vector3f &wi, const Vector3f &wo, const Vector3f &N){
switch(m_type){
case DIFFUSE://材质
{
//均匀采样,则pdf为常数1/2Π
if (dotProduct(wo, N) > 0.0f)
return 0.5f / M_PI;
else
return 0.0f;
break;
}
case MICROFACET:
{
if (dotProduct(wo, N) > 0.0f)
return 0.5f / M_PI;
else
return 0.0f;
break;
}
}
}到这里Material.hpp就结束了,别忘了在开头加上MICROFACET的材质类型。
enum MaterialType { DIFFUSE,MICROFACET};main.cpp
材质属性&加入物体
这里定义了微表面材质的属性,并向场景里放入了小球,注意,这里的Kd和Ks分别对应颜色。
...
Material*Microfacet = new Material(MICROFACET,Vector3f(0.0f));
Microfacet->Kd = Vector3f(0.5, 0.5, 0.5);
Microfacet->Ks = Vector3f(0.5, 0.5, 0.5);
Sphere sphere(Vector3f(120, 100, 300), 100, Microfacet);...
//开始划分三角形网格
MeshTriangle floor("../models/cornellbox/floor.obj", white);
//MeshTriangle shortbox("../models/cornellbox/shortbox.obj", white);
//MeshTriangle tallbox("../models/cornellbox/tallbox.obj", white);
MeshTriangle left("../models/cornellbox/left.obj", red);
MeshTriangle right("../models/cornellbox/right.obj", green);
MeshTriangle light_("../models/cornellbox/light.obj", light);
//把物体加入场景中:objects.push_back(object);
scene.Add(&floor);
scene.Add(&sphere);
//scene.Add(&shortbox);
//scene.Add(&tallbox);
scene.Add(&left);
scene.Add(&right);
scene.Add(&light_);优化部分
到这里并没有完全结束!如果这个时候你直接运行会出现错误:

因此需要给这个函数赋予值,尽管我们用不上他。
Sphere::evalDiffuseColor()
给他一个空值就行。
Vector3f evalDiffuseColor(const Vector2f &st)const {
//return m->getColor();
return {};
}模型有黑点
这时能正常运行了,但是会出现这样的问题,球的表面会有很多黑点:(spp=4)

这个问题我也是上网搜索到了解决办法,这其实是由于光线和球判断交点的时候误差太大,导致有黑点。具体可以看看这篇文章:
Games101,作业7(微表面模型)_Elsa的迷弟的博客
解决办法是,Sphere::getIntersection()函数里给t0一个判断精度0.5,这个精度也是这篇文章的作者通过不同值的比较得到的:
Intersection getIntersection(Ray ray){
Intersection result;
result.happened = false;
Vector3f L = ray.origin - center;
float a = dotProduct(ray.direction, ray.direction);
float b = 2 * dotProduct(ray.direction, L);
float c = dotProduct(L, L) - radius2;
float t0, t1;
if (!solveQuadratic(a, b, c, t0, t1)) return result;
if (t0 < 0) t0 = t1;
if (t0 < 0) return result;
//给了精度0.5
if (t0 > 0.5) {
result.happened = true;
result.coords = Vector3f(ray.origin + ray.direction * t0);
result.normal = normalize(Vector3f(result.coords - center));
result.m = this->m;
result.obj = this;
result.distance = t0;
}
return result;
}优化后的结果:(spp=4)

结果:spp=256,用时25min

边栏推荐
- Dameng database installation
- 2022 operation of simulated examination platform for tea artist (Senior) work license question bank
- Memcached basics 11
- Getting started with Scala_ Immutable list and variable list
- 学习太极创客 — MQTT 第二章(二)ESP8266 QoS 应用
- Flink學習2:應用場景
- 正则表达式:语法
- Docker deploy redis cluster
- Oracle/PLSQL: Ltrim Function
- Human soberness: bottom logic and top cognition
猜你喜欢

Dameng database installation

Cs5213 HDMI to VGA (with audio) single turn scheme, cs5213 HDMI to VGA (with audio) IC

Learn Tai Chi Maker - mqtt (VI) esp8266 releases mqtt message

How does source insight (SI) display the full path? (do not display omitted paths) (turn off trim long path names with ellipses)

Learn from Taiji Maker - mqtt Chapter 2 (I) QoS service quality level

PAT甲级 1026 Table Tennis
![[micro service sentinel] degradation rules slow call proportion abnormal proportion abnormal constant](/img/4d/4d4424b609a3c0cd36c5c79daa8861.png)
[micro service sentinel] degradation rules slow call proportion abnormal proportion abnormal constant

Implementation of window encryption shell

企业数字化转型:信息化与数字化

resnet152 辣椒病虫害图像识别1.0
随机推荐
Overview of Tsinghua & Huawei | semantic communication: Principles and challenges
学习太极创客 — MQTT(八)ESP8266订阅MQTT主题
Flink学习5:工作原理
TP5 Spreadsheet Excle 表格导出
Servlet and JSP final review examination site sorting 42 questions and 42 answers
事业观、金钱观与幸福观
解决cherry pick提交报错问题
jmeter分布式压测
Introduction to stm32
[micro service sentinel] degradation rules slow call proportion abnormal proportion abnormal constant
Career outlook, money outlook and happiness outlook
ESP8266
PAT甲级 1018 Public Bike Management
Learning Tai Chi Maker - mqtt (VII) advanced mqtt theme
Uninstallation of Dameng database
Cs5213 HDMI to VGA (with audio) single turn scheme, cs5213 HDMI to VGA (with audio) IC
PAT甲级 1019 General Palindromic Number
H5 liquid animation JS special effect code
学习太极创客 — MQTT(六)ESP8266 发布 MQTT 消息
Super detailed, 20000 word detailed explanation, thoroughly understand es!