图像转换为SceneKit节点 [英] Convert an image to a SceneKit Node

查看:831
本文介绍了图像转换为SceneKit节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个位图图像:

I have a bit-map image:

(然而,这应与任意图像工作)

( However this should work with any arbitrary image )

我想利用我的形象,使之成为3D SCNNode。我已经完成了很多与此code。这需要每个像素的图像,并创建一个SCNBox几何SCNNode。

I want to take my image and make it a 3D SCNNode. I've accomplished that much with this code. That takes each pixel in the image and creates a SCNNode with a SCNBox geometry.

static inline SCNNode* NodeFromSprite(const UIImage* image) {
  SCNNode *node = [SCNNode node];
  CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
  const UInt8* data = CFDataGetBytePtr(pixelData);
  for (int x = 0; x < image.size.width; x++)
  {
    for (int y = 0; y < image.size.height; y++)
    {
      int pixelInfo = ((image.size.width * y) + x) * 4;
      UInt8 alpha = data[pixelInfo + 3];
      if (alpha > 3)
      {
        UInt8 red   = data[pixelInfo];
        UInt8 green = data[pixelInfo + 1];
        UInt8 blue  = data[pixelInfo + 2];
        UIColor *color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];
        SCNNode *pixel = [SCNNode node];
        pixel.geometry = [SCNBox boxWithWidth:1.001 height:1.001 length:1.001 chamferRadius:0];
        pixel.geometry.firstMaterial.diffuse.contents = color;
        pixel.position = SCNVector3Make(x - image.size.width / 2.0,
                                        y - image.size.height / 2.0,
                                        0);
        [node addChildNode:pixel];
      }
    }
  }
  CFRelease(pixelData);
  node = [node flattenedClone];
  //The image is upside down and I have no idea why.
  node.rotation = SCNVector4Make(1, 0, 0, M_PI);
  return node;
}

但问题是,我在做什么占用了办法不多的记忆!

But the problem is that what I'm doing takes up way to much memory!

我试图找到一种方法,使用较少的内存做到这一点。

I'm trying to find a way to do this with less memory.

所有code和资源,可以在这里找到: https://github.com/KonradWright/KNodeFromSprite

All Code and resources can be found at: https://github.com/KonradWright/KNodeFromSprite

推荐答案

现在你绘制每个像素SCNBox某种颜色的,这意味着:

Now you drawing each pixel as SCNBox of certain color, that means:

  • 在每框选择一个GL平局
  • 的adjancent框之间不必要2隐形面绘制
  • 在画的一排同1X1X1箱N将可以得出1x1xN一箱

看起来像普通的Minecraft般的优化问题:

Seems like common Minecraft-like optimization problem:

  1. 在对待你的形象是3维数组(其中深度通缉图像拉伸深度),再某种颜色的presenting立方体体素的每个元素。
  2. 使用贪婪网格算法(<一HREF =htt​​p://mikolalysenko.github.io/MinecraftMeshes/index.html相对=nofollow>演示)和的自定义SCNGeometry 建立网格SceneKit节点。
  1. Treat your image is 3-dimensional array (where depth is wanted image extrusion depth), each element representing cube voxel of certain color.
  2. Use greedy meshing algorithm (demo) and custom SCNGeometry to create mesh for SceneKit node.

伪code为网格算法跳过adjancent立方体面(simplier,但比贪婪的啮合效果较差):

Pseudo-code for meshing algorithm that skips faces of adjancent cubes (simplier, but less effective than greedy meshing):

#define SIZE_X = 16; // image width
#define SIZE_Y = 16; // image height

// pixel data, 0 = transparent pixel
int data[SIZE_X][SIZE_Y];

// check if there is non-transparent neighbour at x, y
BOOL has_neighbour(x, y) {
    if (x < 0 || x >= SIZE_X || y < 0 || y >= SIZE_Y || data[x][y] == 0)
        return NO; // out of dimensions or transparent
    else
        return YES; 
}

void add_face(x, y orientation, color) {
    // add face at (x, y) with specified color and orientation = TOP, BOTTOM, LEFT, RIGHT, FRONT, BACK
    // can be (easier and slower) implemented with SCNPlane's: https://developer.apple.com/library/mac/documentation/SceneKit/Reference/SCNPlane_Class/index.html#//apple_ref/doc/uid/TP40012010-CLSCHSCNPlane-SW8
    // or (harder and faster) using Custom Geometry: https://github.com/d-ronnqvist/blogpost-codesample-CustomGeometry/blob/master/CustomGeometry/CustomGeometryView.m#L84 
}

for (x = 0; x < SIZE_X; x++) {
    for (y = 0; y < SIZE_Y; y++) {

        int color = data[x][y];
        // skip current pixel is transparent
        if (color == 0)
            continue;

        // check neighbour at top
        if (! has_neighbour(x, y + 1))
            add_face(x,y, TOP, );

        // check neighbour at bottom
        if (! has_neighbour(x, y - 1))
            add_face(x,y, BOTTOM);

        // check neighbour at bottom
        if (! has_neighbour(x - 1, y))
            add_face(x,y, LEFT);

        // check neighbour at bottom
        if (! has_neighbour(x, y - 1))
            add_face(x,y, RIGHT);

        // since array is 2D, front and back faces is always visible for non-transparent pixels
        add_face(x,y, FRONT);
        add_face(x,y, BACK);

    }
}

很多依赖于输入图像。如果不是大,没有各种各样的颜色,那我将与 SCNNode 去加入 SCNPlane 的可见面,然后 flattenedClone() ING的结果。

A lot of depends on input image. If it is not big and without wide variety of colors, it I would go with SCNNode adding SCNPlane's for visible faces and then flattenedClone()ing result.

这篇关于图像转换为SceneKit节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