Closed11

pngからUSDZ生成する機能の実装

SATOSHISATOSHI

1枚絵の画像からUSDZを生成するのがとても面倒なのでツール化したいと考えた

SATOSHISATOSHI

Reality Composerに画像をドラッグ&ドロップで生成できそうだが、なぜか暗くなってしまう

SATOSHISATOSHI

以前、Reality Converterで複数の画像を設定して乗り切った。その作業を自動化したらいけるかも、と。

SATOSHISATOSHI

XcodeのPlaygroundで検証。

ファイル読み込みと保存はこんな形。

実行するとエラー。
実行時のパスを見つけて Documents/ 配下に "Shared Playground Data" という名前のフォルダを手動生成したら保存成功。まじか。

import UIKit
import PlaygroundSupport

let imagePath = Bundle.main.path(forResource: "image001", ofType: "png")!
let image = UIImage(contentsOfFile: imagePath)!
let imagedata = image.jpegData(compressionQuality: 1.0)

let filepath = playgroundSharedDataDirectory.appendingPathComponent("export.jpg")
try! imagedata?.write(to: filepath)
print("write to \(filepath)")
SATOSHISATOSHI

usdaはテキストエディタで下記を保存。
Finderのプレビューでは良い感じで表示されている。

しかしMDLAssetにした時点で失敗。

#usda 1.0

def Xform "sample001"
{
    def Mesh "mesh"
    {
        uniform bool doubleSided = 1
        int[] faceVertexCounts = [4]
        int[] faceVertexIndices = [0, 1, 2, 3]
        rel material:binding = </sample001/material_0>
        normal3f[] normals = [(0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0)]
        point3f[] points = [(-1, 0, -1), (-1, 0, 1), (1, 0, 1), (1, 0, -1)]
        texCoord2f[] primvars:st = [(0, 0), (1, 0), (1, 1), (0, 1)] (
            interpolation = "varying"
        )
    }

    def Material "material_0"
    {
        token inputs:frame:stPrimvarName = "st"
        token outputs:surface.connect = </sample001/material_0/PBRShader.outputs:surface>

        def Shader "PBRShader"
        {
            uniform token info:id = "UsdPreviewSurface"
            color3f inputs:diffuseColor.connect = </sample001/material_0/diffuseTexture.outputs:rgb>
            float inputs:metallic = 0.0
            float inputs:roughness = 0.0
            token outputs:surface
        }

        def Shader "stReader"
        {
            uniform token info:id = "UsdPrimvarReader_float2"
            token inputs:varname.connect = </sample001/material_0.inputs:frame:stPrimvarName>
            float2 outputs:result
        }

        def Shader "diffuseTexture"
        {
            uniform token info:id = "UsdUVTexture"
            asset inputs:file = @sticker001.png@
            float2 inputs:st.connect = </sample001/material_0/stReader.outputs:result>
            float3 outputs:rgb
        }
    }
}
SATOSHISATOSHI

Pythonのコマンドラインツールから生成するのが良いと思えた。

Swiftでどこまでできるのか確認したかった。
SCNSceneから生成する方法を検証。

結果としてdiffuse、transparent、emission、ambientOcclusionに画像設定することで対応できた気配。

    public func exec(sourceImage: UIImage, destUrl: URL) {

        let scene = SCNScene()

        let node = SCNNode()
        node.eulerAngles = SCNVector3(-Float.pi/2, 0, 0)
        node.geometry = SCNPlane(width: 0.5, height: 0.5)

        let material = SCNMaterial()
        material.isDoubleSided = true
        material.diffuse.contents = sourceImage
        material.transparent.contents = sourceImage
        material.emission.contents = sourceImage
        material.ambientOcclusion.contents = sourceImage
        node.geometry?.materials = [material]

        scene.rootNode.addChildNode(node)

        scene.write(to: destUrl, options: nil, delegate: nil, progressHandler: nil)
    }
SATOSHISATOSHI

2048 x 2048 までの正方形の透過情報付きpngを指定すると良い感じのusdzを生成してくれるはず。

SATOSHISATOSHI

AWS LambdaでAPI化してpngのbase64を受け付けるようにしたら実用的か。
一旦ここまで。

このスクラップは2021/11/04にクローズされました