From b8414394dabd0dc85087de1942643e961fe0092a Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sun, 5 Aug 2018 17:53:33 -0400 Subject: [PATCH] Fix lightmap baking with "Receive Transparent" Due to our disabling of texture baking when lightmapping, Blender would not be able to cast light through transparent materials. Now, we revert back to something resembling the manual method of lightmapping from the bad old days of PyPRP. Do note that because we attempt to batch object baking as much as possible, I have disabled baking lightmaps to transparent objects. This is because the transparent objects would need its textures disabled for it to be baked to, but with the textures disabled, the renderer would be unable to correctly determine the object's transparency. D'oh! It would be possible, I suppose, to move them into their own batch, but that makes the state machine a bit more complex. It would be better to wait for someone to need that functionality, I think. --- korman/exporter/etlight.py | 23 +++++++++++++++++++---- korman/render.py | 1 + korman/ui/modifiers/render.py | 26 +++++++++++++++----------- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/korman/exporter/etlight.py b/korman/exporter/etlight.py index 119242b..fec2c2f 100644 --- a/korman/exporter/etlight.py +++ b/korman/exporter/etlight.py @@ -51,9 +51,12 @@ class LightBaker(_MeshManager): def _apply_render_settings(self, toggle, vcols): render = bpy.context.scene.render - toggle.track(render, "use_textures", False) + + # Remember, lightmaps carefully control the enabled textures such that light + # can be cast through transparent materials. See diatribe in lightmap prep. + toggle.track(render, "use_textures", not vcols) toggle.track(render, "use_shadows", True) - toggle.track(render, "use_envmaps", False) + toggle.track(render, "use_envmaps", True) toggle.track(render, "use_raytrace", True) toggle.track(render, "bake_type", "FULL") toggle.track(render, "use_bake_clear", True) @@ -243,6 +246,18 @@ class LightBaker(_MeshManager): modifier = bo.plasma_modifiers.lightmap uv_textures = mesh.uv_textures + # Previously, we told Blender to just ignore textures althogether when baking + # VCols or lightmaps. This is easy, but it prevents us from doing tricks like + # using the "Receive Transparent" option, which allows for light to be cast + # through sections of materials that are transparent. Therefore, on objects + # that are lightmapped, we will disable all the texture slots... + # Due to our batching, however, materials that are transparent cannot be lightmapped. + for material in (i for i in mesh.materials if i is not None): + if material.use_transparency: + raise ExportError("'{}': Cannot lightmap material '{}' because it is transparnt".format(bo.name, material.name)) + for slot in (j for j in material.texture_slots if j is not None): + toggle.track(slot, "use", False) + # Create a special light group for baking if not self._generate_lightgroup(bo, modifier.lights): return False @@ -357,7 +372,7 @@ class LightBaker(_MeshManager): for i in bpy.data.objects: if i == objs: # prevents proper baking to texture - for mat in i.data.materials: + for mat in (j for j in i.data.materials if j is not None): toggle.track(mat, "use_vertex_color_paint", False) i.select = True else: @@ -370,7 +385,7 @@ class LightBaker(_MeshManager): value = i in objs if value: # prevents proper baking to texture - for mat in i.data.materials: + for mat in (j for j in i.data.materials if j is not None): toggle.track(mat, "use_vertex_color_paint", False) toggle.track(i, "hide_render", False) elif isinstance(i.data, bpy.types.Mesh) and not self._has_valid_material(i): diff --git a/korman/render.py b/korman/render.py index d478ef4..393b9eb 100644 --- a/korman/render.py +++ b/korman/render.py @@ -33,6 +33,7 @@ properties_material.MATERIAL_PT_specular.COMPAT_ENGINES.add("PLASMA_GAME") properties_material.MATERIAL_PT_options.COMPAT_ENGINES.add("PLASMA_GAME") properties_material.MATERIAL_PT_preview.COMPAT_ENGINES.add("PLASMA_GAME") properties_material.MATERIAL_PT_transp.COMPAT_ENGINES.add("PLASMA_GAME") +properties_material.MATERIAL_PT_shadow.COMPAT_ENGINES.add("PLASMA_GAME") del properties_material from bl_ui import properties_data_mesh diff --git a/korman/ui/modifiers/render.py b/korman/ui/modifiers/render.py index 34063c2..be79b78 100644 --- a/korman/ui/modifiers/render.py +++ b/korman/ui/modifiers/render.py @@ -87,17 +87,21 @@ def lightmap(modifier, layout, context): layout.prop(modifier, "lights") layout.prop_search(modifier, "uv_map", context.active_object.data, "uv_textures") - operator = layout.operator("object.plasma_lightmap_preview", "Preview Lightmap", icon="RENDER_STILL") - - # Kind of clever stuff to show the user a preview... - # We can't show images, so we make a hidden ImageTexture called LIGHTMAPGEN_PREVIEW. We check - # the backing image name to see if it's for this lightmap. If so, you have a preview. If not, - # well... It was nice knowing you! - tex = bpy.data.textures.get("LIGHTMAPGEN_PREVIEW") - if tex is not None and tex.image is not None: - im_name = "{}_LIGHTMAPGEN.png".format(context.active_object.name) - if tex.image.name == im_name: - layout.template_preview(tex, show_buttons=False) + # Lightmaps can only be applied to objects with opaque materials. + if any((i.use_transparency for i in modifier.id_data.data.materials if i is not None)): + layout.label("Transparent objects cannot be lightmapped.", icon="ERROR") + else: + operator = layout.operator("object.plasma_lightmap_preview", "Preview Lightmap", icon="RENDER_STILL") + + # Kind of clever stuff to show the user a preview... + # We can't show images, so we make a hidden ImageTexture called LIGHTMAPGEN_PREVIEW. We check + # the backing image name to see if it's for this lightmap. If so, you have a preview. If not, + # well... It was nice knowing you! + tex = bpy.data.textures.get("LIGHTMAPGEN_PREVIEW") + if tex is not None and tex.image is not None: + im_name = "{}_LIGHTMAPGEN.png".format(context.active_object.name) + if tex.image.name == im_name: + layout.template_preview(tex, show_buttons=False) def rtshadow(modifier, layout, context): split = layout.split()