I hate to resurrect an old thread, but I hacked out a quick Ruby script for converting the 3dcg-arts models into a standard .obj file.
It's not perfect, but seems to work pretty well, at least for the older format files. You have to manually add the correct images to the materials, but the UVs and material entries should get created correctly. I haven't found how to find the image name to link to each material yet, but I assign different random colors to each material to make it easier to see which part of the model uses which material.
Use of the script is a little convoluted. From the developer console, save the javascript file with all the vertex data for the model (usually the filename is the model number), then run this script on that file. It's a Ruby script, so call it from the command line, passing the filepath to the saved javascript file as an argument. It will batch multiple if you pass multiple file paths in at once.
EDIT: I should've used a larger test sample before posting. This doesn't work for all files, so caveat emptor. I'll post a fixed version when I figure out why some files work and some don't.
Code: Select all
#! /usr/bin/env ruby
require 'rubygems'
require 'json'
def write_verts(vertices, file)
puts "Writing Vertices…"
vertex_counter = 0
vertices.each do |one_vertex|
if vertex_counter % 3 == 0
file.write("v ")
end
file.write("#{one_vertex.to_s} ")
vertex_counter = vertex_counter + 1
if vertex_counter %3 == 0
file.write("\n")
end
end
puts "\tVertices written: #{vertices.length / 3}"
end
def write_uvs(uvs, file)
puts "Writing UVs…"
vertex_counter = 0
uvs.each do |one_uv|
if vertex_counter % 2 == 0
file.write("vt ")
end
file.write("#{one_uv.to_s} ")
vertex_counter = vertex_counter + 1
if vertex_counter % 2 == 0
file.write("\n")
end
end
puts "\tUVs written:#{uvs.length / 2}\n"
end
def write_normals(normals, file)
puts "Writing Normals…"
vertex_counter = 0
normals.each do |one_normal|
if vertex_counter % 3 == 0
file.write("vn ")
end
file.write("#{one_normal.to_s} ")
vertex_counter = vertex_counter + 1
if vertex_counter %3 == 0
file.write("\n")
end
end
puts "\tNormals written:#{normals.length / 3}\n"
end
def write_triangle(faces, offset, file)
x = faces[offset]
y = faces[offset+1]
z = faces[offset+2]
file.write("f #{x}// #{y}// #{z}//\n")
end
def write_quad(faces, offset, file)
x = faces[offset]
y = faces[offset+1]
z = faces[offset+2]
w = faces[offset+3]
file.write("f #{x}// #{y}// #{z}// #{w}\n")
end
def write_faces(vertex, faces_string, file, materials_array)
puts "Writing Faces…"
faces = faces_string.scan(/(42,\d+,\d+,\d+,\d+,\d+,\d+,\d+,\d+,\d+,\d+)|(43,\d+,\d+,\d+,\d+,\d+,\d+,\d+,\d+,\d+,\d+,\d+,\d+,\d+)/)
x = y = z = w = 0
face_count = 0
material_count = 1
last_material_index = -1
faces.each do |one_face|
face_parts = one_face.compact[0].split(",")
if face_parts[0] = 42
material_index = face_parts[4]
if (material_index != last_material_index)
file.write("usemtl texture#{material_index}\n")
materials_array.push("texture#{material_index}") unless materials_array.include?("texture#{material_index}")
last_material_index = material_index
end
x = face_parts[1].to_i + 1
y = face_parts[2].to_i + 1
z = face_parts[3].to_i + 1
xt = face_parts[5].to_i + 1
yt = face_parts[6].to_i + 1
zt = face_parts[7].to_i + 1
xn = face_parts[8].to_i + 1
yn = face_parts[9].to_i + 1
zn = face_parts[10].to_i + 1
file.write("f #{x}/#{xt}/ #{y}/#{yt}/ #{z}/#{zt}/\n")
elsif face_parts[0] = 43
material_index = face_parts[5]
if (material_index != last_material_index)
file.write("usemtl texture#{material_index}\n")
materials_array.push("texture#{material_index}") unless materials_array.include?("texture#{material_index}")
last_material_index = material_index
end
x = face_parts[1].to_i +1
y = face_parts[2].to_i +1
z = face_parts[3].to_i +1
w = face_parts[4].to_i +1
xt = face_parts[6].to_i +1
yt = face_parts[7].to_i +1
zt = face_parts[8].to_i +1
wt = face_parts[9].to_i +1
xn = face_parts[10].to_i +1
yn = face_parts[11].to_i +1
zn = face_parts[12].to_i +1
wn = face_parts[13].to_i +1
file.write("f #{x}/#{xt}/ #{y}/#{yt}/ #{z}/#{zt}/ #{w}/#{wt}/\n")
end
face_count = face_count + 1
end
puts "\tFaces written: #{face_count.to_s}"
end
ARGV.each do|a|
input_file_path = a
puts "Processing file: #{a}"
json_file = File.open(input_file_path, "r")
json_text = json_file.read
json_file.close
start_token = "var m = "
end_token = "]]};"
data_start_index = json_text.index(start_token) + start_token.length
data_end_index = json_text.index(end_token) + end_token.length
json_text = json_text[data_start_index, data_end_index - data_start_index - 1]
json_data = JSON.parse(json_text)
vertices = json_data["vertices"][0]
faces = json_data["faces"]
uvs = json_data["uvs"][0][0]
normals = json_data["normals"][0]
materials = json_data["materials"][0]
puts "Raw Vertices: #{vertices.length}"
puts "Raw Faces: #{faces.length}"
puts "Raw UVs: #{uvs.length}"
mtl_filepath = "#{input_file_path}.mtl"
mtl_localfile = mtl_filepath.split(File::SEPARATOR)[-1]
output_file_path = "#{input_file_path}.obj"
materials_array = []
File.open(output_file_path, 'w') do |file|
file.write("mtllib #{mtl_localfile}\n")
write_verts(vertices, file)
write_uvs(uvs, file)
write_faces(vertices, faces.join(","), file, materials_array)
end
File.open(mtl_filepath, 'w') do |file|
materials_array.each do |one_material|
file.write("newmtl #{one_material}\n")
file.write("Kd #{rand} #{rand} #{rand}\n");
file.write("Ka 0.600 0.600 0.600\n");
file.write("Ks 0.000 0.000 0.000\n");
file.write("Tr 1.0\n");
file.write("#{one_material}.png\n");
end
end
end