Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates & Bugfixes #4

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ You'll need:
- Unity 2021.3.4.f1

- gltfast package (by name, `com.unity.cloud.gltfast`)
- Unity2Vircadia package [**(this repo)**](https://github.com/vircadia/unity-to-vircadia-pipeline/raw/master/dist/Unity2Vircadia_v1.0.1.unitypackage)
- Unity2Vircadia package [**(this repo)**](https://github.com/vircadia/unity-to-vircadia-pipeline/raw/master/dist/Unity2Vircadia_v1.0.2.unitypackage)

- Blender 4.0.2 or newer

- UnityToVircadia Blender addon [**(this repo)**](https://github.com/vircadia/unity-to-vircadia-pipeline/raw/master/dist/UnityToVircadia_BlenderAddon_v1.0.1.zip)
- UnityToVircadia Blender addon [**(this repo)**](https://github.com/vircadia/unity-to-vircadia-pipeline/raw/master/dist/UnityToVircadia_BlenderAddon_v1.0.2.zip)

### Step 1. Unity

Expand All @@ -28,11 +28,11 @@ You'll need:
### Step 2. Blender

1. Start a new scene and delete any default content (cube, camera, light, etc.)
2. Install the `UnityToVircadia` Blender plugin by going to "Edit/Preferences," select the "Add-on" tab and press the "Install" button. Select the `UnityToVircadia.zip` file and Press "Install Add-on". Press the check checkbox to enable the plugin. This will create a `UnityToVircadia` tab on the N panel.
2. Install the `UnityToVircadia` Blender plugin by going to "Edit/Preferences," select the "Add-on" tab and press the "Install" button. Select the `UnityToVircadia_BlenderAddon_v1.0.2.zip` file and Press "Install Add-on". Press the check checkbox to enable the plugin. This will create a `UnityToVircadia` tab on the N panel.
3. Open the `UnityToVircadia` tab on the N Panel
4. Select "Import glTF 2.0" and Import the `.glb` file you exported from Unity
5. Press "Import Lightmap Info" and a dialog will open. Select the "LightmapInfo.txt" file from the folder we created earlier. This will generate a mesh container for the lightmaps called "vircadia_lightmapData." \* Note: At the moment you will not see these lightmaps until export. container will be removed automatically in Vircadia-web
6. Press "Adjust Shaders" to correct material properties and repeats.
6. Press "Adjust Shaders" and a dialog will open. Select the "MaterialsCheckReport.txt" file to correct material properties and repeats.
7. Press "Preview Lightmaps" to preview lightmaps. You can then "Clear Lightmaps" to revert to your previous state if you choose.
8. Press the "Export glTF 2.0 button to export your model. Set your format to `glTF Binary (.glb)`. From within the export dialog, open the "include" tab and be sure "Custom Properties" is selected. We recommend setting your Material Image format to `Webp` and checking "Create Webp". Compression can be used as well to lower file size, but minor artifacts may appear. Export `glTF 2.0`.

Expand Down
31 changes: 29 additions & 2 deletions blender/UnityToVircadia/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,29 @@ def execute(self, context):
context.scene.lightmaps_applied = not context.scene.lightmaps_applied
return {'FINISHED'}

class AdjustShadersOperator(bpy.types.Operator):
"""Adjust Shaders"""
bl_idname = "object.adjust_shaders"
bl_label = "Adjust Shaders"
bl_description = "Adjust shaders based on the MaterialsCheckReport.txt file"

def execute(self, context):
bpy.ops.object.adjust_shaders('INVOKE_DEFAULT')
return {'FINISHED'}

class ExportGLTFOperator(bpy.types.Operator):
"""Export glTF 2.0"""
bl_idname = "export_scene.unity_to_vircadia_gltf"
bl_label = "Export glTF 2.0"
bl_description = "Export the scene as glTF 2.0 after clearing lightmaps if necessary"

def execute(self, context):
if context.scene.lightmaps_applied:
bpy.ops.object.toggle_lightmaps()

bpy.ops.export_scene.gltf('INVOKE_DEFAULT')
return {'FINISHED'}

class UnityToVircadiaPanel(bpy.types.Panel):
bl_label = "UnityToVircadia"
bl_idname = "OBJECT_PT_UnityToVircadia"
Expand All @@ -45,18 +68,20 @@ def draw(self, context):
layout.operator("import_scene.gltf", text="Import glTF 2.0")
# layout.operator("object.correct_scale") # TODO later
layout.operator("import.lightmap_info")
layout.operator("object.adjust_shaders")
layout.operator("object.adjust_shaders", text="Adjust Shaders")

# Toggle button for applying/clearing lightmaps
if context.scene.lightmaps_applied:
layout.operator("object.toggle_lightmaps", text="Clear Lightmaps")
else:
layout.operator("object.toggle_lightmaps", text="Preview Lightmaps")

layout.operator("export_scene.gltf", text="Export glTF 2.0")
layout.operator("export_scene.unity_to_vircadia_gltf", text="Export glTF 2.0")

def register():
bpy.utils.register_class(ToggleLightmapsOperator)
bpy.utils.register_class(AdjustShadersOperator)
bpy.utils.register_class(ExportGLTFOperator)
bpy.utils.register_class(UnityToVircadiaPanel)
bpy.utils.register_class(makeObjectsSingleUserFixScale.CorrectScale)
bpy.utils.register_class(getLightmapInformation.GetLightmapInfo)
Expand All @@ -65,6 +90,8 @@ def register():

def unregister():
bpy.utils.unregister_class(ToggleLightmapsOperator)
bpy.utils.unregister_class(AdjustShadersOperator)
bpy.utils.unregister_class(ExportGLTFOperator)
bpy.utils.unregister_class(UnityToVircadiaPanel)
bpy.utils.unregister_class(makeObjectsSingleUserFixScale.CorrectScale)
bpy.utils.unregister_class(getLightmapInformation.GetLightmapInfo)
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
98 changes: 83 additions & 15 deletions blender/UnityToVircadia/fixMappingNodesRemoveExtras.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,77 @@
import bpy
import os
import re

def connect_mapping_to_textures_and_adjust_gloss_and_spec(material):
def read_material_tiling_from_file(file_path):
material_tiling = {}
with open(file_path, 'r') as file:
lines = file.readlines()
current_material = None
for line in lines:
line = line.strip()
if line.startswith("Material:"):
current_material = line.split(": ")[1]
material_tiling[current_material] = {}
elif current_material and line:
if line.startswith("Tiling X:"):
material_tiling[current_material]['x'] = float(line.split(": ")[1])
elif line.startswith("Tiling Y:"):
material_tiling[current_material]['y'] = float(line.split(": ")[1])
return material_tiling

def remove_numbered_suffix(name):
return re.sub(r'\.\d+$', '', name)

def connect_mapping_to_textures_and_adjust_gloss_and_spec(material, material_tiling):
if not material.node_tree:
return

nodes = material.node_tree.nodes
mapping_node = None
target_texture_node = None # This will be used for both gloss and spec textures
links = material.node_tree.links

# Find the mapping node
for node in nodes:
if node.type == 'MAPPING':
mapping_node = node
# Find all mapping nodes in the material
mapping_nodes = [node for node in nodes if node.type == 'MAPPING']

# Create a new mapping node if none exist
if not mapping_nodes:
mapping_node = nodes.new(type='ShaderNodeMapping')
mapping_nodes.append(mapping_node)

for mapping_node in mapping_nodes:
# Adjust the scaling of the mapping node based on the material tiling information
material_name_without_suffix = remove_numbered_suffix(material.name)
for mat_name, tiling_info in material_tiling.items():
if remove_numbered_suffix(mat_name) == material_name_without_suffix:
mapping_node.inputs['Scale'].default_value = (
tiling_info['x'],
tiling_info['y'],
1.0 # Set the Z-scale to 1
)
mapping_node.inputs['Scale'].keyframe_insert(data_path='default_value')
break

# Create a new texture coordinate node if it doesn't exist
if 'Texture Coordinate' not in nodes:
tex_coord_node = nodes.new(type='ShaderNodeTexCoord')
else:
tex_coord_node = nodes['Texture Coordinate']

for mapping_node in mapping_nodes:
# Connect the texture coordinate node to the mapping node
if not any(link.from_node == tex_coord_node and link.to_node == mapping_node for link in links):
links.new(tex_coord_node.outputs['UV'], mapping_node.inputs['Vector'])

# Connect the mapping node to all image texture nodes
if mapping_node:
# Connect the mapping node to all texture nodes
for node in nodes:
if node.type == 'TEX_IMAGE':
material.node_tree.links.new(mapping_node.outputs['Vector'], node.inputs['Vector'])
if not any(link.from_node == mapping_node and link.to_socket == node.inputs['Vector'] for link in links):
links.new(mapping_node.outputs['Vector'], node.inputs['Vector'])

# Update the node tree to apply the changes
material.node_tree.nodes.update()

# Find the texture node with "GLOSS" or "SPEC" in its name
target_texture_node = None
for node in nodes:
if node.type == 'TEX_IMAGE' and ("gloss" in node.image.name.lower() or "spec" in node.image.name.lower()):
target_texture_node = node
Expand All @@ -37,7 +89,7 @@ def connect_mapping_to_textures_and_adjust_gloss_and_spec(material):

# Remove Roughness Factor node if connected to Separate Color node
if roughness_factor_node and separate_color_node:
for link in material.node_tree.links:
for link in links:
if link.from_node == separate_color_node and link.to_node == roughness_factor_node:
nodes.remove(roughness_factor_node)
break
Expand All @@ -49,18 +101,34 @@ def connect_mapping_to_textures_and_adjust_gloss_and_spec(material):
# Find the Principled BSDF node and connect gloss/spec texture
for node in nodes:
if node.type == 'BSDF_PRINCIPLED':
material.node_tree.links.new(target_texture_node.outputs['Color'], node.inputs['Specular IOR Level'])
if not any(link.from_node == target_texture_node and link.to_socket == node.inputs['Specular IOR Level'] for link in links):
links.new(target_texture_node.outputs['Color'], node.inputs['Specular IOR Level'])

def adjust_shaders(context, file_path):
material_tiling = read_material_tiling_from_file(file_path)

def adjust_shaders():
# Iterate over all materials in the scene
for material in bpy.data.materials:
connect_mapping_to_textures_and_adjust_gloss_and_spec(material)
connect_mapping_to_textures_and_adjust_gloss_and_spec(material, material_tiling)

class AdjustShaders(bpy.types.Operator):
"""Adjust Shaders"""
bl_idname = "object.adjust_shaders"
bl_label = "Adjust Shaders"

filepath: bpy.props.StringProperty(subtype="FILE_PATH")

def execute(self, context):
adjust_shaders()
adjust_shaders(context, self.filepath)
return {'FINISHED'}

def invoke(self, context, event):
self.filepath = "MaterialsCheckReport.txt"
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}

def register():
bpy.utils.register_class(AdjustShaders)

def unregister():
bpy.utils.unregister_class(AdjustShaders)
30 changes: 21 additions & 9 deletions blender/UnityToVircadia/getLightmapInformation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import bpy
import os
import re
import random
import string

def load_lightmap_info(filepath):
with open(filepath, 'r') as file:
Expand All @@ -16,25 +19,32 @@ def parse_info(content):
if line.startswith('Lightmap Texture:'):
obj_info['lightmap_texture'] = line.split(': ')[1].strip()
elif line.startswith('Tiling X:'):
obj_info['tiling_x'] = float(line.split(': ')[1].strip())
obj_info['tiling_x'] = float(line.split(': ')[1].strip().replace(',', '.'))
elif line.startswith('Tiling Y:'):
obj_info['tiling_y'] = float(line.split(': ')[1].strip())
obj_info['tiling_y'] = float(line.split(': ')[1].strip().replace(',', '.'))
elif line.startswith('Offset X:'):
obj_info['offset_x'] = float(line.split(': ')[1].strip())
obj_info['offset_x'] = float(line.split(': ')[1].strip().replace(',', '.'))
elif line.startswith('Offset Y:'):
obj_info['offset_y'] = float(line.split(': ')[1].strip())
obj_info['offset_y'] = float(line.split(': ')[1].strip().replace(',', '.'))
elif line.startswith('Path:'):
obj_info['path'] = line.split(': ')[1].strip()
if 'lightmap_texture' in obj_info:
info.append(obj_info)
return info

def generate_random_string(length):
characters = string.ascii_letters + string.digits
return ''.join(random.choice(characters) for _ in range(length))

def create_materials(obj_info):
materials = []
for info in obj_info:
# Generate a random string of 16 characters
random_string = generate_random_string(16)

# Remove the file extension for the lightmap texture name
lightmap_texture_name_without_extension = os.path.splitext(info['lightmap_texture'])[0]
mat_name = f"vircadia_lightmapData_{lightmap_texture_name_without_extension}"
mat_name = f"vircadia_lightmapData_{random_string}"

if mat_name in bpy.data.materials:
mat = bpy.data.materials[mat_name]
Expand All @@ -46,12 +56,12 @@ def create_materials(obj_info):
tex_image.label = "BASE COLOR" # Set the label to "BASE COLOR"

image_path = os.path.join(info['path'], info['lightmap_texture'])
image_name = os.path.splitext(os.path.basename(image_path))[0] # Remove the extension from the image name
image_name = random_string # Use the random string as the image name

if image_name in bpy.data.images:
tex_image.image = bpy.data.images[image_name]
else:
# Load the image and remove the extension from its name in Blender
# Load the image and set its name to the random string
loaded_image = bpy.data.images.load(image_path)
loaded_image.name = image_name
tex_image.image = loaded_image
Expand Down Expand Up @@ -97,7 +107,8 @@ def add_custom_properties(obj_info, materials):
for info in obj_info:
obj = bpy.data.objects.get(info['name'])
if obj:
mat_name = f"vircadia_lightmapData_{os.path.splitext(info['lightmap_texture'])[0]}"
mat = materials[obj_info.index(info)]
mat_name = mat.name
obj['vircadia_lightmap'] = mat_name
obj['vircadia_lightmap_texcoord'] = 1

Expand Down Expand Up @@ -131,6 +142,7 @@ def execute(self, context):
return {'FINISHED'}

def invoke(self, context, event):
self.filepath = "LightmapInfo.txt" # Set the default file name
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}

Expand All @@ -141,4 +153,4 @@ def unregister():
bpy.utils.unregister_class(GetLightmapInfo)

if __name__ == "__main__":
register()
register()
Binary file removed dist/Unity2Vircadia_v1.0.1.unitypackage
Binary file not shown.
Binary file added dist/Unity2Vircadia_v1.0.2.unitypackage
Binary file not shown.
Binary file removed dist/UnityToVircadia_BlenderAddon_v1.0.1.zip
Binary file not shown.
Binary file added dist/UnityToVircadia_BlenderAddon_v1.0.2.zip
Binary file not shown.
Loading