Projet

Général

Profil

Raydium Blender » AddOn_Test.py

version du script non final, manque importation, génération du maillage uv (manuel pour l'instant) - Anonyme, 12/11/2021 17:01

 
import bpy
import os
import time

#bpy.data.meshes.remove(my_mesh)
#bpy.ops.object.convert(target='MESH',keep_original=True)

active_object=None
selected_objects=[]
active_object_mode=''
temp_object=None
all_scene=True

#texture swap count
texture_swap_count=0
current_texture_list=[]
exported_mesh_list=[]

def object_deselect_all():
bpy.ops.object.select_all(action='DESELECT')
def object_select(obj):
object_deselect_all()
bpy.ops.object.select_pattern(pattern=obj.name)

def object_select_list(lobj):
object_deselect_all()
for o in lobj:
bpy.ops.object.select_pattern(pattern=o.name,extend=True)
def object_active(obj):
bpy.context.view_layer.objects.active = obj

def object_select_and_active(obj):
object_deselect_all()
object_select(obj)
object_active(obj)

def save_state(context):
global active_object,selected_objects,active_object_mode
print ("Saving State")
active_object=context.active_object
if active_object!=None:
active_object_mode = context.object.mode
#Switch to object mode as default
bpy.ops.object.mode_set(mode='OBJECT')
selected_objects = context.selected_objects

def restore_state(context):
global selected_objects,active_object,active_object_mode
print ("Restoring State.")

#Switch to object mode
ob=context.object
if ob!=None:
if ob.mode=='EDIT':
bpy.ops.object.mode_set(mode='OBJECT')
if active_object!=None:
object_active(active_object)

object_select_list(selected_objects)
if active_object_mode=='EDIT':
bpy.ops.object.mode_set(mode='EDIT')

def convert_to_mesh(obj):
global temp_object
print ("Creating temporary working Mesh for {}.".format(obj))
object_select_and_active(obj)
if obj.type=='MESH':
bpy.ops.object.duplicate()
else:
bpy.ops.object.convert(target='MESH',keep_original=True)
if (len(bpy.context.selected_objects)!=1):
raise ("Should never happen ")
temp_object=bpy.context.selected_objects[0]
object_active(temp_object)
for modifier in temp_object.modifiers:
print ("Applying modifier %s"%modifier.name)
try:
bpy.ops.object.modifier_apply(modifier=modifier.name)
except:
print ("Error applying modifier")
pass
# m=obj.to_mesh(bpy.context.scene,True,"RENDER")
# bpy.ops.object.add(type='MESH')
# temp_object=bpy.context.active_object
# temp_object.data=m

temp_object.name = "Mesh_"+obj.name
return temp_object

def convert_quad_to_tri(obj):
print ("Triangulate Faces with pattern")
object_select_and_active(obj)
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.reveal()
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.quads_convert_to_tris()
bpy.ops.object.mode_set(mode='OBJECT')

def export_vertice(vert,face,me,obj,f):
global all_scene
if all_scene:
rot = obj.matrix_world
pos = obj.location
vloc,qrot,vscale = rot.decompose()
v=me.vertices[vert].co.copy()
if face.use_smooth:
n=me.vertices[vert].normal.copy()
else:
n=face.normal.copy()
if all_scene:
v = (rot * v)
n = qrot * n

f.write("%+0f %+0f %+0f"%(v[0],v[1],v[2]))
f.write(" %+0f %+0f %+0f"%(n[0],n[1],n[2]))

def build_vertex_color_list(i_vert,i_face,me):
tex_list=[]
for vcol in me.vertex_colors:
if i_vert==0:
col = vcol.data[i_face].color1
if i_vert==1:
col = vcol.data[i_face].color2
if i_vert==2:
col = vcol.data[i_face].color3
r=col[0]
g=col[1]
b=col[2]
texture=("rgb(%3.2f,%3.2f,%3.2f)"%(r,g,b))
tex_list.append({'u':0.0,'v':0.0,'tex':texture})

return tex_list

def build_uv_texture_list(i_vert,i_face,me,obj):
global texture_swap_count,current_texture_list
tex_list=[]
tex_name_list=[]
#champs image : materials.materials[0].node_tree.nodes['Texture image'].image.depth
### CHANGEMENT TEST 12/11 #####
me_img = me.materials[0].node_tree.nodes['Texture image'].image
for uvt in me.uv_layers:
#if uvt.data[i_face].image!=None:
if me_img==None:
if i_vert==0:
#uv=uvt.data[i_face].uv1
uv=uvt.data[i_face].uv[1]
if i_vert==1:
#uv=uvt.data[i_face].uv2
uv=uvt.data[i_face].uv[2]
if i_vert==2:
#uv=uvt.data[i_face].uv3
uv=uvt.data[i_face].uv[3]
#texture=os.path.basename(uvt.data[i_face].image.filepath)
texture=os.path.basename(me_img.filepath)
#name=uvt.data[i_face].image.name
name=me_img.name
if (tex_name_list.count(name)==0):
tex_name_list.append(name)
#if not(os.path.isfile(texture)) or uvt.data[i_face].image.file_format!='TARGA':
if not(os.path.isfile(texture)) or me_img.file_format!='TARGA':
print ("New Image Texture",texture)
image=me_img
image.file_format='TARGA'
if image.filepath:
image.filepath_raw=os.path.basename(image.filepath).rsplit('.',1)[0]+'.tga'
else:
image.filepath=image.name+".tga"
try:
print ("Sauvegarde image ",image.filepath)
image.save()
except:
pass
texture=os.path.basename(me_img.filepath)
map=uvt.data[i_face].image.mapping;
tex_list.append({'u':uv[0],'v':uv[1],'tex':texture,'map':map});

for i in range(len(tex_name_list)):
try:
if (tex_name_list[i]!=current_texture_list[i]):
current_texture_list[i]=tex_name_list[i]
texture_swap_count+=1
except:
current_texture_list.append(tex_name_list[i])
texture_swap_count+=1
return tex_list

def selected(faces):

bpy.ops.object.mode_set(mode='OBJECT')
n=0
for face in faces:
if face.select:
n=n+1
bpy.ops.object.mode_set(mode='EDIT')
return n

def unselect_unhide():
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.reveal()
bpy.ops.object.mode_set(mode='OBJECT')
return

def select_same_image():
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_similar(type='IMAGE')
bpy.ops.object.mode_set(mode='OBJECT')
return

def hide_unselected():
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.hide(unselected=True)
bpy.ops.object.mode_set(mode='OBJECT')

def export_mesh(obj,f):
#me=obj.data

me=obj.to_mesh()
#me.update(calc_tessface=True)
me.calc_loop_triangles()

#nf=len(me.tessfaces)
nf=len(me.loop_triangles)
lper=-11
print ("Exporting mesh %s, %d faces, %d vertices"%(obj.data.name,len(me.loop_triangles),len(me.vertices)))

cpt=0
# for i_tface,tface in enumerate(me.faces):
#depth, texture name, texture mode, indice
faces_array=[[0,'',i] for i in range(nf)]

print ("Working on %d faces" % len(me.loop_triangles))
print ("Building faces texture list")
#champs image : materials.materials[0].node_tree.nodes['Texture image'].image.depth
for i,face in enumerate(me.loop_triangles):
me_images = me.materials[0].node_tree.nodes["Texture image"].image
if me_images!=None:
faces_array[face.index][1]+='|'+me_images.name
faces_array[face.index][0]=me_images.depth # used to set rbga texture at the end of file

##### CHANGEMENT TEST 12/11 ######
# for i,face in enumerate(me.loop_triangles):
# #for uvt in me.tessface_uv_textures:
# for uvt in me.uv_layers:
# if uvt.data[i].image!=None:
# faces_array[face.index][1]+='|'+uvt.data[i].image.name
# faces_array[face.index][0]=uvt.data[i].image.depth # used to set rbga texture at the end of file
for i,face in enumerate(me.loop_triangles):
#for vc in me.tessface_vertex_colors:
for vc in me.vertex_colors:
if vc.data[i].color1!=None:
texture=build_vertex_color_list(0,i,me)
for t in texture:
faces_array[face.index][1]+='|'+t['tex']
print ("Sorting texture list")
faces_array.sort()

print ("Exporting sorted list")
#for i_face,face in enumerate(me.faces):
for fa in faces_array:
face = me.loop_triangles[fa[2]]
i_face = face.index
per=((cpt+1)*100)/nf
if per>lper+10:
print("%d%% (%d)"%(per,cpt))
lper=per
#print (i_face)
verts = face.vertices
for i_vert,vert in enumerate(verts):
export_vertice(vert,face,me,obj,f)

tex_list=build_uv_texture_list(i_vert,i_face,me,obj)
if (len(tex_list)==0):
tex_list+=build_vertex_color_list(i_vert,i_face,me)
if len(tex_list)==0:
tex_list.append({'u':0.0,'v':0.0,'tex':'rgb(0.6,0.6,0.6)'})
tex=tex_list[0]
f.write(" %f %f %s"%(tex['u'],tex['v'],tex['tex']))
ref_tex=tex_list[0] # used to find special multi texture without uv coordinates
tex_list.remove(tex)
for tex in tex_list:
#ugly way to specify a texture without inherited uv mapping
if (tex['map']=='UV'):
if (abs(tex['u']-50.0*ref_tex['u'])<1e-5) and (abs(tex['v']-50.0*ref_tex['v'])<1e-5):
f.write(";%s"%(tex['tex']))
else:
f.write(";%f|%f|%s"%(tex['u'],tex['v'],tex['tex']))
else:
f.write("#%s"%(tex['tex']))

f.write("\n")
cpt+=1
print ("%d%% (%d)"%(per,nf))
#bpy.data.meshes.remove(me)

bl_info = {
"name": "TRI FILES IMPORT EXPORT",
"blender": (2, 80, 0),
"category": "Import-Export",
}

def write_some_data(context, filepath, save_elements,save_position):
global all_scene,texture_swap_count
global exported_mesh_list

exported_mesh_list=[]
pos_file_name = os.path.basename(filepath) + ".pos"

print ("Using file name: %s Working directory: %s"%(os.path.basename(filepath),os.path.dirname(filepath)))
print ("Changing working directory to %s"%os.path.dirname(filepath))
os.chdir(os.path.dirname(filepath))
if save_elements:
print ("Saving Each element in its own file according to mesh name.")
all_scene=False
else:
all_scene=True
if save_position:
print ("Saving elements positions in %s file."%pos_file_name)
f_pos=open(pos_file_name,'w')
save_state(context)
if len(context.selected_objects)==0:
bpy.ops.object.select_all(action='SELECT')
print ("No object selected, selecting all objects.")

selected_objects = context.selected_objects
texture_swap_count=0
print ("%d objects to export."%(len(selected_objects)))
big_wobj=None
for i_obj,obj in enumerate(selected_objects):
try:
mesh_name=obj.data.name
except:
mesh_name=""
if save_position:
n1=obj.name.replace(" ","_")
n2=mesh_name.replace(" ","_")
f_pos.write("%32.32s %32.32s %f %f %f %f %f %f\n"%(n1,n2,obj.location[0],obj.location[1],obj.location[2],obj.rotation_euler[0],obj.rotation_euler[1],obj.rotation_euler[2]))
if obj.type=='LAMP' or obj.type=='CAMERA' or obj.type=='CURVE':
print ("Skipping Export of object {}.".format(obj))
continue

#mesh_name=obj.data.name
if mesh_name[0]=='.':
print ("Not exporting %s hidden mesh (begin with a . "%mesh_name)
continue
if not (mesh_name in exported_mesh_list):
exported_mesh_list.append(mesh_name)
else:
print ("Skipping %s already exported"%mesh_name)
continue
#deselect_all()
#bpy.ops.object.select_name(name=obj.name)
#bpy.ops.object.select_pattern(pattern=obj.name)
object_select(obj)
print ("Exporting {} / {} Type:{}".format(obj,obj.name,obj.type))
wobj = convert_to_mesh(obj)
convert_quad_to_tri(wobj)
if all_scene:
if big_wobj==None:
print("Creating One big object/mesh for all scene.\n")
big_wobj=wobj
big_wobj.name="Export_Object"
big_wobj.data.name="Export_Mesh"
else:
print ("Joining %s and %s\n"%(big_wobj.name,wobj.name))
object_select_and_active(big_wobj)
bpy.ops.object.select_pattern(pattern=wobj.name,extend=True)
bpy.ops.object.join()
if not all_scene:
file_name=mesh_name
file_name+='.tri'
print ("Opening %s for writing."%file_name)
f =open(file_name,'w')
print ("Version 1 tri file")
f.write("1\n")
export_mesh(wobj,f)
print("Closing %s file."%file_name)
f.close()
print ("Removing temporary object.")
object_select_and_active(wobj)
bpy.ops.object.delete()

if all_scene:
print ("Saving all scene in one file.")
print ("Opening %s for writing."%os.path.basename(filepath))
f =open(os.path.basename(filepath),'w')
print ("Version 1 tri file")
f.write("1\n")
export_mesh(big_wobj,f);
print ("Closing tri file.")
f.close()
print ("Removing temporary big object.")
object_select_and_active(big_wobj)
bpy.ops.object.delete()
if save_position:
print ("Closing position file.")
f_pos.close()
restore_state(context)
print ("Texture swap count:%d."%texture_swap_count)
return {'FINISHED'}


def read_some_data(context,filepath,clean_mesh):
print ("Using file name: %s Working directory: %s"%(os.path.basename(filepath),os.path.dirname(filepath)))
print ("Changing working directory to %s"%os.path.dirname(filepath))
os.chdir(os.path.dirname(filepath))
print ("importing %s."%filepath)
finf=os.stat(filepath)
fsiz=finf.st_size
file=open(filepath,'r')
name=os.path.basename(filepath).split('.')[0]
ver = file.readline()
print (ver)
ver=int(ver)
if ver != 1 and ver!= 0 :
print ("Not a version 1 tri file. Not supported.")
return {'CANCELLED'}
print ('Creating Object')
bpy.ops.object.add(type='MESH')
#print ('Creating Mesh %s'%name)
#bpy.data.meshes.new(name)
#me=bpy.data.meshes[name]
#bpy.context.object.data=me
me=bpy.context.object.data
print ("Reading datas.")

nv=0
ne=0
nf=0

v=me.vertices
e=me.edges
f=me.loop_triangles
n=0
while 1:
vert=file.readline()
n=n+1
if not vert:
break
file.seek(0) #rewind file
file.readline() #skip first line (version)
#allocate vertices,edges face, very very faster this way
v.add(n)
f.add(n/3)
e.add(n)
ltt=[] #last texture table, used to count texture changes
texture_change_count=0
image_not_found=[]

lper=-11
while 1:
vert=file.readline()
if not vert:
break


per=(nv+2)*100/n;
if per>lper+10:
print ("%d%% (%d)"%(per,nf))
lper=per
vs=vert.split()
ivs=0

v[nv].co=[float(vs[0]),float(vs[1]),float(vs[2])]
ivs=3

if ver==1:
v[nv].normal=[float(vs[3]),float(vs[4]),float(vs[5])]
ivs=6

#now compute texture information
tu=[]
tv=[]
tt=[]
tu.append(float(vs[ivs])) #remember it will be tu[0]
tv.append(float(vs[ivs+1]))
t=vs[ivs+2] #full texture name
t=t.split(';') #split textures name, first name only, others u|v|name
temp=[];
for it in t:
ts=it.split('#');
if len(ts)==1:
temp.append([ts[0],0]);
else:
temp.append([ts[0],0]);
temp.append([ts[1],1]); # if we can split, the second is environnement texture.
t=temp;
tt.append(t[0]) #add first texture name to texture list
t.remove(t[0])
for itt in t:
it=itt[0]; # get texture string
map=itt[1];
#print (it)
iit=it.split('|')
#u and v coordinate and texture name
if len(iit)==3:
tu.append(float(iit[0]))
tv.append(float(iit[1]))
tt.append([iit[2],map])
#only texture name using raydium hard coded scale factor of 50 from first texture coordinate
if len(iit)==1:
tu.append(tu[0]*50) #first texture it's ALWAYS in 0
tv.append(tv[0]*50)
tt.append([iit[0],map])
ntt=0 # number of texture layers
ntc=0 # number of vertex color layers
for i,ti in enumerate(tt): #for each texture
t=ti[0];
map=ti[1];
if t.find('rgb')==0:
ntc=ntc+1
if ntc > len(me.vertex_colors):
print ("Adding RGB texture layer")
me.vertex_colors.new()
l=t.split('(')
l=l[1]
l=l.split(',')
l[2]=l[2].split(')')[0]
if (nv%3)==0:
me.vertex_colors[ntc-1].data[nf].color1=[float(l[0]),float(l[1]),float(l[2])]
if (nv%3)==1:
me.vertex_colors[ntc-1].data[nf].color2=[float(l[0]),float(l[1]),float(l[2])]
if (nv%3)==2:
me.vertex_colors[ntc-1].data[nf].color3=[float(l[0]),float(l[1]),float(l[2])]
else:
ntt=ntt+1
#print (t)
if ntt > len (me.uv_textures):
print ("Adding uv texture layer")
me.uv_textures.new()
im=bpy.data.images.get(t)

if (image_not_found.count(t)==0):
if not(isinstance(im,bpy.types.Image)):
print ("Loading image %s."%t)
try:
print ("trying")
bpy.data.images.load(t)
print ("end trying")
except:
print ("except")
image_not_found.append(t)
print ("Not found image:%s."%t)
pass
im=bpy.data.images.get(t)
if (im==None):
continue
me.uv_layers[ntt-1].data[nf].image=im
if map==0:
me.uv_layers[ntt-1].data[nf].image.mapping='UV';
else:
me.uv_layers[ntt-1].data[nf].image.mapping='REFLECTION';
#me.uv_textures[ntt-1].data[nf].use_image=True
if(nv%3)==0:
me.uv_layers[ntt-1].data[nf].uv1=[tu[i],tv[i]]
if(nv%3)==1:
me.uv_layers[ntt-1].data[nf].uv2=[tu[i],tv[i]]
if(nv%3)==2:
me.uv_layers[ntt-1].data[nf].uv3=[tu[i],tv[i]]
for i,t in enumerate(tt): #Count texture changes
try:
lt=ltt[i]
except:
ltt.append(t)
texture_change_count+=1
if (t!=ltt[i]):
texture_change_count+=1
ltt[i]=t

nv=nv+1

if (nv%3)==0:
e[ne].vertices=[(nv-3),(nv-2)]
e[ne+1].vertices=[(nv-2),(nv-1)]
e[ne+2].vertices=[(nv-1),(nv-3)]
ne=ne+3
f[nf].vertices=[(nv-3),(nv-2),(nv-1)]
if v[nv-3].normal==v[nv-2].normal and v[nv-2].normal==v[nv-1].normal:
f[nf].use_smooth=False
else:
f[nf].use_smooth=True
nf=nf+1
me.update(calc_edges=True,calc_tessface=True)
print ("%d%% (%d)"%(per,nf))
print (".tri file need %d textures swap"% texture_change_count)
for t in image_not_found:
print ("Error image %s not found."%t)
print ("Mesh Imported Vertices:%d Edges:%d Faces:%d."%(len(v),len(e),len(f)))
#me.from_pydata(v,e,f)
bpy.ops.object.mode_set(mode='EDIT')
print("close file.")
file.close()
if clean_mesh:
print("Clean Up Mesh")
bpy.ops.mesh.remove_doubles(mergedist=0.0001)
bpy.ops.mesh.tris_convert_to_quads()
bpy.ops.object.mode_set(mode='OBJECT')
return {'FINISHED'}

# ExportHelper is a helper class, defines filename and
# invoke() function which calls the file selector.

# ExportHelper is a helper class, defines filename and
# invoke() function which calls the file selector.
from bpy_extras.io_utils import ExportHelper,ImportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Operator

class ExportSomeData(Operator, ExportHelper):
'''Export Raydium .tri file.'''
bl_idname = "export.raydium_tri" # this is important since its how bpy.ops.export.some_data is constructed
bl_label = "Export Raydium Tri File"

# ExportHelper mixin class uses this
filename_ext = ".tri"

filter_glob = StringProperty(default="*.tri", options={'HIDDEN'})

# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
save_elements = BoolProperty(name="Save Each Element", description="Save each object as one file, using mesh name", default=False)
save_position = BoolProperty(name="Save Each Element Pos/Rot",description="Save Position and rotation of each element",default=False)

# type = EnumProperty(items=(('OPT_A', "First Option", "Description one"),
# ('OPT_B', "Second Option", "Description two."),
# ),
# name="Example Enum",
# description="Choose between two items",
# default='OPT_A')
#
@classmethod
def poll(cls, context):
#return context.active_object != None
return len(context.selectable_objects)>0

def execute(self, context):
now=time.time()
print ("----------------New Export------------------------")
ret=write_some_data(context, self.filepath, self.save_elements,self.save_position)
print ("Elapsed: %f"%(time.time()-now))
return ret


class ImportSomeData(Operator, ImportHelper):
'''Import Raydium .tri file.'''
bl_idname = "import_mesh.raydium_tri" # this is important since its how bpy.ops.export.some_data is constructed
bl_label = "Import Raydium Tri File"

# ExportHelper mixin class uses this
filename_ext = ".tri"

filter_glob = StringProperty(default="*.tri", options={'HIDDEN'})

# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
clean_mesh = BoolProperty(name="Clean Up Mesh", description="Remove doubles vertices and try to make quads faces", default=False)

# type = EnumProperty(items=(('OPT_A', "First Option", "Description one"),
# ('OPT_B', "Second Option", "Description two."),
# ),
# name="Example Enum",
# description="Choose between two items",
# default='OPT_A')
#
@classmethod
def poll(cls, context):
return True
#return context.active_object != None
#return len(context.selectable_objects)>0

def execute(self, context):
now=time.time()
print ("----------------New Import------------------------")
ret=read_some_data(context,self.filepath,self.clean_mesh)
print ("Elapsed: %f"%(time.time()-now))
return ret


# Only needed if you want to add into a dynamic menu
def menu_func_export(self, context):
self.layout.operator(ExportSomeData.bl_idname, text="Raydium (.tri)")

def menu_func_import(self, context):
self.layout.operator(ImportSomeData.bl_idname, text="Raydium (.tri)")


def register():
print("Add On Activer")
bpy.utils.register_class(ExportSomeData)
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
bpy.utils.register_class(ImportSomeData)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)


def unregister():
print("Add On Desactiver")
bpy.utils.unregister_class(ExportSomeData)
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
bpy.utils.unregister_class(ImportSomeData)
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)




(8-8/10)