Hi Devs,
I have been trying to access the original obj data from an asset I loaded in using ModelIO.
I import the asset using the MDLAsset(url: vertexDescriptor: bufferAllocator: preserveTopology: error:)
I set preserve topology to true, which from my understanding should keep all the data consistent with the original.
My question is how does one correlate the submesh face data to the vertex data and the index data?
I have read the documents which mention you should use the order of the faceTopologyBuffer, which will result in a 3D object that does look correct but all the points have unique vertices (non welded edges).
I can make an assumption and loop over all the vertices and remove any duplicates, there by creating my own index buffer, but that would create an assumption that all faces have been welded which is also not correct.
Is there a way to get the original data out of MDLAsset, or should I look to other avenues like assimp?
Thank you for the help,
Simon
Post
Replies
Boosts
Views
Activity
Ahoy Developrs,
I was wondering if someone might be able to help me, regarding working with Data, Buffers and Pointers, as I am working with Metal, ModelIO and large arrays of vertex data.
Are there ways of converting/accessing Data instances as their original variable type without having to map/duplicate the data into a new variable? and visa-vera. I have to convert arrays into MDLMeshBuffer to pass them into ModelIO, from custom geometry that I have made at runtime.
This can be quite convoluted as I have my own array of structs for geometric topology. This gets converted into MetalBuffer for GPU drawing, but I want to leverage ModelIO for importing/exporting. To leverage ModelIO I need to convert to and from the ModelIO Mesh Buffers, which can be converted into Data objects, and then convert those into data specific
All this conversion to and from create quite a bit of memory bloat.
The following are 3 examples of how I have been interacting with the different types,
are there better /more efficient ways of doing this?
// Converts Data to variable
var positions = Array<simd_float3>(repeating: simd_float3.zero, count: data2.count/MemoryLayout<simd_float3>.stride)
_ = arr2.withUnsafeMutableBytes { data.copyBytes(to: $0) }
// Example ModelIO vert conversion
for i in 0..<mdlMesh.vertexBuffers.count {
let vBuff = mdlMesh.vertexBuffers[i]
let buffLyt = mdlMesh.vertexDescriptor.layouts[i] as! MDLVertexBufferLayout
let vertCount = vBuff.length / buffLyt.stride
let buffermap:MDLMeshBufferMap = vBuff.map()
let rawBasePtr:UnsafeMutableRawPointer = buffermap.bytes
for vertIndex in 0..<vertCount {
let b = rawBasePtr.load(fromByteOffset: buffLyt.stride * vertIndex, as: (simd_float3).self)
vertices.append(b)
}
}
// Example ModelIO submesh conversion
/// The layout of the face indicies
var topologyVertCount:Array<UInt8> = []
if subMesh.topology != nil {
let topology = subMesh.topology!
let faceBuffer = topology.faceTopology!
print("Topology Buffer : \(topology)")
print(" face count: \(topology.faceCount)")
print(" hole count: \(topology.holeCount)")
for faceIndex in 0..<topology.faceCount {
let b = faceBuffer.map().bytes.load(fromByteOffset: MemoryLayout<UInt8>.stride * faceIndex, as: UInt8.self)
topologyVertCount.append(b)
}
}
Thank you for the help,
Simon
Ahoy everyone,
I am currently in the process of writing a custom undo system, as I will be handling large geometric data, and want to make sure the undo data is very efficient.
The plan is to get all the byte data, and then perform an XOR and store the result in an optomised way.
Currently I can retieve the class objects byte data using the Data() data type, but this does not encapsulate all the data that makes up the object. you end up with pointers that point to data which is not getting collected.
Question A: Is there an existing API call or data type that allows me to pass in a class object and returns all the byte data ?
Question B: If question A is no, could you recommend/suggest a way to achieve this?
Thank you for your time and help :)
The following is my Playground I was using for testing purposes, just incase I have made a huge mistake with my use of the Data type.
import Foundation
import simd
class Node {
public var position : simd_float3 = [0, 0, 0]
public var name : String = "Node"
public var vertices : Array<simd_float3> = []
}
/// Default instance
var newClassNode = Node()
/// Modified instances
var moved_newClassNode = Node()
moved_newClassNode.name = "Updated_Node_Position"
moved_newClassNode.position = [1, 1, 1]
moved_newClassNode.vertices = [ [0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4],
[5, 5, 5], [6, 6, 6], [7, 7, 7], [8, 8, 8], [9, 9, 9], ]
/// Size of the MemoryLayout class
let mem_size = MemoryLayout<Node>.size
var data_test = Data(bytes: &newClassNode, count: mem_size)
var data_test2 = Data(bytes: &moved_newClassNode, count: mem_size)
let d_ints = data_test.map { UInt8($0) }
let d2_ints = data_test2.map { UInt8($0) }
/// The XOR byte data.
var xor_bytes : Array<UInt8> = []
/// The byte data that has had the xor bytes applied.
var applied_xor : Array<UInt8> = []
// XOR comparison
/// The following is performing the byte XOR comparison for each byte found in the Data object.
for i in 0..<mem_size {
xor_bytes.append(d_ints[i] ^ d2_ints[i])
}
// Applies the XOR bytes, and stores the result
for i in 0..<mem_size {
applied_xor.append(d_ints[i] ^ xor_bytes[i])
}
/// Assigns the byte data to a Data variable
var xor_data = Data(applied_xor)
/// Result of the applied xor data cast back into the original object type.
let appliedNode = xor_data.withUnsafeBytes { $0.load(as: Node.self) }
// Updating a variable after the XOR should not appear in the final result, unless its using pointers and not fully capturing all the bytedata
moved_newClassNode.vertices[1] = [101,101,101]
/// == LOGGING ==
memory_debug(data_test)
memory_debug(data_test2)
print("\n-- XOR Numeric --")
for i in 0..<mem_size {
print("\(d_ints[i]) ^ \(d2_ints[i]) = \(xor_bytes[i])")
}
print("\n-- BINARY representation --")
for i in 0..<mem_size {
print("\( pad(string:String(d_ints[i], radix:2), toSize:8) ) ^ \( pad(string:String(d2_ints[i], radix:2), toSize:8 )) = \( pad(string:String(xor_bytes[i], radix:2), toSize:8))")
}
print("\n-- xor applied --")
for i in 0..<mem_size {
print("\(d_ints[i]) ^ \(xor_bytes[i]) = \(applied_xor[i])")
}
print("\n -- Converted applied xor byte data to object --")
print(appliedNode.name)
print(appliedNode.position)
print(appliedNode.vertices)
/* ============
* Functions
* ============
*/
func memory_debug(_ input_data:Data) {
print("\n-- Data_Test Debug --")
print(input_data)
print(input_data as NSData)
print("count : \(input_data.count)")
let hex_string = input_data.map { String(format: "%02x", $0) }.joined()
print(hex_string) // hex value
//print(String(Int(hex_string, radix:16)!, radix:2)) // hex to binary value
print(input_data.map { String($0, radix:2) } )
}
func pad(string : String, toSize: Int) -> String {
var padded = string
for _ in 0..<(toSize - string.count) {
padded = "0" + padded
}
return padded
}
Hi Devs,
Anyone know how to get the local mouse click position of a UIKit view that is wrapped in a NSViewRepresentable and drawn using SwiftUI.
No matter what I do it always returns the entire window view, and I am after the location relative to the MTKView.
I am overriding the MTKView's, mouseDown function, and wanting to get the local position from the mouseDown event.
using self.convert(event.locationInWindow, to:self), returns the same position as event.locationInWindow
The reason I need the local position inside the MTKView, is I will be sampling an idBuffer at that point.
Any help would be greatly appreciated,
Thanks Simon
Hi Community,
I have a question regarding ShareLink. In the documentation you pass it an array of items or as a single item.
The way I have previously setup my share sheet was a button would trigger an event, that would check what has been selected. if nothing was selected then no share sheet would appear, is something was selected, then those selected items are exported and the share sheet gets the path to the folder.
Using ShareLink I have been trying to figure out the best way to implement the same functionanilty but utilising ShareLink. If I pass the function get_export_location(), to the share sheet that will work as long as something is selected, if nothing is selected an empty array is returned but the share sheet still appears.
Should I wrap the ShareLink in a Button, that checks for the selection before passing it to the ShareLink, or am I thinking about the design of the api incorrectly. As I have tried this but the ShareLink does not appear.
[Export Button Pressed] > [Evaluate Selection] > [if selection, show ShareLink]
Any help would be greatly appreciated.
Thanks, Simon