Disabled external gits
This commit is contained in:
183
cs440-acg/ext/plugin/io_nori.py
Normal file
183
cs440-acg/ext/plugin/io_nori.py
Normal file
@@ -0,0 +1,183 @@
|
||||
|
||||
import math
|
||||
import os
|
||||
import shutil
|
||||
from xml.dom.minidom import Document
|
||||
|
||||
import bpy
|
||||
import bpy_extras
|
||||
from bpy.props import BoolProperty, IntProperty, StringProperty
|
||||
from bpy_extras.io_utils import ExportHelper
|
||||
from mathutils import Matrix
|
||||
|
||||
bl_info = {
|
||||
"name": "Export Nori scenes format",
|
||||
"author": "Adrien Gruson, Delio Vicini, Tizian Zeltner",
|
||||
"version": (0, 1),
|
||||
"blender": (2, 80, 0),
|
||||
"location": "File > Export > Nori exporter (.xml)",
|
||||
"description": "Export Nori scene format (.xml)",
|
||||
"warning": "",
|
||||
"wiki_url": "",
|
||||
"tracker_url": "",
|
||||
"category": "Import-Export"}
|
||||
|
||||
|
||||
class NoriWriter:
|
||||
|
||||
def __init__(self, context, filepath):
|
||||
self.context = context
|
||||
self.filepath = filepath
|
||||
self.working_dir = os.path.dirname(self.filepath)
|
||||
|
||||
def create_xml_element(self, name, attr):
|
||||
el = self.doc.createElement(name)
|
||||
for k, v in attr.items():
|
||||
el.setAttribute(k, v)
|
||||
return el
|
||||
|
||||
def create_xml_entry(self, t, name, value):
|
||||
return self.create_xml_element(t, {"name": name, "value": value})
|
||||
|
||||
def create_xml_transform(self, mat, el=None):
|
||||
transform = self.create_xml_element("transform", {"name": "toWorld"})
|
||||
if(el):
|
||||
transform.appendChild(el)
|
||||
value = ""
|
||||
for j in range(4):
|
||||
for i in range(4):
|
||||
value += str(mat[j][i]) + ","
|
||||
transform.appendChild(self.create_xml_element("matrix", {"value": value[:-1]}))
|
||||
return transform
|
||||
|
||||
def create_xml_mesh_entry(self, filename):
|
||||
meshElement = self.create_xml_element("mesh", {"type": "obj"})
|
||||
meshElement.appendChild(self.create_xml_element("string", {"name": "filename", "value": "meshes/"+filename}))
|
||||
return meshElement
|
||||
|
||||
def write(self):
|
||||
"""Main method to write the blender scene into Nori format"""
|
||||
|
||||
n_samples = 32
|
||||
# create xml document
|
||||
self.doc = Document()
|
||||
self.scene = self.doc.createElement("scene")
|
||||
self.doc.appendChild(self.scene)
|
||||
|
||||
# 1) write integrator configuration
|
||||
self.scene.appendChild(self.create_xml_element("integrator", {"type": "normals"}))
|
||||
|
||||
# 2) write sampler
|
||||
sampler = self.create_xml_element("sampler", {"type": "independent"})
|
||||
sampler.appendChild(self.create_xml_element("integer", {"name": "sampleCount", "value": str(n_samples)}))
|
||||
self.scene.appendChild(sampler)
|
||||
|
||||
# 3) export one camera
|
||||
cameras = [cam for cam in self.context.scene.objects
|
||||
if cam.type in {'CAMERA'}]
|
||||
if(len(cameras) == 0):
|
||||
print("WARN: No camera to export")
|
||||
else:
|
||||
if(len(cameras) > 1):
|
||||
print("WARN: Does not handle multiple camera, only export the active one")
|
||||
self.scene.appendChild(self.write_camera(self.context.scene.camera)) # export the active one
|
||||
|
||||
# 4) export all meshes
|
||||
if not os.path.exists(self.working_dir + "/meshes"):
|
||||
os.makedirs(self.working_dir + "/meshes")
|
||||
|
||||
meshes = [obj for obj in self.context.scene.objects
|
||||
if obj.type in {'MESH', 'FONT', 'SURFACE', 'META'}]
|
||||
print(meshes)
|
||||
for mesh in meshes:
|
||||
self.write_mesh(mesh)
|
||||
|
||||
# 6) write the xml file
|
||||
self.doc.writexml(open(self.filepath, "w"), "", "\t", "\n")
|
||||
|
||||
def write_camera(self, cam):
|
||||
"""convert the selected camera (cam) into xml format"""
|
||||
camera = self.create_xml_element("camera", {"type": "perspective"})
|
||||
camera.appendChild(self.create_xml_entry("float", "fov", str(cam.data.angle * 180 / math.pi)))
|
||||
camera.appendChild(self.create_xml_entry("float", "nearClip", str(cam.data.clip_start)))
|
||||
camera.appendChild(self.create_xml_entry("float", "farClip", str(cam.data.clip_end)))
|
||||
percent = self.context.scene.render.resolution_percentage / 100.0
|
||||
camera.appendChild(self.create_xml_entry("integer", "width", str(
|
||||
int(self.context.scene.render.resolution_x * percent))))
|
||||
camera.appendChild(self.create_xml_entry("integer", "height", str(
|
||||
int(self.context.scene.render.resolution_y * percent))))
|
||||
|
||||
mat = cam.matrix_world
|
||||
|
||||
# Conversion to Y-up coordinate system
|
||||
coord_transf = bpy_extras.io_utils.axis_conversion(
|
||||
from_forward='Y', from_up='Z', to_forward='-Z', to_up='Y').to_4x4()
|
||||
mat = coord_transf @ mat
|
||||
pos = mat.translation
|
||||
# Nori's camera needs this these coordinates to be flipped
|
||||
m = Matrix([[-1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 0]])
|
||||
t = mat.to_3x3() @ m.to_3x3()
|
||||
mat = Matrix([[t[0][0], t[0][1], t[0][2], pos[0]],
|
||||
[t[1][0], t[1][1], t[1][2], pos[1]],
|
||||
[t[2][0], t[2][1], t[2][2], pos[2]],
|
||||
[0, 0, 0, 1]])
|
||||
trans = self.create_xml_transform(mat)
|
||||
camera.appendChild(trans)
|
||||
return camera
|
||||
|
||||
def write_mesh(self, mesh):
|
||||
viewport_selection = self.context.selected_objects
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
|
||||
obj_name = mesh.name + ".obj"
|
||||
obj_path = os.path.join(self.working_dir, 'meshes', obj_name)
|
||||
mesh.select_set(True)
|
||||
bpy.ops.export_scene.obj(filepath=obj_path, check_existing=False,
|
||||
use_selection=True, use_edges=False, use_smooth_groups=False,
|
||||
use_materials=False, use_triangles=True, use_mesh_modifiers=True)
|
||||
mesh.select_set(False)
|
||||
|
||||
# Add the corresponding entry to the xml
|
||||
mesh_element = self.create_xml_mesh_entry(obj_name)
|
||||
# We currently just export a default material, a more complex material conversion
|
||||
# could be implemented following: http://tinyurl.com/nnhxwuh
|
||||
bsdf_element = self.create_xml_element("bsdf", {"type": "diffuse"})
|
||||
bsdf_element.appendChild(self.create_xml_entry("color", "albedo", "0.75,0.75,0.75"))
|
||||
mesh_element.appendChild(bsdf_element)
|
||||
self.scene.appendChild(mesh_element)
|
||||
|
||||
for ob in viewport_selection:
|
||||
ob.select_set(True)
|
||||
|
||||
|
||||
class NoriExporter(bpy.types.Operator, ExportHelper):
|
||||
"""Export a blender scene into Nori scene format"""
|
||||
|
||||
# add to menu
|
||||
bl_idname = "export_scene.nori"
|
||||
bl_label = "Export Nori scene"
|
||||
|
||||
filename_ext = ".xml"
|
||||
filter_glob: StringProperty(default="*.xml", options={'HIDDEN'})
|
||||
|
||||
def execute(self, context):
|
||||
nori = NoriWriter(context, self.filepath)
|
||||
nori.write()
|
||||
return {'FINISHED'}
|
||||
|
||||
def menu_func_export(self, context):
|
||||
self.layout.operator(NoriExporter.bl_idname, text="Export Nori scene...")
|
||||
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(NoriExporter)
|
||||
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_class(NoriExporter)
|
||||
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
22
cs440-acg/ext/plugin/readme.md
Normal file
22
cs440-acg/ext/plugin/readme.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Nori Exporter for Blender
|
||||
by Delio Vicini and Tizian Zeltner, based on Adrien Gruson's original exporter.
|
||||
|
||||
## Installation
|
||||
|
||||
First, you must download a fairly recent version of Blender (the plugin is tested for versions >= 2.8). You can download blender from https://www.blender.org or using your system's package manager.
|
||||
|
||||
To install the plugin, open Blender and go to "Edit -> Preferences... -> Add-ons" and click on "Install...".
|
||||
This should open a file browser in which you can navigate to the `io_nori.py` file and select it.
|
||||
This will copy the exporter script to Blender's plugin directory.
|
||||
After the plugin is installed, it has to be activated by clicking the checkbox next to it in the Add-ons menu.
|
||||
|
||||
## Usage
|
||||
|
||||
Once the plugin is installed, scenes can be expored by clicking "File -> Export -> Export Nori Scene..."
|
||||
|
||||
The plugin exports all objects in the scene as separate OBJ FIles. It then generates a Nori XML file with the scene's camera, a basic integrator and XML entries to reference all the exported meshes.
|
||||
|
||||
## Limitations
|
||||
|
||||
The plugin does not support exporting BSDFs and emitters. It will just assign a default BSDF to all shapes. It further exports each mesh as is.
|
||||
This means that if you have a mesh with multiple materials in Blender, you will have to split it manually into separate submeshes before exporting (one for each material). This can be done by selecting the mesh with multiple materials, going to edit mode (tab) then selecting all vertices (A) and clicking "separate" (P) and then "by material". This will separate the mesh into meshes with one material each. After exporting, each of these meshes will have a separate entry in the scene's XML file and can therefore be assigned a different BSDF.
|
Reference in New Issue
Block a user