three_d/renderer/material/
deferred_physical_material.rs1use crate::core::*;
2use crate::renderer::*;
3
4#[derive(Clone)]
15pub struct DeferredPhysicalMaterial {
16 pub name: String,
18 pub albedo: Srgba,
20 pub albedo_texture: Option<Texture2DRef>,
23 pub metallic: f32,
25 pub roughness: f32,
27 pub metallic_roughness_texture: Option<Texture2DRef>,
30 pub occlusion_strength: f32,
32 pub occlusion_texture: Option<Texture2DRef>,
35 pub normal_scale: f32,
37 pub normal_texture: Option<Texture2DRef>,
39 pub render_states: RenderStates,
41 pub emissive: Srgba,
43 pub emissive_texture: Option<Texture2DRef>,
46 pub alpha_cutout: Option<f32>,
50}
51
52impl DeferredPhysicalMaterial {
53 pub fn new(context: &Context, cpu_material: &CpuMaterial) -> Self {
59 let albedo_texture =
60 cpu_material
61 .albedo_texture
62 .as_ref()
63 .map(|cpu_texture| match &cpu_texture.data {
64 TextureData::RgbU8(_) | TextureData::RgbaU8(_) => {
65 let mut cpu_texture = cpu_texture.clone();
66 cpu_texture.data.to_linear_srgb();
67 Texture2DRef::from_cpu_texture(context, &cpu_texture)
68 }
69 _ => Texture2DRef::from_cpu_texture(context, cpu_texture),
70 });
71 let metallic_roughness_texture =
72 if let Some(ref cpu_texture) = cpu_material.occlusion_metallic_roughness_texture {
73 Some(Texture2DRef::from_cpu_texture(context, cpu_texture))
74 } else {
75 cpu_material
76 .metallic_roughness_texture
77 .as_ref()
78 .map(|cpu_texture| Texture2DRef::from_cpu_texture(context, cpu_texture))
79 };
80 let occlusion_texture = if cpu_material.occlusion_metallic_roughness_texture.is_some() {
81 metallic_roughness_texture.clone()
82 } else {
83 cpu_material
84 .occlusion_texture
85 .as_ref()
86 .map(|cpu_texture| Texture2DRef::from_cpu_texture(context, cpu_texture))
87 };
88 let normal_texture = cpu_material
89 .normal_texture
90 .as_ref()
91 .map(|cpu_texture| Texture2DRef::from_cpu_texture(context, cpu_texture));
92 let emissive_texture =
93 cpu_material
94 .emissive_texture
95 .as_ref()
96 .map(|cpu_texture| match &cpu_texture.data {
97 TextureData::RgbU8(_) | TextureData::RgbaU8(_) => {
98 let mut cpu_texture = cpu_texture.clone();
99 cpu_texture.data.to_linear_srgb();
100 Texture2DRef::from_cpu_texture(context, &cpu_texture)
101 }
102 _ => Texture2DRef::from_cpu_texture(context, cpu_texture),
103 });
104 Self {
105 name: cpu_material.name.clone(),
106 albedo: cpu_material.albedo,
107 albedo_texture,
108 metallic: cpu_material.metallic,
109 roughness: cpu_material.roughness,
110 metallic_roughness_texture,
111 normal_texture,
112 normal_scale: cpu_material.normal_scale,
113 occlusion_texture,
114 occlusion_strength: cpu_material.occlusion_strength,
115 render_states: RenderStates::default(),
116 alpha_cutout: cpu_material.alpha_cutout,
117 emissive: cpu_material.emissive,
118 emissive_texture,
119 }
120 }
121
122 pub fn from_physical_material(physical_material: &PhysicalMaterial) -> Self {
126 Self {
127 name: physical_material.name.clone(),
128 albedo: physical_material.albedo,
129 albedo_texture: physical_material.albedo_texture.clone(),
130 metallic: physical_material.metallic,
131 roughness: physical_material.roughness,
132 metallic_roughness_texture: physical_material.metallic_roughness_texture.clone(),
133 normal_texture: physical_material.normal_texture.clone(),
134 normal_scale: physical_material.normal_scale,
135 occlusion_texture: physical_material.occlusion_texture.clone(),
136 occlusion_strength: physical_material.occlusion_strength,
137 render_states: RenderStates {
138 write_mask: WriteMask::default(),
139 blend: Blend::Disabled,
140 ..physical_material.render_states
141 },
142 emissive: physical_material.emissive,
143 emissive_texture: physical_material.emissive_texture.clone(),
144 alpha_cutout: if physical_material.is_transparent {
145 Some(0.5)
146 } else {
147 None
148 },
149 }
150 }
151 pub fn lighting_pass(
157 context: &Context,
158 viewer: &dyn Viewer,
159 geometry_pass_color_texture: ColorTexture,
160 geometry_pass_depth_texture: DepthTexture,
161 lights: &[&dyn Light],
162 ) {
163 apply_screen_effect(
164 context,
165 lighting_pass::LightingPassEffect {},
166 viewer,
167 lights,
168 Some(geometry_pass_color_texture),
169 Some(geometry_pass_depth_texture),
170 );
171 }
172}
173
174impl FromCpuMaterial for DeferredPhysicalMaterial {
175 fn from_cpu_material(context: &Context, cpu_material: &CpuMaterial) -> Self {
176 Self::new(context, cpu_material)
177 }
178}
179
180impl Material for DeferredPhysicalMaterial {
181 fn id(&self) -> EffectMaterialId {
182 EffectMaterialId::DeferredPhysicalMaterial(
183 self.albedo_texture.is_some(),
184 self.metallic_roughness_texture.is_some(),
185 self.occlusion_texture.is_some(),
186 self.normal_texture.is_some(),
187 self.emissive_texture.is_some(),
188 self.alpha_cutout.is_some(),
189 )
190 }
191
192 fn fragment_shader_source(&self, _lights: &[&dyn Light]) -> String {
193 let mut output = include_str!("../../core/shared.frag").to_string();
194 if self.albedo_texture.is_some()
195 || self.metallic_roughness_texture.is_some()
196 || self.normal_texture.is_some()
197 || self.occlusion_texture.is_some()
198 || self.emissive_texture.is_some()
199 || self.alpha_cutout.is_some()
200 {
201 output.push_str("in vec2 uvs;\n");
202 if self.albedo_texture.is_some() {
203 output.push_str("#define USE_ALBEDO_TEXTURE;\n");
204 }
205 if self.metallic_roughness_texture.is_some() {
206 output.push_str("#define USE_METALLIC_ROUGHNESS_TEXTURE;\n");
207 }
208 if self.occlusion_texture.is_some() {
209 output.push_str("#define USE_OCCLUSION_TEXTURE;\n");
210 }
211 if self.normal_texture.is_some() {
212 output.push_str("#define USE_NORMAL_TEXTURE;\nin vec3 tang;\nin vec3 bitang;\n");
213 }
214 if self.emissive_texture.is_some() {
215 output.push_str("#define USE_EMISSIVE_TEXTURE;\n");
216 }
217 if self.alpha_cutout.is_some() {
218 output.push_str(
219 format!(
220 "#define ALPHACUT;\nfloat acut = {};",
221 self.alpha_cutout.unwrap()
222 )
223 .as_str(),
224 );
225 }
226 }
227 output.push_str(include_str!("shaders/deferred_physical_material.frag"));
228 output
229 }
230
231 fn use_uniforms(&self, program: &Program, _viewer: &dyn Viewer, _lights: &[&dyn Light]) {
232 program.use_uniform("metallic", self.metallic);
233 program.use_uniform("roughness", self.roughness);
234 program.use_uniform("albedo", self.albedo.to_linear_srgb());
235 program.use_uniform("emissive", self.emissive.to_linear_srgb());
236 if let Some(ref texture) = self.albedo_texture {
237 program.use_texture("albedoTexture", texture);
238 program.use_uniform("albedoTexTransform", texture.transformation);
239 }
240 if let Some(ref texture) = self.metallic_roughness_texture {
241 program.use_texture("metallicRoughnessTexture", texture);
242 program.use_uniform("metallicRoughnessTexTransform", texture.transformation);
243 }
244 if let Some(ref texture) = self.occlusion_texture {
245 program.use_uniform("occlusionStrength", self.occlusion_strength);
246 program.use_uniform("occlusionTexTransform", texture.transformation);
247 program.use_texture("occlusionTexture", texture);
248 }
249 if let Some(ref texture) = self.normal_texture {
250 program.use_uniform("normalScale", self.normal_scale);
251 program.use_uniform("normalTexTransform", texture.transformation);
252 program.use_texture("normalTexture", texture);
253 }
254 if program.requires_uniform("emissiveTexture") {
255 if let Some(ref texture) = self.emissive_texture {
256 program.use_uniform("emissiveTexTransform", texture.transformation);
257 program.use_texture("emissiveTexture", texture);
258 }
259 }
260 }
261
262 fn render_states(&self) -> RenderStates {
263 self.render_states
264 }
265
266 fn material_type(&self) -> MaterialType {
267 MaterialType::Deferred
268 }
269}
270
271impl Default for DeferredPhysicalMaterial {
272 fn default() -> Self {
273 Self {
274 name: "default".to_string(),
275 albedo: Srgba::WHITE,
276 albedo_texture: None,
277 metallic: 0.0,
278 roughness: 1.0,
279 metallic_roughness_texture: None,
280 normal_texture: None,
281 normal_scale: 1.0,
282 occlusion_texture: None,
283 occlusion_strength: 1.0,
284 render_states: RenderStates::default(),
285 alpha_cutout: None,
286 emissive: Srgba::BLACK,
287 emissive_texture: None,
288 }
289 }
290}