TerraForge3D  2.3.1
3D Terrain And Landscape Generator
PBRMaterialNode.cpp
1#include "Shading/ShaderNodes/PBRMaterialNode.h"
2
3#include <iostream>
4
5static void LoadPBRFunctions(GLSLHandler *handler)
6{
7 GLSLFunction DistributionGGX("DistributionGGX", "vec3 N, vec3 H, float roughness", "float");
8 DistributionGGX.AddLine(GLSLLine("float a = roughness * roughness;"));
9 DistributionGGX.AddLine(GLSLLine("float a2 = a * a;"));
10 DistributionGGX.AddLine(GLSLLine("float NdotH = max(dot(N, H), 0.0f);"));
11 DistributionGGX.AddLine(GLSLLine("float NdotH2 = NdotH * NdotH;"));
12 DistributionGGX.AddLine(GLSLLine("float denom = NdotH2 * (a2 - 1.0) + 1.0;"));
13 DistributionGGX.AddLine(GLSLLine("return a2 / (PI * denom * denom);"));
14 handler->AddFunction(DistributionGGX);
15 GLSLFunction GeometrySchlickGGX("GeometrySchlickGGX", "float NdotV, float roughness", "float");
16 GeometrySchlickGGX.AddLine(GLSLLine("float r = (roughness + 1.0);"));
17 GeometrySchlickGGX.AddLine(GLSLLine("float k = (r*r) / 8.0;"));
18 GeometrySchlickGGX.AddLine(GLSLLine(""));
19 GeometrySchlickGGX.AddLine(GLSLLine("float nom = NdotV;"));
20 GeometrySchlickGGX.AddLine(GLSLLine("float denom = NdotV * (1.0 - k) + k;"));
21 GeometrySchlickGGX.AddLine(GLSLLine(""));
22 GeometrySchlickGGX.AddLine(GLSLLine("return nom / denom;"));
23 handler->AddFunction(GeometrySchlickGGX);
24 GLSLFunction GeometrySmith("GeometrySmith", "vec3 N, vec3 V, vec3 L, float roughness", "float");
25 GeometrySmith.AddLine(GLSLLine("float NdotV = max(dot(N, V), 0.0);"));
26 GeometrySmith.AddLine(GLSLLine("float NdotL = max(dot(N, L), 0.0);"));
27 GeometrySmith.AddLine(GLSLLine(""));
28 GeometrySmith.AddLine(GLSLLine("float ggx2 = GeometrySchlickGGX(NdotV, roughness);"));
29 GeometrySmith.AddLine(GLSLLine("float ggx1 = GeometrySchlickGGX(NdotL, roughness);"));
30 GeometrySmith.AddLine(GLSLLine(""));
31 GeometrySmith.AddLine(GLSLLine("return ggx1 * ggx2;"));
32 handler->AddFunction(GeometrySmith);
33 GLSLFunction frenselSchlick("fresnelSchlick", "float cosTheta, vec3 F0", "vec3");
34 frenselSchlick.AddLine(GLSLLine("return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);"));
35 handler->AddFunction(frenselSchlick);
36}
37
38void PBRMaterialNode::OnEvaluate(GLSLFunction *function, GLSLLine *line)
39{
40 LoadPBRFunctions(handler);
41 function->AddLine(GLSLLine("vec3 " + VAR("albedo") + " = vec3(1.0f);", "The albedo color of the material."));
42 function->AddLine(GLSLLine("vec3 " + VAR("normal") + " = vec3(1.0f);", "The normal of the material."));
43 function->AddLine(GLSLLine("float " + VAR("metallic") + " = 1.0f;", "The metalic of the material."));
44 function->AddLine(GLSLLine("float " + VAR("roughness") + " = 1.0f;", "The roughness of the material."));
45 function->AddLine(GLSLLine("float " + VAR("ao") + " = 1.0f;", "The ambient occlusion of the material."));
46
47 if(inputPins[0]->IsLinked())
48 {
49 GLSLLine tmp("", "");
50 inputPins[0]->other->Evaluate(GetParams(function, &tmp));
51 function->AddLine(GLSLLine("if(" + SDATA(0) + " == 1.0f)", "If gamma corection is enabled adjust the texture accordingly."));
52 function->AddLine(GLSLLine("\t" + VAR("albedo") + " = pow(" + tmp.line + ", vec3(gamma));", "The albedo color of the material."));
53 function->AddLine(GLSLLine("else", "If gamma corection is disabled just use the texture as it is."));
54 function->AddLine(GLSLLine("\t" + VAR("albedo") + " = " + tmp.line + ";", "The albedo color of the material."));
55 }
56
57 if(inputPins[1]->IsLinked())
58 {
59 GLSLLine tmp("", "");
60 inputPins[1]->other->Evaluate(GetParams(function, &tmp));
61 function->AddLine(GLSLLine(VAR("normal") + " = " + tmp.line + ";", "The normal map sampled for current fragment"));
62 function->AddLine(GLSLLine(VAR("normal") + " = TBN * (" + VAR("normal") + " * 2.0f - 1.0f);", "Scale the normal to -1.0f to 1.0f and transform to tangent space"));
63 }
64
65 if(inputPins[5]->IsLinked())
66 {
67 GLSLLine tmp("", "");
68 inputPins[5]->other->Evaluate(GetParams(function, &tmp));
69 function->AddLine(GLSLLine("", "Using the ARM texture for ao, roughness and metalic"));
70 function->AddLine(GLSLLine("vec3 " + VAR("tmp") + " = " + tmp.line + ";", "Temporatily storing the arm data."));
71 function->AddLine(GLSLLine(VAR("ao") + " = " + VAR("tmp") + ".x;", "The ambient occlusion of the material."));
72 function->AddLine(GLSLLine(VAR("roughness") + " = " + VAR("tmp") + ".y;", "The roughness of the material."));
73 function->AddLine(GLSLLine(VAR("metallic") + " = " + VAR("tmp") + ".z;", "The metalic of the material."));
74 }
75
76 else
77 {
78 if(inputPins[2]->IsLinked())
79 {
80 GLSLLine tmp("", "");
81 inputPins[2]->other->Evaluate(GetParams(function, &tmp));
82 function->AddLine(GLSLLine(VAR("metallic") + " = " + tmp.line + ".x;", "The metalic of the material."));
83 }
84
85 if(inputPins[3]->IsLinked())
86 {
87 GLSLLine tmp("", "");
88 inputPins[3]->other->Evaluate(GetParams(function, &tmp));
89 function->AddLine(GLSLLine(VAR("roughness") + " = " + tmp.line + ".x;", "The roughness of the material."));
90 }
91
92 if(inputPins[4]->IsLinked())
93 {
94 GLSLLine tmp("", "");
95 inputPins[4]->other->Evaluate(GetParams(function, &tmp));
96 function->AddLine(GLSLLine(VAR("ao") + " = " + tmp.line + ".x;", "The ambient occlusion of the material."));
97 }
98 }
99
100 function->AddLine(GLSLLine("vec3 " + VAR("N") + " = " + VAR("normal") + ";", "The normal vector"));
101 function->AddLine(GLSLLine("vec3 " + VAR("V") + " = normalize(_CameraPos - FragPos.xyz);", "The view vector"));
102 function->AddLine(GLSLLine("", ""));
103 function->AddLine(GLSLLine("", "Calculate reflectance at normal incidence; if dia-electric (like plastic) use F0"));
104 function->AddLine(GLSLLine("", "of 0.04 and if it's a metal, use the albedo color as F0 (metallic workflow)"));
105 function->AddLine(GLSLLine("vec3 " + VAR("F0") + " = vec3(0.04f);", ""));
106 function->AddLine(GLSLLine(VAR("F0") + " = mix(" + VAR("F0") + ", " + VAR("albedo") + ", " + VAR("metallic") + " );", ""));
107 function->AddLine(GLSLLine("", "Reflectance equation"));
108 function->AddLine(GLSLLine("vec3 " + VAR("Lo") + " = vec3(0.0f);", ""));
109 function->AddLine(GLSLLine("// for(int i = 0 ; i < _NumLights ; i++ )", ""));
110 function->AddLine(GLSLLine("// {", ""));
111 function->AddLine(GLSLLine("", "Calculate per-light radiance"));
112 function->AddLine(GLSLLine("vec3 " + VAR("L") + " = normalize(_LightPosition - FragPos.xyz);", ""));
113 function->AddLine(GLSLLine("vec3 " + VAR("H") + " = normalize(" + VAR("V") + " + " + VAR("L") + ");", ""));
114 function->AddLine(GLSLLine("float " + VAR("distance") + " = length( _LightPosition - FragPos.xyz );", ""));
115 function->AddLine(GLSLLine("float " + VAR("attenuation") + " = 1.0f / (" + VAR("distance") + " * " + VAR("distance") + ");", ""));
116 function->AddLine(GLSLLine("vec3 " + VAR("radiance") + " = _LightColor * _LightStrength * " + VAR("attenuation") + ";", ""));
117 function->AddLine(GLSLLine("", ""));
118 function->AddLine(GLSLLine("", "Color-Torrance BRDF"));
119 function->AddLine(GLSLLine("float " + VAR("NDF") + " = DistributionGGX(" + VAR("N") + ", " + VAR("H") + ", " + VAR("roughness") + ");", ""));
120 function->AddLine(GLSLLine("float " + VAR("G") + " = GeometrySmith(" + VAR("N") + ", " + VAR("V") + ", " + VAR("L") + ", " + VAR("roughness") + ");", ""));
121 function->AddLine(GLSLLine("vec3 " + VAR("F") + " = fresnelSchlick(max(dot(" + VAR("H") + ", " + VAR("V") + "), 0.0f), " + VAR("F0") + ");", ""));
122 function->AddLine(GLSLLine("", ""));
123 function->AddLine(GLSLLine("vec3 " + VAR("numerator") + " = " + VAR("NDF") + " * " + VAR("G") + " * " + VAR("F") + ";", ""));
124 function->AddLine(GLSLLine("float " + VAR("denominator") + " = 4.0f * max(dot(" + VAR("N") + ", " + VAR("V") + "), 0.0f) * max(dot(" + VAR("N") + ", " + VAR("L") + "), 0.0f) + 0.0001f;", "+ 0.0001f to prevent divide by zero"));
125 function->AddLine(GLSLLine("vec3 " + VAR("specular") + " = " + VAR("numerator") + " / " + VAR("denominator") + ";", ""));
126 function->AddLine(GLSLLine("", ""));
127 function->AddLine(GLSLLine("vec3 " + VAR("kS") + " = " + VAR("F") + ";", "kS is equal to Fresnel"));
128 function->AddLine(GLSLLine("", ""));
129 function->AddLine(GLSLLine("", "For energy conservation, the diffuse and specular light can't"));
130 function->AddLine(GLSLLine("", "be above 1.0 (unless the surface emits light); to preserve this"));
131 function->AddLine(GLSLLine("", "relationship the diffuse component (kD) should equal 1.0 - kS."));
132 function->AddLine(GLSLLine("vec3 " + VAR("kD") + " = vec3(1.0f) - " + VAR("kS") + ";", ""));
133 function->AddLine(GLSLLine("", ""));
134 function->AddLine(GLSLLine("", "Multiply kD by the inverse metalness such that only non-metals"));
135 function->AddLine(GLSLLine("", "have diffuse lighting, or a linear blend if partly metal (pure metals"));
136 function->AddLine(GLSLLine("", "have no diffuse light)."));
137 function->AddLine(GLSLLine(VAR("kD") + " *= 1.0 - " + VAR("metallic") + ";", ""));
138 function->AddLine(GLSLLine("", ""));
139 function->AddLine(GLSLLine("", "Scale light by NdotL"));
140 function->AddLine(GLSLLine("float " + VAR("NdotL") + " = max(dot(" + VAR("N") + ", " + VAR("L") + "), 0.0f); ", ""));
141 function->AddLine(GLSLLine("", ""));
142 function->AddLine(GLSLLine("", "// Add to outgoing radiance Lo"));
143 function->AddLine(GLSLLine(VAR("Lo") + " += (" + VAR("kD") + " * " + VAR("albedo") + " / PI + " + VAR("specular") + ") * " + VAR("radiance") + " * " + VAR("NdotL") + ";", "Note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again"));
144 function->AddLine(GLSLLine("", ""));
145 function->AddLine(GLSLLine("// }", ""));
146 function->AddLine(GLSLLine("", ""));
147 function->AddLine(GLSLLine("", "Ambient lighting (note that the next IBL tutorial will replace"));
148 function->AddLine(GLSLLine("", "this ambient lighting with environment lighting)."));
149 function->AddLine(GLSLLine("vec3 " + VAR("ambient") + " = vec3(0.03f) * " + VAR("albedo") + " * " + VAR("ao") + ";", ""));
150 function->AddLine(GLSLLine("", ""));
151 function->AddLine(GLSLLine("vec3 " + VAR("result") + " = " + VAR("ambient") + " + " + VAR("Lo") + ";", ""));
152 function->AddLine(GLSLLine("", ""));
153 function->AddLine(GLSLLine("if(" + SDATA(1) + " == 1.0f)", "If HDR Tonemapping is enable tonemap the result"));
154 function->AddLine(GLSLLine("{", ""));
155 function->AddLine(GLSLLine("\t" + VAR("result") + " = " + VAR("result") + " / (" + VAR("result") + " + vec3(1.0f));", ""));
156 function->AddLine(GLSLLine("}", ""));
157 function->AddLine(GLSLLine("", ""));
158 function->AddLine(GLSLLine("if(" + SDATA(0) + " == 1.0f)", "If Gamma Correction is enable gamma correct the result"));
159 function->AddLine(GLSLLine("{", ""));
160 function->AddLine(GLSLLine("\t" + VAR("result") + " = pow(" + VAR("result") + ", vec3(1.0f/gamma));", ""));
161 function->AddLine(GLSLLine("}", ""));
162 function->AddLine(GLSLLine("", ""));
163 line->line = VAR("result");
164}
165
166void PBRMaterialNode::Load(nlohmann::json data)
167{
168 gammaCorrection = data["gammaCorrection"];
169 hdrTonemapping = data["hdrTonemapping"];
170}
171
172nlohmann::json PBRMaterialNode::Save()
173{
174 nlohmann::json data;
175 data["type"] = "PBRMaterial";
176 data["gammaCorrection"] = gammaCorrection;
177 data["hdrTonemapping"] = hdrTonemapping;
178 return data;
179}
180
181void PBRMaterialNode::UpdateShaders()
182{
183 sharedData->d0 = gammaCorrection ? 1.0f : 0.0f;
184 sharedData->d1 = hdrTonemapping ? 1.0f : 0.0f;
185}
186
187void PBRMaterialNode::OnRender()
188{
189 DrawHeader("PBR Material");
190 inputPins[0]->Render();
191 ImGui::SameLine();
192 ImGui::Text("Albedo");
193 ImGui::SameLine();
194 outputPins[0]->Render();
195 inputPins[1]->Render();
196 ImGui::SameLine();
197 ImGui::Text("Normal");
198 inputPins[2]->Render();
199 ImGui::SameLine();
200 ImGui::Text("Metallic");
201 inputPins[3]->Render();
202 ImGui::SameLine();
203 ImGui::Text("Roughness");
204 inputPins[4]->Render();
205 ImGui::SameLine();
206 ImGui::Text("AO");
207 inputPins[5]->Render();
208 ImGui::SameLine();
209 ImGui::Text("ARM");
210
211 if (ImGui::Checkbox("Gamma Correction", &gammaCorrection))
212 {
213 sharedData->d0 = gammaCorrection ? 1.0f : 0.0f;
214 }
215
216 if (ImGui::Checkbox("HDR Tonemapping", &hdrTonemapping))
217 {
218 sharedData->d1 = hdrTonemapping ? 1.0f : 0.0f;
219 }
220}
221
222PBRMaterialNode::PBRMaterialNode(GLSLHandler *handler)
223 :SNENode(handler)
224{
225 name = "PBR Material";
226 headerColor = ImColor(SHADER_MATERIAL_NODE_COLOR);
227 inputPins.push_back(new SNEPin(NodeEditorPinType::Input, SNEPinType::SNEPinType_Float3)); // Albedo
228 inputPins.push_back(new SNEPin(NodeEditorPinType::Input, SNEPinType::SNEPinType_Float3)); // Normal
229 inputPins.push_back(new SNEPin(NodeEditorPinType::Input, SNEPinType::SNEPinType_Float3)); // Metallic
230 inputPins.push_back(new SNEPin(NodeEditorPinType::Input, SNEPinType::SNEPinType_Float3)); // Roughness
231 inputPins.push_back(new SNEPin(NodeEditorPinType::Input, SNEPinType::SNEPinType_Float3)); // Ambient Occlusion
232 inputPins.push_back(new SNEPin(NodeEditorPinType::Input, SNEPinType::SNEPinType_Float3)); // ARM
233 outputPins.push_back(new SNEPin(NodeEditorPinType::Output, SNEPinType::SNEPinType_Float3)); // Result
234}
235
236
237PBRMaterialNode::~PBRMaterialNode()
238{
239}
a class to store JSON values
Definition: json.hpp:17860