1 # SPDX-FileCopyrightText: 2015-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 """Translate complex shaders to exported POV textures."""
10 def write_object_material_interior(file, material
, ob
, tab_write
):
11 """Translate some object level material from Blender UI (VS data level)
13 to POV interior{} syntax and write it to exported file.
14 This is called in model_all.objects_loop
16 # DH - modified some variables to be function local, avoiding RNA write
17 # this should be checked to see if it is functionally correct
19 # Commented out: always write IOR to be able to use it for SSS, Fresnel reflections...
20 # if material and material.pov.transparency_method == 'RAYTRACE':
23 # implicit if material:
24 # But there can be only one ior!
25 if material
.pov_subsurface_scattering
.use
: # SSS IOR get highest priority
26 tab_write(file, "interior {\n")
27 tab_write(file, "ior %.6f\n" % material
.pov_subsurface_scattering
.ior
)
28 # Then the raytrace IOR taken from raytrace transparency properties and used for
29 # reflections if IOR Mirror option is checked.
30 elif material
.pov
.mirror_use_IOR
or material
.pov
.transparency_method
!= "Z_TRANSPARENCY":
31 tab_write(file, "interior {\n")
32 tab_write(file, "ior %.6f\n" % material
.pov_raytrace_transparency
.ior
)
34 tab_write(file, "interior {\n")
35 tab_write(file, "ior 1.0\n")
37 pov_fake_caustics
= False
38 pov_photons_refraction
= False
39 pov_photons_reflection
= bool(material
.pov
.photons_reflection
)
40 if not material
.pov
.refraction_caustics
:
41 pov_fake_caustics
= False
42 pov_photons_refraction
= False
43 elif material
.pov
.refraction_type
== "1":
44 pov_fake_caustics
= True
45 pov_photons_refraction
= False
46 elif material
.pov
.refraction_type
== "2":
47 pov_fake_caustics
= False
48 pov_photons_refraction
= True
50 # If only Raytrace transparency is set, its IOR will be used for refraction, but user
51 # can set up 'un-physical' fresnel reflections in raytrace mirror parameters.
52 # Last, if none of the above is specified, user can set up 'un-physical' fresnel
53 # reflections in raytrace mirror parameters. And pov IOR defaults to 1.
54 if material
.pov
.caustics_enable
:
56 tab_write(file, "caustics %.3g\n" % material
.pov
.fake_caustics_power
)
57 if pov_photons_refraction
:
58 # Default of 1 means no dispersion
59 tab_write(file, "dispersion %.6f\n" % material
.pov
.photons_dispersion
)
60 tab_write(file, "dispersion_samples %.d\n" % material
.pov
.photons_dispersion_samples
)
63 if material
.pov
.use_transparency
and material
.pov
.transparency_method
== "RAYTRACE":
65 # In Blender this value has always been reversed compared to what tooltip says.
66 # 100.001 rather than 100 so that it does not get to 0
67 # which deactivates the feature in POV
69 file, "fade_distance %.3g\n" % (100.001 - material
.pov_raytrace_transparency
.depth_max
)
72 tab_write(file, "fade_power %.3g\n" % material
.pov_raytrace_transparency
.falloff
)
74 tab_write(file, "fade_color <%.3g, %.3g, %.3g>\n" % material
.pov
.interior_fade_color
[:])
76 # (variable) dispersion_samples (constant count for now)
77 tab_write(file, "}\n")
78 if material
.pov
.photons_reflection
or material
.pov
.refraction_type
== "2":
79 tab_write(file, "photons{")
80 tab_write(file, "target %.3g\n" % ob
.pov
.spacing_multiplier
)
81 if not ob
.pov
.collect_photons
:
82 tab_write(file, "collect off\n")
83 if pov_photons_refraction
:
84 tab_write(file, "refraction on\n")
85 if pov_photons_reflection
:
86 tab_write(file, "reflection on\n")
87 tab_write(file, "}\n")
97 material_names_dictionary
,
100 """Translate Blender material to POV texture{} block and write in exported file."""
101 # Assumes only called once on each material
103 from .render
import safety
106 name_orig
= material
.name
107 name
= material_names_dictionary
[name_orig
] = unique_name(
108 bpy
.path
.clean_name(name_orig
), material_names_dictionary
110 # If saturation(.s) is not zero, then color is not grey, and has a tint
111 colored_specular_found
= (material
.pov
.specular_color
.s
> 0.0) and (
112 material
.pov
.diffuse_shader
!= "MINNAERT"
115 name
= name_orig
= DEF_MAT_NAME
118 # Several versions of the finish: ref_level_bound conditions are variations for specular/Mirror
119 # texture channel map with alternative finish of 0 specular and no mirror reflection.
120 # ref_level_bound=1 Means No specular nor Mirror reflection
121 # ref_level_bound=2 Means translation of spec and mir levels for when no map influences them
122 # ref_level_bound=3 Means Maximum Spec and Mirror
124 def pov_has_no_specular_maps(file, ref_level_bound
):
125 """Translate Blender specular map influence to POV finish map trick and write to file."""
126 if ref_level_bound
== 1:
128 tab_write(file, "//--No specular nor Mirror reflection--\n")
130 tab_write(file, "\n")
131 tab_write(file, "#declare %s = finish {\n" % safety(name
, ref_level_bound
=1))
133 elif ref_level_bound
== 2:
137 "//--translation of spec and mir levels for when no map " "influences them--\n",
140 tab_write(file, "\n")
141 tab_write(file, "#declare %s = finish {\n" % safety(name
, ref_level_bound
=2))
143 elif ref_level_bound
== 3:
145 tab_write(file, "//--Maximum Spec and Mirror--\n")
147 tab_write(file, "\n")
148 tab_write(file, "#declare %s = finish {\n" % safety(name
, ref_level_bound
=3))
150 # POV-Ray 3.7 now uses two diffuse values respectively for front and back shading
151 # (the back diffuse is like blender translucency)
152 front_diffuse
= material
.pov
.diffuse_intensity
153 back_diffuse
= material
.pov
.translucency
155 if material
.pov
.conserve_energy
:
157 # Total should not go above one
158 if (front_diffuse
+ back_diffuse
) <= 1.0:
160 elif front_diffuse
== back_diffuse
:
161 # Try to respect the user's 'intention' by comparing the two values but
162 # bringing the total back to one.
163 front_diffuse
= back_diffuse
= 0.5
164 # Let the highest value stay the highest value.
165 elif front_diffuse
> back_diffuse
:
166 # clamps the sum below 1
167 back_diffuse
= min(back_diffuse
, (1.0 - front_diffuse
))
169 front_diffuse
= min(front_diffuse
, (1.0 - back_diffuse
))
171 # map hardness between 0.0 and 1.0
172 roughness
= 1.0 - ((material
.pov
.specular_hardness
- 1.0) / 510.0)
173 ## scale from 0.0 to 0.1
175 # add a small value because 0.0 is invalid.
176 roughness
+= 1.0 / 511.0
178 # ------------------------------ Diffuse Shader ------------------------------ #
179 # Not used for Full spec (ref_level_bound=3) of the shader.
180 if material
.pov
.diffuse_shader
== "OREN_NAYAR" and ref_level_bound
!= 3:
181 # Blender roughness is what is generally called oren nayar Sigma,
182 # and brilliance in POV-Ray.
183 tab_write(file, "brilliance %.3g\n" % (0.9 + material
.roughness
))
185 if material
.pov
.diffuse_shader
== "TOON" and ref_level_bound
!= 3:
186 tab_write(file, "brilliance %.3g\n" % (0.01 + material
.diffuse_toon_smooth
* 0.25))
187 # Lower diffuse and increase specular for toon effect seems to look better
191 if material
.pov
.diffuse_shader
== "MINNAERT" and ref_level_bound
!= 3:
192 # tab_write(file, "aoi %.3g\n" % material.pov.darkness)
193 pass # let's keep things simple for now
194 if material
.pov
.diffuse_shader
== "FRESNEL" and ref_level_bound
!= 3:
195 # tab_write(file, "aoi %.3g\n" % material.pov.diffuse_fresnel_factor)
196 pass # let's keep things simple for now
197 if material
.pov
.diffuse_shader
== "LAMBERT" and ref_level_bound
!= 3:
198 # trying to best match lambert attenuation by that constant brilliance value
199 tab_write(file, "brilliance 1\n")
201 if ref_level_bound
== 2:
202 # ------------------------------ Specular Shader ------------------------------ #
203 # No difference between phong and cook torrence in blender HaHa!
204 if material
.pov
.specular_shader
in ["COOKTORR", "PHONG"]:
205 tab_write(file, "phong %.3g\n" % material
.pov
.specular_intensity
)
206 tab_write(file, "phong_size %.3g\n" % (material
.pov
.specular_hardness
/ 3.14))
208 # POV-Ray 'specular' keyword corresponds to a Blinn model, without the ior.
209 elif material
.pov
.specular_shader
== "BLINN":
210 # Use blender Blinn's IOR just as some factor for spec intensity
214 % (material
.pov
.specular_intensity
* (material
.pov
.specular_ior
/ 4.0)),
216 tab_write(file, "roughness %.3g\n" % roughness
)
217 # Could use brilliance 2(or varying around 2 depending on ior or factor) too.
219 elif material
.pov
.specular_shader
== "TOON":
220 tab_write(file, "phong %.3g\n" % (material
.pov
.specular_intensity
* 2.0))
221 # use extreme phong_size
223 file, "phong_size %.3g\n" % (0.1 + material
.pov
.specular_toon_smooth
/ 2.0)
226 elif material
.pov
.specular_shader
== "WARDISO":
227 # find best suited default constant for brilliance Use both phong and
228 # specular for some values.
233 material
.pov
.specular_intensity
/ (material
.pov
.specular_slope
+ 0.0005)
236 # find best suited default constant for brilliance Use both phong and
237 # specular for some values.
239 file, "roughness %.4g\n" % (0.0005 + material
.pov
.specular_slope
/ 10.0)
241 # find best suited default constant for brilliance Use both phong and
242 # specular for some values.
243 tab_write(file, "brilliance %.4g\n" % (1.8 - material
.pov
.specular_slope
* 1.8))
245 # -------------------------------------------------------------------------------- #
246 elif ref_level_bound
== 1:
247 if material
.pov
.specular_shader
in ["COOKTORR", "PHONG"]:
248 tab_write(file, "phong 0\n") # %.3g\n" % (material.pov.specular_intensity/5))
249 tab_write(file, "phong_size %.3g\n" % (material
.pov
.specular_hardness
/ 3.14))
251 # POV-Ray 'specular' keyword corresponds to a Blinn model, without the ior.
252 elif material
.pov
.specular_shader
== "BLINN":
253 # Use blender Blinn's IOR just as some factor for spec intensity
257 % (material
.pov
.specular_intensity
* (material
.pov
.specular_ior
/ 4.0)),
259 tab_write(file, "roughness %.3g\n" % roughness
)
260 # Could use brilliance 2(or varying around 2 depending on ior or factor) too.
262 elif material
.pov
.specular_shader
== "TOON":
263 tab_write(file, "phong %.3g\n" % (material
.pov
.specular_intensity
* 2.0))
264 # use extreme phong_size
266 file, "phong_size %.3g\n" % (0.1 + material
.pov
.specular_toon_smooth
/ 2.0)
269 elif material
.pov
.specular_shader
== "WARDISO":
270 # find best suited default constant for brilliance Use both phong and
271 # specular for some values.
276 material
.pov
.specular_intensity
/ (material
.pov
.specular_slope
+ 0.0005)
279 # find best suited default constant for brilliance Use both phong and
280 # specular for some values.
282 file, "roughness %.4g\n" % (0.0005 + material
.pov
.specular_slope
/ 10.0)
284 # find best suited default constant for brilliance Use both phong and
285 # specular for some values.
286 tab_write(file, "brilliance %.4g\n" % (1.8 - material
.pov
.specular_slope
* 1.8))
287 elif ref_level_bound
== 3:
288 # Spec must be Max at ref_level_bound 3 so that white of mixing texture always shows specularity
289 # That's why it's multiplied by 255. maybe replace by texture's brightest pixel value?
290 if material
.pov_texture_slots
:
292 material
.pov
.specular_intensity
293 * material
.pov
.specular_color
.v
295 * slot
.specular_factor
299 material
.pov
.specular_intensity
* material
.pov
.specular_color
.v
* 255
301 tab_write(file, "specular %.3g\n" % max_spec_factor
)
302 tab_write(file, "roughness %.3g\n" % (1 / material
.pov
.specular_hardness
))
303 tab_write(file, "diffuse %.3g, %.3g\n" % (front_diffuse
, back_diffuse
))
305 tab_write(file, "ambient %.3g\n" % material
.pov
.ambient
)
306 # POV-Ray blends the global value
307 # tab_write(file, "ambient rgb <%.3g, %.3g, %.3g>\n" % \
308 # tuple([c*material.pov.ambient for c in world.ambient_color]))
309 tab_write(file, "emission %.3g\n" % material
.pov
.emit
) # New in POV-Ray 3.7
311 # POV-Ray just ignores roughness if there's no specular keyword
312 # tab_write(file, "roughness %.3g\n" % roughness)
314 if material
.pov
.conserve_energy
:
315 # added for more realistic shading. Needs some checking to see if it
316 # really works. --Maurice.
317 tab_write(file, "conserve_energy\n")
319 if colored_specular_found
:
320 tab_write(file, "metallic\n")
323 if ref_level_bound
!= 1 and material
.pov_raytrace_mirror
.use
:
324 raytrace_mirror
= material
.pov_raytrace_mirror
325 if raytrace_mirror
.reflect_factor
:
326 tab_write(file, "reflection {\n")
327 tab_write(file, "rgb <%.3g, %.3g, %.3g>\n" % material
.pov
.mirror_color
[:])
328 if material
.metallic
:
329 tab_write(file, "metallic %.3g\n" % material
.metallic
)
330 # Blurry reflections for UberPOV
331 if using_uberpov
and raytrace_mirror
.gloss_factor
< 1.0:
332 # tab_write(file, "#ifdef(unofficial) #if(unofficial = \"patch\") #if(patch(\"upov-reflection-roughness\") > 0)\n")
334 file, "roughness %.6f\n" % (0.000001 / raytrace_mirror
.gloss_factor
)
336 # tab_write(file, "#end #end #end\n") # This and previous comment for backward compatibility, messier pov code
337 if material
.pov
.mirror_use_IOR
: # WORKING ?
338 # Removed from the line below: gives a more physically correct
339 # material but needs proper IOR. --Maurice
340 tab_write(file, "fresnel 1 ")
343 "falloff %.3g exponent %.3g} "
344 % (raytrace_mirror
.fresnel
, raytrace_mirror
.fresnel_factor
),
347 if material
.pov_subsurface_scattering
.use
:
348 subsurface_scattering
= material
.pov_subsurface_scattering
351 "subsurface { translucency <%.3g, %.3g, %.3g> }\n"
353 (subsurface_scattering
.radius
[0]),
354 (subsurface_scattering
.radius
[1]),
355 (subsurface_scattering
.radius
[2]),
359 if material
.pov
.irid_enable
:
362 "irid { %.4g thickness %.4g turbulence %.4g }"
364 material
.pov
.irid_amount
,
365 material
.pov
.irid_thickness
,
366 material
.pov
.irid_turbulence
,
371 tab_write(file, "diffuse 0.8\n")
372 tab_write(file, "phong 70.0\n")
374 # tab_write(file, "specular 0.2\n")
376 # This is written into the object
378 if material and material.pov.transparency_method=='RAYTRACE':
379 'interior { ior %.3g} ' % material.raytrace_transparency.ior
382 # tab_write(file, "crand 1.0\n") # Sand granyness
383 # tab_write(file, "metallic %.6f\n" % material.metallic)
384 # tab_write(file, "phong %.6f\n" % material.spec)
385 # tab_write(file, "phong_size %.6f\n" % material.spec)
386 # tab_write(file, "brilliance %.6f " % (material.pov.specular_hardness/256.0) # Like hardness
388 tab_write(file, "}\n\n")
390 # ref_level_bound=2 Means translation of spec and mir levels for when no map influences them
391 pov_has_no_specular_maps(file, ref_level_bound
=2)
394 special_texture_found
= False
397 for t
in material
.pov_texture_slots
:
399 # index = material.pov.active_texture_index
400 slot
= material
.pov_texture_slots
[tmpidx
] # [index]
401 povtex
= slot
.texture
# slot.name
402 tex
= bpy
.data
.textures
[povtex
]
404 if t
and t
.use
and tex
is not None:
406 if (tex
.type == "IMAGE" and tex
.image
) or tex
.type != "IMAGE":
418 special_texture_found
= True
420 continue # Some texture found
422 if special_texture_found
or colored_specular_found
:
423 # ref_level_bound=1 Means No specular nor Mirror reflection
424 pov_has_no_specular_maps(file, ref_level_bound
=1)
426 # ref_level_bound=3 Means Maximum Spec and Mirror
427 pov_has_no_specular_maps(file, ref_level_bound
=3)