- New mesh export node.

This commit is contained in:
Tanasart 2024-06-17 11:22:18 +07:00
parent be99110708
commit e67d134d2a
10 changed files with 298 additions and 5 deletions

View file

@ -637,6 +637,7 @@
{"name":"node_3d_material","order":10,"path":"scripts/node_3d_material/node_3d_material.yy",},
{"name":"node_3d_mesh_cone","order":6,"path":"scripts/node_3d_mesh_cone/node_3d_mesh_cone.yy",},
{"name":"node_3d_mesh_cylinder","order":3,"path":"scripts/node_3d_mesh_cylinder/node_3d_mesh_cylinder.yy",},
{"name":"node_3d_mesh_export","order":14,"path":"scripts/node_3d_mesh_export/node_3d_mesh_export.yy",},
{"name":"node_3d_mesh_extrude","order":8,"path":"scripts/node_3d_mesh_extrude/node_3d_mesh_extrude.yy",},
{"name":"node_3d_mesh_obj","order":2,"path":"scripts/node_3d_mesh_obj/node_3d_mesh_obj.yy",},
{"name":"node_3d_mesh_plane","order":7,"path":"scripts/node_3d_mesh_plane/node_3d_mesh_plane.yy",},
@ -1630,6 +1631,7 @@
{"name":"s_node_3d_light_point","order":18,"path":"sprites/s_node_3d_light_point/s_node_3d_light_point.yy",},
{"name":"s_node_3d_meterial","order":12,"path":"sprites/s_node_3d_meterial/s_node_3d_meterial.yy",},
{"name":"s_node_3d_obj_combine","order":5,"path":"sprites/s_node_3d_obj_combine/s_node_3d_obj_combine.yy",},
{"name":"s_node_3d_obj_export","order":30,"path":"sprites/s_node_3d_obj_export/s_node_3d_obj_export.yy",},
{"name":"s_node_3d_obj","order":3,"path":"sprites/s_node_3d_obj/s_node_3d_obj.yy",},
{"name":"s_node_3d_plane","order":6,"path":"sprites/s_node_3d_plane/s_node_3d_plane.yy",},
{"name":"s_node_3d_point_affector","order":21,"path":"sprites/s_node_3d_point_affector/s_node_3d_point_affector.yy",},

View file

@ -1017,6 +1017,7 @@
{"id":{"name":"node_3d_mesh_cone","path":"scripts/node_3d_mesh_cone/node_3d_mesh_cone.yy",},},
{"id":{"name":"node_3d_mesh_cube","path":"scripts/node_3d_mesh_cube/node_3d_mesh_cube.yy",},},
{"id":{"name":"node_3d_mesh_cylinder","path":"scripts/node_3d_mesh_cylinder/node_3d_mesh_cylinder.yy",},},
{"id":{"name":"node_3d_mesh_export","path":"scripts/node_3d_mesh_export/node_3d_mesh_export.yy",},},
{"id":{"name":"node_3d_mesh_extrude","path":"scripts/node_3d_mesh_extrude/node_3d_mesh_extrude.yy",},},
{"id":{"name":"node_3d_mesh_obj","path":"scripts/node_3d_mesh_obj/node_3d_mesh_obj.yy",},},
{"id":{"name":"node_3d_mesh_plane","path":"scripts/node_3d_mesh_plane/node_3d_mesh_plane.yy",},},
@ -2172,6 +2173,7 @@
{"id":{"name":"s_node_3d_light_point","path":"sprites/s_node_3d_light_point/s_node_3d_light_point.yy",},},
{"id":{"name":"s_node_3d_meterial","path":"sprites/s_node_3d_meterial/s_node_3d_meterial.yy",},},
{"id":{"name":"s_node_3d_obj_combine","path":"sprites/s_node_3d_obj_combine/s_node_3d_obj_combine.yy",},},
{"id":{"name":"s_node_3d_obj_export","path":"sprites/s_node_3d_obj_export/s_node_3d_obj_export.yy",},},
{"id":{"name":"s_node_3d_obj","path":"sprites/s_node_3d_obj/s_node_3d_obj.yy",},},
{"id":{"name":"s_node_3d_plane","path":"sprites/s_node_3d_plane/s_node_3d_plane.yy",},},
{"id":{"name":"s_node_3d_point_affector","path":"sprites/s_node_3d_point_affector/s_node_3d_point_affector.yy",},},

