Timestamps:
0:00 [Intro] Introduction to scope of tutorial and outline of workflow
0:31 [Rhino] The logic of the layer hierarchy
1:21 [Rhino] For simplicity, glass panes should be singular planes per window
1:31 [Rhino] Converting the Brep geometries to meshes
3:13 [Rhino] Exporting the meshes as an OBJ file with proper export settings
5:20 [Blender] Opening the default start-up scene in Blender, and deleting everything in it
6:24 [Blender] Importing the exported OBJ, with the Split by Group option active
6:54 [Blender] You can use any unit scale in Blender
7:37 [Blender] Preparing your imported model with the included Blender Python script
8:19 [Blender] Correctly scaling your object
9:28 [Blender] Optionally adjusting your Start and End Clipping distances for the viewport
10:11 [Blender] Applying all transforms for the imported object
10:35 [Blender] Navigating in the viewport, and creating a camera aligned to the viewport perspective
12:11 [Blender] Adjusting camera settings, rotating and translating (moving) the camera
16:16 [Blender] Test rendering, with EEVEE and Cycles as Render Engine, including creating a point light and changing noise thresholds
21:09 [Blender] For iterative testing, 8-bit JPEG is fine, but for final rendering, save to a 16-bit file format for better quality
22:02 [Blender] Introduction to the vertices normal directions' influence on how the surface is interpreted by the render engine
23:18 [Blender] Defining sharp edges for normal smoothing, and seam edges for UV island unwrapping
25:34 [Blender] Use the defined sharp edges, together with Auto smoothing, to recalculate the normals on a decimated version of the mesh
30:13 [Blender] To make UV unwrapping more efficient, it may be good to apply the decimation
31:22 [Blender] Organizing objects into Collections, for easy toggling of visibility
31:51 [Blender] UV unwrapping within a paradigm of real-world scale referencing and multiple texture sets
37:18 [Blender] Scaling all UV islands so as to match the scale of the reference plane
41:28 [Blender] Fixing erroneously unwrapped faces, utilizing the Smart UV Project feature for a quick result
44:01 [Resources] Acquiring material textures, published with a CC0 Public Domain licence
44:57 [PolyHaven] Downloading a relevant selection of image textures from a material texture set
47:33 [Blender] Authoring a texture-based material shader template with the Node Editor
55:07 [Blender] Changing the assigned textures for all individual material slots
57:28 [Blender] Authoring a glass material shader
58:13 [Blender] Manipulating UV islands to achieve better alignment with an assigned texture
1:01:07 [Blender] Customizing the node adjustments for the materials, so as to achieve their intended look
1:04:12 [PolyHaven] Downloading an HDRI environment texture, for daylighting the model
1:04:38 [Blender] Refining the World shader node setup, assigning your HDRI texture and rotating it
1:07:38 [Blender] Penultimate render (with a too high noise threshold for an adequate final result)
1:08:06 [Blender] Final render
1:09:54 [Post-mortem] Comparing the render outputs
1:10:35 [Outro] Conclusion of the tutorial
Links to resources:
https://www.blender.org/
https://ambientcg.com/
https://polyhaven.com/
Link to project files for reference:
https://drive.google.com/drive/folder...
Blender Python script to assign predefined material slots for imported mesh:
"""Initially, reduce the complexity of the object names (requires "M_" layer prefix in Rhino):"""
import bpy
for obj in bpy.context.scene.objects:
obj.name = "M_" + obj.name.split("M_")[1]
"""Then, join objects with same layer name:"""
unique_names = set([obj.name.split(".")[0] for obj in bpy.context.view_layer.objects if obj.type == 'MESH'])
for obj_name in unique_names:
bpy.ops.object.select_all(action='DESELECT')
for obj in bpy.context.view_layer.objects:
if obj.name.split(".")[0] == obj_name:
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
if len(bpy.context.selected_objects) != 1:
bpy.ops.object.join()
"""For any joined object, make sure that the name is the suffixless one:"""
for obj in bpy.context.scene.objects:
obj.name = obj.name.split(".")[0]
"""Create individual material slots for the objects:"""
for obj in bpy.context.scene.objects:
material_slot_name = obj.name
bpy.data.materials.new(name=material_slot_name)
obj.data.materials.append(bpy.data.materials[material_slot_name])
"""Join all the objects:"""
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.join()
"""Rename the joined object:"""
for obj in bpy.context.scene.objects:
obj.name = "3DModel_WithMaterialSlots"
obj.data.name = "ImportedModel"
"""(End of script.)"""
This tutorial demonstrates to KTH Architecture students how to export their models from Rhino and importing them in Blender for rendering.