From 8bb8683f7ce71eb3a13507995bccee7e11a286d5 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Fri, 5 Jun 2015 23:24:11 -0400 Subject: [PATCH] Implement crappy vertex color light baking... This should make the average age look a little bit better. I hope... If you want to get rid of this crappy lighting, create a vertex color layer. Or, better yet, add a stupid lightmap modifier! --- korman/exporter/mesh.py | 69 ++++++++++++++++++++++++++------- korman/operators/op_lightmap.py | 51 ++++++++++++++++++++---- 2 files changed, 100 insertions(+), 20 deletions(-) diff --git a/korman/exporter/mesh.py b/korman/exporter/mesh.py index ba82b59..cdb4b7c 100644 --- a/korman/exporter/mesh.py +++ b/korman/exporter/mesh.py @@ -24,6 +24,8 @@ from . import utils _MAX_VERTS_PER_SPAN = 0xFFFF _WARN_VERTS_PER_SPAN = 0x8000 +_VERTEX_COLOR_LAYERS = {"col", "color", "colour"} + class _RenderLevel: MAJOR_OPAQUE = 0 MAJOR_FRAMEBUF = 1 @@ -148,6 +150,17 @@ class MeshConverter: }) geodata = [_geodatacls() for i in mesh.materials] + # Locate relevant vertex color layers now... + color, alpha = None, None + for vcol_layer in mesh.tessface_vertex_colors: + name = vcol_layer.name.lower() + if name in _VERTEX_COLOR_LAYERS: + color = vcol_layer.data + elif name == "autocolor" and color is None: + color = vcol_layer.data + elif name == "alpha": + alpha = vcol_layer.data + # Convert Blender faces into things we can stuff into libHSPlasma for i, tessface in enumerate(mesh.tessfaces): data = geodata[tessface.material_index] @@ -157,24 +170,42 @@ class MeshConverter: # NOTE: Blender has no third (W) coordinate tessface_uvws = [uvtex.data[i].uv for uvtex in mesh.tessface_uv_textures] + # Unpack colors + if color is None: + tessface_colors = ((1.0, 1.0, 1.0), (1.0, 1.0, 1.0), (1.0, 1.0, 1.0), (1.0, 1.0, 1.0)) + else: + src = color[i] + tessface_colors = (src.color1, src.color2, src.color3, src.color4) + + # Unpack alpha values + if alpha is None: + tessface_alphas = (1.0, 1.0, 1.0, 1.0) + else: + src = alpha[i] + # average color becomes the alpha value + tessface_alphas = (((src.color1[0] + src.color1[1] + src.color1[2]) / 3), + ((src.color2[0] + src.color2[1] + src.color2[2]) / 3), + ((src.color3[0] + src.color3[1] + src.color3[2]) / 3), + ((src.color4[0] + src.color4[1] + src.color4[2]) / 3)) + # Convert to per-material indices for j, vertex in enumerate(tessface.vertices): uvws = tuple([uvw[j] for uvw in tessface_uvws]) - # Grab VCols (TODO--defaulting to white for now) - # This will be finalized once the vertex color light code baking is in - color = (255, 255, 255, 255) + # Grab VCols + vertex_color = (int(tessface_colors[j][0] * 255), int(tessface_colors[j][1] * 255), + int(tessface_colors[j][2] * 255), int(tessface_alphas[j] * 255)) # Now, we'll index into the vertex dict using the per-face elements :( # We're using tuples because lists are not hashable. The many mathutils and PyHSPlasma # types are not either, and it's entirely too much work to fool with all that. - coluv = (color, uvws) + coluv = (vertex_color, uvws) if coluv not in data.blender2gs[vertex]: source = mesh.vertices[vertex] geoVertex = plGeometrySpan.TempVertex() geoVertex.position = utils.vector3(source.co) geoVertex.normal = utils.vector3(source.normal) - geoVertex.color = hsColor32(*color) + geoVertex.color = hsColor32(*vertex_color) geoVertex.uvs = [hsVector3(uv[0], uv[1], 0.0) for uv in uvws] data.blender2gs[vertex][coluv] = len(data.vertices) data.vertices.append(geoVertex) @@ -217,15 +248,10 @@ class MeshConverter: return diface.key def _export_mesh(self, bo): - # Step 0.8: If this mesh wants to be light mapped, we need to go ahead and generate it. - if bo.plasma_modifiers.lightmap.enabled: - print(" Baking lightmap...") - print("====") - bpy.context.scene.objects.active = bo - bpy.ops.object.plasma_lightmap_autobake() - print("====") + # Step 0.8: If this mesh wants to be lit, we need to go ahead and generate it. + self._export_static_lighting(bo) - # Step 0.9: Update the mesh + # Step 0.9: Update the mesh such that we can do things and schtuff... mesh = bo.data mesh.update(calc_tessface=True) @@ -263,6 +289,23 @@ class MeshConverter: geospans[i] = (self._create_geospan(bo, mesh, blmat, hsgmat), blmat.pass_index) return geospans + def _export_static_lighting(self, bo): + if bo.plasma_modifiers.lightmap.enabled: + print(" Baking lightmap...") + print("====") + bpy.context.scene.objects.active = bo + bpy.ops.object.plasma_lightmap_autobake() + print("====") + else: + for vcol_layer in bo.data.vertex_colors: + name = vcol_layer.name.lower() + if name in _VERTEX_COLOR_LAYERS: + break + else: + print(" Baking crappy vertex color lighting...") + bpy.ops.object.plasma_vertexlight_autobake() + + def _find_create_dspan(self, bo, hsgmat, pass_index): location = self._mgr.get_location(bo) if location not in self._dspans: diff --git a/korman/operators/op_lightmap.py b/korman/operators/op_lightmap.py index c7957b7..8047c59 100644 --- a/korman/operators/op_lightmap.py +++ b/korman/operators/op_lightmap.py @@ -16,14 +16,20 @@ import bpy from ..helpers import GoodNeighbor -class _LightmapOperator: +class _LightingOperator: @classmethod def poll(cls, context): if context.object is not None: return context.scene.render.engine == "PLASMA_GAME" + def _hide_textures(self, mesh, toggle): + for mat in mesh.materials: + for tex in mat.texture_slots: + if tex is not None and tex.use: + toggle.track(tex, "use", False) -class LightmapAutobakeOperator(_LightmapOperator, bpy.types.Operator): + +class LightmapAutobakeOperator(_LightingOperator, bpy.types.Operator): bl_idname = "object.plasma_lightmap_autobake" bl_label = "Bake Lightmap" bl_options = {"INTERNAL"} @@ -76,10 +82,9 @@ class LightmapAutobakeOperator(_LightmapOperator, bpy.types.Operator): toggle.track(render, "bake_type", "FULL") toggle.track(render, "use_bake_to_vertex_color", False) - for mat in obj.data.materials: - for tex in mat.texture_slots: - if tex is not None and tex.use: - toggle.track(tex, "use", False) + # If we run a full render with our textures enabled, guess what we will get in our LM? + # Yeah, textures. Mutter mutter mutter. + self._hide_textures(obj.data, toggle) # Now, we *finally* bake the lightmap... # FIXME: Don't bake Plasma RT lights @@ -89,7 +94,7 @@ class LightmapAutobakeOperator(_LightmapOperator, bpy.types.Operator): return {"FINISHED"} -class LightmapAutobakePreviewOperator(_LightmapOperator, bpy.types.Operator): +class LightmapAutobakePreviewOperator(_LightingOperator, bpy.types.Operator): bl_idname = "object.plasma_lightmap_preview" bl_label = "Preview Lightmap" bl_options = {"INTERNAL"} @@ -104,3 +109,35 @@ class LightmapAutobakePreviewOperator(_LightmapOperator, bpy.types.Operator): tex.image = bpy.data.images["{}_LIGHTMAPGEN".format(context.active_object.name)] return {"FINISHED"} + + +class VertexColorLightingOperator(_LightingOperator, bpy.types.Operator): + bl_idname = "object.plasma_vertexlight_autobake" + bl_label = "Bake Vertex Color Lighting" + bl_options = {"INTERNAL"} + + def execute(self, context): + with GoodNeighbor() as toggle: + mesh = context.active_object.data + mesh.update() + + # Find the "autocolor" vertex color layer + autocolor = mesh.vertex_colors.get("autocolor") + if autocolor is None: + mesh.vertex_colors.new("autocolor") + toggle.track(mesh.vertex_colors, "active", autocolor) + + # Prepare to bake... + self._hide_textures(mesh, toggle) + # TODO: don't bake runtime lights + + # Bake settings + render = context.scene.render + toggle.track(render, "bake_type", "FULL") + toggle.track(render, "use_bake_to_vertex_color", True) + + # Bake + bpy.ops.object.bake_image() + + # And done! + return {"FINISHED"}