当前位置:网站首页>Games101 job 7 improvement - implementation process of micro surface material
Games101 job 7 improvement - implementation process of micro surface material
2022-06-27 03:27:00 【flashinggg】
Catalog
Supplementary calculation coloring function -eval()
Supplementary calculation formula -private:
Add the remaining properties of the material -pdf&sample
Material properties & Add object
Improve some operation requirements :

Before reading it, I can read it together with another blog :GAMES101 Homework 7 Improve - What you need to know to implement the microsurface model
What are we going to do ? The main operation is in Material.hpp Completed in .
Add Material.hpp
Supplementary calculation coloring function -eval()
Improve the microsurface model to be implemented , In fact, with DIFFUSE equally , It is also a kind of material , It needs a series of calculations to get BRDF Value , I.e. path Scene.cpp -> castRay() In function code , In the calculation formula of direct illumination and indirect illumination f_r Value :
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;The assignments are respectively :
//dir
Vector3f f_r = inter.m->eval(wo, -ws, N);
//indir
Vector3f f_r = obj_to_scene.m->eval(wo, wi, N);Then our eyes are fixed on eval() This function , This function is Material.hpp in class Material Defined , Used to calculate the color value returned by the material .
class Material{
public:
...
// Calculate the contribution of light
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:
{
// Calculation DIFFUSE contribution -> kd
float cosalpha = dotProduct(N, wo);// Just look at the hemisphere , The other half doesn't look , So you have to judge wo and N The angle between
if (cosalpha > 0.0f) {
Vector3f diffuse = Kd / M_PI;
return diffuse;
}
else
return Vector3f(0.0f);
break;
}
}
}Then first eval() Well defined in the book MICROFACET This material , The comments have been as detailed as possible :
Vector3f Material::eval(const Vector3f &wi, const Vector3f &wo, const Vector3f &N){
switch(m_type){
case DIFFUSE:
{
...
}
case MICROFACET:
{
float cosalpha = dotProduct(N, wo);// Just look at the hemisphere , The other half doesn't look , So you have to judge wo and N The angle between
if (cosalpha > 0.0f) {
// Calculation of parameters
// Be careful :wi Here is the direction of the incident light , So the calculation needs to become -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);
// Calculate the normal density function D
float D = DistributionGGX(NdotH, roughness);
// Calculate the shadow occlusion function G
//Disney Way
float G = GeometrySmith_Disney(N, wo, -wi, roughness);
//UE4 way
//float G = GeometrySmith_UE4(N, wo, -wi, roughness);
// Fresnel term F
float ior = 1.5;
float F;
fresnel(wi, N, ior, F);
// Calculate the specular reflection BRDF
float m = 4 * std::max(NdotL * NdotL, 0.00001f);
float Specular = D * G * F / m;
// Calculate the proportion of reflected and refracted light
// Reflection ks
float ks = F;
float kd = 1 - F;
// Diffuse BRDF
float rou = 1.0f;// Define diffuse material reflectivity , Size in (0,1), Direct to 1
float Diffuse = rou / M_PI;
// It is worth noting that , there Kd and Ks Is the corresponding color , and Specular I have already taken F 了 ( The proportion of reflected light has been considered ), There is no need to multiply by ks 了
return Kd * Diffuse * kd + Ks * Specular;
}
else
return Vector3f(0.0f);
break;
}
}
}Supplementary calculation formula -private:
And the code used above fresnel() The same function , We also need to define calculations G、D The value of the function , These functions follow fresnel() equally , It's all in Material Class private The definition of , stay private Just add it to the .
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);
}
// Define shadow occlusion function G
//Disney way:
// Yes G1 The implementation of the
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));
}
// The light source direction and observation direction are calculated respectively ggx1 and ggx2, Multiply to get 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;
}
// The light source direction and observation direction are calculated respectively ggx1 and ggx2, Multiply to get 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;
}Add the remaining properties of the material -pdf&sample
Just paste the code here , Totally copyDIFFUSE The material .
Vector3f Material::sample(const Vector3f &wi, const Vector3f &N){
switch(m_type){
case DIFFUSE:
{
// Sample the hemisphere evenly
// hemisphere z Axis value z∈[0,1]
// r -> Radius with normal as rotation axis ,x²+y²+z²=1,r²=x²+y²
//phi∈[0,2Π], Rotation Angle
float x_1 = get_random_float(), x_2 = get_random_float();// Random [0,1] Value
float z = std::fabs(1.0f - 2.0f * x_1);// I don't quite understand why I don't take it directly [0,1] random number
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);// The direction of random light on the hemispherical surface
// Then you need to convert the local light coordinates on the hemisphere into world coordinates
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;
}
}
}
// Calculate the probability density function pdf
float Material::pdf(const Vector3f &wi, const Vector3f &wo, const Vector3f &N){
switch(m_type){
case DIFFUSE:// texture of material
{
// Uniform sampling , be pdf Constant 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;
}
}
}Come here Material.hpp It's over , Don't forget to add... At the beginning MICROFACET Material type of .
enum MaterialType { DIFFUSE,MICROFACET};main.cpp
Material properties & Add object
Here we define the properties of the micro surface material , And put a small ball into the scene , Be careful , there Kd and Ks Respectively corresponding to the color .
...
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);...
// Start triangulating
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);
// Add objects to the scene :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_);Optimization part
It's not over here ! If you run directly at this time, there will be an error :