View file

@ -5,19 +5,19 @@
global.VF_POS_COL = vertex_format_end();
vertex_format_begin();
vertex_format_add_position_3d();
vertex_format_add_normal();
vertex_format_add_texcoord();
vertex_format_add_color();
vertex_format_add_position_3d(); // x y z // 12
vertex_format_add_normal(); // x y z // 12
vertex_format_add_texcoord(); // u v // 8
vertex_format_add_color(); // r g b a // 4
global.VF_POS_NORM_TEX_COL = vertex_format_end();
global.VF_POS_NORM_TEX_COL_size = 36;
#endregion
function __3dObject() constructor {
vertex = [];
VB = [];
normal_vertex = [];
object_counts = 1;
VB = [];
NVB = noone;
normal_draw_size = 0.2;

View file

@ -0,0 +1,173 @@
function Node_3D_Mesh_Export(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Mesh Export";
inputs[| 0] = nodeValue("Mesh", self, JUNCTION_CONNECT.input, VALUE_TYPE.d3Mesh, noone)
.setVisible(true, true);
inputs[| 1] = nodeValue("Paths", self, JUNCTION_CONNECT.input, VALUE_TYPE.path, "")
.setDisplay(VALUE_DISPLAY.path_save, { filter: "Obj (.obj)|*.obj" })
.setVisible(true);
inputs[| 2] = nodeValue("Export Texture", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true);
inputs[| 3] = nodeValue("Invert UV", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false);
input_display_list = [ 0,
["Export", false], 1, 2, 3,
];
insp1UpdateTooltip = "Export";
insp1UpdateIcon = [ THEME.sequence_control, 1, COLORS._main_value_positive ];
static onInspector1Update = function() { export(); }
static export = function() {
var _mesh = getInputData(0);
var _path = getInputData(1);
var _mat = getInputData(2);
var _invv = getInputData(3);
if(_mesh == noone) return;
if(!is_instanceof(_mesh, __3dObject)) return;
var _vbs = _mesh.VB;
var _mtlPath = filename_dir(_path) + "\\" + filename_name_only(_path) + ".mtl";
var _mtlName = filename_name(_mtlPath);
var _mtl = "# Pixel Composer\n";
var _obj = "# Pixel Composer\n";
if(_mat) _obj += $"mtllib {_mtlName}\n";
for (var i = 0, n = array_length(_vbs); i < n; i++) {
var _vb = _vbs[i];
var _buffer = buffer_create_from_vertex_buffer(_vb, buffer_fixed, 1);
var _buffer_s = buffer_get_size(_buffer);
_obj += $"o shape{i}\n";
if(_mat) {
var _matName = $"mat.{i}";
var _material = array_safe_get_fast(_mesh.materials, i, 0);
if(_material) {
_mtl += $"newmtl {_matName}\n";
_obj += $"usemtl {_matName}\n";
if(is_surface(_material.surface)) {
var _surfPath = $"{filename_dir(_path)}\\{filename_name_only(_path)}_texture{i}.png";
surface_save(_material.surface, _surfPath);
_mtl += $"map_Kd {_surfPath}\n";
}
}
}
var _obj_v = "";
var _obj_vn = "";
var _obj_vt = "";
var _obj_f = "";
var _map_v = ds_map_create();
var _map_vn = ds_map_create();
var _map_vt = ds_map_create();
var _map_f = ds_map_create();
switch(_mesh.VF) {
case global.VF_POS_NORM_TEX_COL :
var _format_s = global.VF_POS_NORM_TEX_COL_size;
var _vertex_s = floor(_buffer_s / _format_s);
var _ind = 0;
buffer_to_start(_buffer);
var _idx_v = [ 0, 0, 0 ];
var _idx_vn = [ 0, 0, 0 ];
var _idx_vt = [ 0, 0, 0 ];
ds_map_clear(_map_v);
ds_map_clear(_map_vn);
ds_map_clear(_map_vt);
ds_map_clear(_map_f);
repeat(_vertex_s) {
var _px = buffer_read(_buffer, buffer_f32);
var _py = buffer_read(_buffer, buffer_f32);
var _pz = buffer_read(_buffer, buffer_f32);
var _nx = buffer_read(_buffer, buffer_f32);
var _ny = buffer_read(_buffer, buffer_f32);
var _nz = buffer_read(_buffer, buffer_f32);
var _u = buffer_read(_buffer, buffer_f32);
var _v = buffer_read(_buffer, buffer_f32);
if(_invv) _v = 1. - _v;
var _r = buffer_read(_buffer, buffer_s8);
var _g = buffer_read(_buffer, buffer_s8);
var _b = buffer_read(_buffer, buffer_s8);
var _a = buffer_read(_buffer, buffer_s8);
var __v = $"v {string_format(_px, -1, 5)} {string_format(_py, -1, 5)} {string_format(_pz, -1, 5)}";
var __vn = $"vn {string_format(_nx, -1, 5)} {string_format(_ny, -1, 5)} {string_format(_nz, -1, 5)}";
var __vt = $"vt {string_format(_u, -1, 5)} {string_format(_v, -1, 5)}";
var _id_v, _id_vn, _id_vt;
if(ds_map_exists(_map_v, __v)) {
_id_v = _map_v[? __v];
} else {
_id_v = ds_map_size(_map_v) + 1;
_map_v[? __v] = _id_v;
_obj_v += $"{__v} \n";
}
if(ds_map_exists(_map_vn, __vn)) {
_id_vn = _map_vn[? __vn];
} else {
_id_vn = ds_map_size(_map_vn) + 1;
_map_vn[? __vn] = _id_vn;
_obj_vn += $"{__vn} \n";
}
if(ds_map_exists(_map_vt, __vt)) {
_id_vt = _map_vt[? __vt];
} else {
_id_vt = ds_map_size(_map_vt) + 1;
_map_vt[? __vt] = _id_vt;
_obj_vt += $"{__vt} \n";
}
_idx_v[_ind % 3] = _id_v;
_idx_vn[_ind % 3] = _id_vn;
_idx_vt[_ind % 3] = _id_vt;
if(_ind % 3 == 2) _obj_f += $"f {_idx_v[0]}/{_idx_vt[0]}/{_idx_vn[0]} {_idx_v[1]}/{_idx_vt[1]}/{_idx_vn[1]} {_idx_v[2]}/{_idx_vt[2]}/{_idx_vn[2]}\n";
_ind++;
}
break;
}
ds_map_destroy(_map_v);
ds_map_destroy(_map_vn);
ds_map_destroy(_map_vt);
ds_map_destroy(_map_f);
_obj += _obj_v + "\n";
_obj += _obj_vn + "\n";
_obj += _obj_vt + "\n";
_obj += _obj_f + "\n";
buffer_delete(_buffer);
}
file_text_write_all( _path, _obj);
if(_mat) file_text_write_all(_mtlPath, _mtl);
var noti = log_message("EXPORT", $"Export model complete.", THEME.noti_icon_tick, COLORS._main_value_positive, false);
noti.path = filename_dir(_path);
noti.setOnClick(function() { shellOpenExplorer(self.path); }, "Open in explorer", THEME.explorer);
}
static update = function() {}
}

View file

@ -0,0 +1,13 @@
{
"$GMScript":"",
"%Name":"node_3d_mesh_export",
"isCompatibility":false,
"isDnD":false,
"name":"node_3d_mesh_export",
"parent":{
"name":"3D",
"path":"folders/nodes/data/3D.yy",
},
"resourceType":"GMScript",
"resourceVersion":"2.0",
}

View file

@ -0,0 +1,12 @@
{
"isDnD": false,
"isCompatibility": false,
"parent": {
"name": "variable",
"path": "folders/nodes/data/variable.yy",
},
"resourceVersion": "1.0",
"name": "node_counter",
"tags": [],
"resourceType": "GMScript",
}

View file

@ -661,6 +661,7 @@ function __initNodes() {
addNodeObject(d3d, "3D Scene", s_node_3d_scene, "Node_3D_Scene", [1, Node_3D_Scene],, "Combine multiple 3D objects into a single junction.").setVersion(11510);
addNodeObject(d3d, "3D Repeat", s_node_3d_array, "Node_3D_Repeat", [1, Node_3D_Repeat],, "Repeat the same 3D mesh multiple times.").setVersion(11510);
addNodeObject(d3d, "Transform 3D", s_node_image_transform_3d, "Node_3D_Transform_Image", [1, Node_3D_Transform_Image],, "Transform image in 3D space").setVersion(11600);
addNodeObject(d3d, "Mesh Export", s_node_3d_obj_export, "Node_3D_Mesh_Export", [1, Node_3D_Mesh_Export],, "Export 3D mesh as .obj file").setVersion(11740);
ds_list_add(d3d, "Mesh");
addNodeObject(d3d, "3D Object", s_node_3d_obj, "Node_3D_Mesh_Obj", [0, Node_create_3D_Obj],, "Load .obj file from your computer as a 3D object.").setVersion(11510);

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -0,0 +1,90 @@
{
"$GMSprite":"",
"%Name":"s_node_3d_obj_export",
"bboxMode":0,
"bbox_bottom":63,
"bbox_left":4,
"bbox_right":63,
"bbox_top":6,
"collisionKind":1,
"collisionTolerance":0,
"DynamicTexturePage":false,
"edgeFiltering":false,
"For3D":false,
"frames":[
{"$GMSpriteFrame":"","%Name":"1fe6f9a1-3122-4252-8359-48f017365596","name":"1fe6f9a1-3122-4252-8359-48f017365596","resourceType":"GMSpriteFrame","resourceVersion":"2.0",},
],
"gridX":0,
"gridY":0,
"height":64,
"HTile":false,
"layers":[
{"$GMImageLayer":"","%Name":"c12fe317-c955-41e7-a157-32e91731ee30","blendMode":0,"displayName":"default","isLocked":false,"name":"c12fe317-c955-41e7-a157-32e91731ee30","opacity":100.0,"resourceType":"GMImageLayer","resourceVersion":"2.0","visible":true,},
],
"name":"s_node_3d_obj_export",
"nineSlice":null,
"origin":4,
"parent":{
"name":"3D",
"path":"folders/nodes/icons/3D.yy",
},
"preMultiplyAlpha":false,
"resourceType":"GMSprite",
"resourceVersion":"2.0",
"sequence":{
"$GMSequence":"",
"%Name":"s_node_3d_obj_export",
"autoRecord":true,
"backdropHeight":768,
"backdropImageOpacity":0.5,
"backdropImagePath":"",
"backdropWidth":1366,
"backdropXOffset":0.0,
"backdropYOffset":0.0,
"events":{
"$KeyframeStore<MessageEventKeyframe>":"",
"Keyframes":[],
"resourceType":"KeyframeStore<MessageEventKeyframe>",
"resourceVersion":"2.0",
},
"eventStubScript":null,
"eventToFunction":{},
"length":1.0,
"lockOrigin":false,
"moments":{
"$KeyframeStore<MomentsEventKeyframe>":"",
"Keyframes":[],
"resourceType":"KeyframeStore<MomentsEventKeyframe>",
"resourceVersion":"2.0",
},
"name":"s_node_3d_obj_export",
"playback":1,
"playbackSpeed":30.0,
"playbackSpeedType":0,
"resourceType":"GMSequence",
"resourceVersion":"2.0",
"showBackdrop":true,
"showBackdropImage":false,
"timeUnits":1,
"tracks":[
{"$GMSpriteFramesTrack":"","builtinName":0,"events":[],"inheritsTrackColour":true,"interpolation":1,"isCreationTrack":false,"keyframes":{"$KeyframeStore<SpriteFrameKeyframe>":"","Keyframes":[
{"$Keyframe<SpriteFrameKeyframe>":"","Channels":{
"0":{"$SpriteFrameKeyframe":"","Id":{"name":"1fe6f9a1-3122-4252-8359-48f017365596","path":"sprites/s_node_3d_obj_export/s_node_3d_obj_export.yy",},"resourceType":"SpriteFrameKeyframe","resourceVersion":"2.0",},
},"Disabled":false,"id":"68e1dc21-23ce-44b4-ac1c-048da2846c01","IsCreationKey":false,"Key":0.0,"Length":1.0,"resourceType":"Keyframe<SpriteFrameKeyframe>","resourceVersion":"2.0","Stretch":false,},
],"resourceType":"KeyframeStore<SpriteFrameKeyframe>","resourceVersion":"2.0",},"modifiers":[],"name":"frames","resourceType":"GMSpriteFramesTrack","resourceVersion":"2.0","spriteId":null,"trackColour":0,"tracks":[],"traits":0,},
],
"visibleRange":null,
"volume":1.0,
"xorigin":32,
"yorigin":32,
},
"swatchColours":null,
"swfPrecision":0.5,
"textureGroupId":{
"name":"Default",
"path":"texturegroups/Default",
},
"type":0,
"VTile":false,
"width":64,
}