So you need to assign a value to this function , Although we don't need him .
Sphere::evalDiffuseColor()
Just give him a null value .
Vector3f evalDiffuseColor(const Vector2f &st)const {
//return m->getColor();
return {};
}The model has black spots
At this time, it can work normally , But there will be such problems , There will be many black spots on the surface of the ball :(spp=4)

I also found a solution to this problem through Internet search , In fact, this is because there is too much error when the light and the ball judge the intersection , Cause black spots . See this article for details :
Games101, Homework 7( Micro surface model )_Elsa My brother's blog
The solution is ,Sphere::getIntersection() What's in the function t0 A judgment accuracy 0.5, This precision is also obtained by the author of this article through the comparison of different values :
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;
// Given precision 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;
}The result of optimization :(spp=4)

result :spp=256, when 25min

边栏推荐
- 2021:Check it again:Progressive Visual Question Answering via Visual Entailment通过视觉暗示进行渐进式视觉问答
- Resnet152 pepper pest image recognition 1.0
- 【一起上水硕系列】Day 6
- Yiwen teaches you Kali information collection
- Learn Tai Chi Maker - mqtt Chapter 2 (3) reserved messages
- 语义化版本 2.0.0
- 2021:Greedy Gradient Ensemble for Robust Visual Question Answering
- lodash get js代码实现
- Easy to use plug-ins in idea
- Topolvm: kubernetes local persistence scheme based on LVM, capacity aware, dynamically create PV, and easily use local disk
猜你喜欢

Learning Tai Chi Maker - mqtt Chapter 2 (II) esp8266 QoS application

Uni app's uparse rich text parsing perfectly parses rich text!

Solve the problem of error reporting in cherry pick submission

Agile development - self use

2019LXMERT:Learning Cross-Modality Encoder Representations from Transformers

Products change the world

PAT甲级 1020 Tree Traversals

2021:Beyond Question-Based Biases:Assessing Multimodal Shortcut Learning in Visual Question Answeri

记录unity 自带读取excel的方法和遇到的一些坑的解决办法

Web development framework - Express (installation and use, static hosting, routing processing, use of Middleware)
随机推荐
2020:MUTANT: A Training Paradigm for Out-of-Distribution Generalizationin Visual Question Answering
lodash get js代码实现
jmeter分布式压测
IDEA中好用的插件
学习太极创客 — MQTT(八)ESP8266订阅MQTT主题
Learning Tai Chi Maker - mqtt Chapter 2 (II) esp8266 QoS application
手撸promise【二、Promise源码】【代码详细注释/测试案例完整】
【数组】剑指 Offer II 012. 左右两边子数组的和相等 | 剑指 Offer II 013. 二维子矩阵的和
Servlet and JSP final review examination site sorting 42 questions and 42 answers
剑指Offer || :栈与队列(简单)
TopoLVM: 基于LVM的Kubernetes本地持久化方案,容量感知,动态创建PV,轻松使用本地磁盘
2021:Zero-shot Visual Question Answering using Knowledge Graphs使用知识图的零次视觉问答
How can e-commerce products be promoted and advertised on Zhihu?
Cs5213 HDMI to VGA (with audio) single turn scheme, cs5213 HDMI to VGA (with audio) IC
我是怎样简化开源系统中的接口的开发的?
Pat grade a 1023 have fun with numbers
PAT甲级 1024 Palindromic Number
Semantic version 2.0.0
学习太极创客 — MQTT 第二章(二)ESP8266 QoS 应用
Questions and answers of chlor alkali electrolysis process in 2022