1. 程式人生 > >ARKit + SceneKit Geometries Tutorial (Part 1)

ARKit + SceneKit Geometries Tutorial (Part 1)

What is a geometry object?

First we need to understand what a geometry object is made up of. It’s essentially a collection of points (vertices) in 3D space that are connected together to form surfaces in the form of triangles.

The vertices form triangles because 3 is the minimum number of points you need to create a surface; one point is just a point, two points is a line, three you can make a triangular surface, and with four points you can make a quadrilateral which can be split up into 2 triangles.

These vertices can be connected together in a number of ways in SceneKit, these ways are: triangles, triangleStrip, line, point and polygon. In other frameworks, like OpenGL you also have triangle fan, quads, quads strip etc. those geometries are still possible to create, but not in exactly the same way. I’d advise you read up on OpenGL primitives before continuing, it will help to have that knowledge.

This chapter does a pretty good job at it, that’s where I learned from many years ago; these foundations do not change with time like most higher level programming does.

SCNPlane

For SCNPlane the geometry is always a rectangle, so no skewing is needed. Therefore all the information we need is a width and a height.

Of the above mentioned geometries either triangles, triangleStrip or polygon would work for us. Polygon has the potential to create more vertices than we need, and as the result will be two triangles sharing two vertices and one edge triangleStrip would require the least amount of work. (File on GitHub)

extension SCNGeometry {
static func Plane(width: CGFloat, height: CGFloat) -> SCNGeometry {
let src = SCNGeometrySource(vertices: [
SCNVector3(-width / 2, -height / 2, 0),
SCNVector3(width / 2, -height / 2, 0),
SCNVector3(-width / 2, height / 2, 0),
SCNVector3(width / 2, height / 2, 0)
])
    let indices: [UInt32] = [0, 1, 2, 3]
    let normals = SCNGeometrySource(normals: [SCNVector3](repeating: SCNVector3(0, 0, 1), count: 4))
    let textureMap = SCNGeometrySource(textureCoordinates: [      CGPoint(x: 0, y: 1),
CGPoint(x: 1, y: 1),
CGPoint(x: 0, y: 0),
CGPoint(x: 1, y: 0)
])
let inds = SCNGeometryElement(indices: indices, primitiveType: .triangleStrip)
    return SCNGeometry(sources: [src, normals, textureMap], elements: [inds])
}
}

In the above I’ve also included normals and a texture map example. The normals will be automatically calculated, but I’ve left it in anyway so it’s clear how could be added. If the texture mapping doesn’t make sense, check out this page on how it works in OpenGL; the main difference being that the origin is at the top left in iOS, not the bottom left.

As you can see from the attached GIF, it looks exactly the same as a SCNPlane geometry.

The main difference doing this we don’t have access to the modifiers available with SCNPlane such as the corner radius, segment counts, but they can be added easily with a bit of math. Message me or leave a comment if you think it’d be worthwhile to add that!

SCNBox

SCNBox is typically a cuboid geometry with 6 rectangular faces (so 12 triangles) and 8 vertices. No skewing or anything like that so all we need is to have a width, height, and length for this one. Omitting chamferRadius for the time being.

A box could be made from triangles or triangleStrip, but I’ll go with triangles this time to change it up a bit. If you wanted to try this out yourself I’d highly recommend editing the indices to work with the triangleStrip type, as that would be the preferred method for making a cuboid, or any hexahedron for that matter.

First step is to get all the vertices (and again, on GitHub):

let w = width / 2
let h = height / 2
let l = length / 2
let src = SCNGeometrySource(vertices: [
// bottom 4 vertices
SCNVector3(-w, -h, -l),
SCNVector3(w, -h, -l),
SCNVector3(w, -h, l),
SCNVector3(-w, -h, l),
// top 4 vertices
SCNVector3(-w, h, -l),
SCNVector3(w, h, -l),
SCNVector3(w, h, l),
SCNVector3(-w, h, l)
])

It might take a second for you to see all those as the vertices, I’m assuming you have a width, height & length given, and am dividing them before hand because it’s easier to read and less computation for the app.

Now we have to draw all the triangles. Each face has 2 triangles, so needs 6 indices each, 2 of those will have the same edge. These are the indices I’ve calculated and have split up by cuboid face so that it’s easier to understand:

let indices: [UInt32] = [
// bottom face
0, 1, 3,
3, 1, 2,
// left face
0, 3, 4,
4, 3, 7,
// right face
1, 5, 2,
2, 5, 6,
// top face
4, 7, 5,
5, 7, 6,
// front face
3, 2, 7,
7, 2, 6,
// back face
0, 4, 1,
1, 4, 5,
]
let inds = SCNGeometryElement(indices: indices, primitiveType: .triangles)

And as before, using the convenience init of SCNGeometry:

let boxGeometry = SCNGeometry(source: [src], elements: [inds])

The result looks like this:

We’ve seen this before right? What’s the point?

The point is that once you have these foundations you can create slightly different geometries with just a little poking and no need to bring in external models.

The above cube has dimensions 0.2x0.2x0.2. If I create a new geometry type that I call, for example, SkewBox, which takes in an extra parameter skew: CGPoint I can change my vertices like this (also on GitHub):

let src = SCNGeometrySource(vertices: [
// bottom 4 vertices
SCNVector3(-w, -h, -l),
SCNVector3(w, -h, -l),
SCNVector3(w, -h, l),
SCNVector3(-w, -h, l),
// top 4 vertices
SCNVector3(-w + skew.x, h, -l + skew.y),
SCNVector3(w + skew.x, h, -l + skew.y),
SCNVector3(w + skew.x, h, l + skew.y),
SCNVector3(-w + skew.x, h, l + skew.y),
])

The output:

From here you can create any hexahedron at all! And then on to any shape beyond that.

The next step is animating a geometry to stretch and skew in a way that cannot be done simply by scaling a node, only by changing a geometry, such as the examples here:

The tutorial for this will be in Part 2

In my next post I go through how to create a demo just like the one above!

Click here to see Part 2. Also feel free to follow/message me on Twitter or LinkedIn if anything’s unclear or have any suggestions for future posts. Check out my GitHub for other projects.

相關推薦

ARKit + SceneKit Geometries Tutorial (Part 1)

What is a geometry object?First we need to understand what a geometry object is made up of. It’s essentially a collection of points (vertices) in 3D space

ARKit + SceneKit Geometries Tutorial (Part 2)

Animating a single vertexThe first thing we’re going to do is take a single vertex of the cube and have an animation that makes it look like it’s pulling a

Recurrent Neural Networks Tutorial, Part 1 – Introduction to RNNs學習筆記

介紹-什麼是RNN 1.RNN的主要思想是利用序列資訊。 The idea behind RNNs is to make use of sequential information. In a traditional neural network we assu

[Tutorial, Part 1] How to develop Go gRPC microservice with HTTP/REST endpoint, middleware…

[Tutorial, Part 1] How to develop Go gRPC microservice with HTTP/REST endpoint, middleware, Kubernetes deployment, etc.There are a lot of article how to cr

Lesson 2 Building your first web page: Part 1

appear mage ats ref with display sed emp bare In this ‘hands-on’ module we will be building our first web page in no time. W

linux操作系統及命令Part 1

oldboy ont pre 普通 下載 man tro 分隔符 所在 1.關於linux系統的安裝與流程 (1)下載Vmware workstation 與 linux系統(centos版本、redhat版本、Ubuntu版本...)鏡像。 (2)詳細安裝見

開啟Python取經之路-CLASS-6(Part 1

int code 中標 cnblogs 環境 執行 變量 spa -c 第一個python程序 HELLO WORLD 1 print("hello world") 單行註釋:# 多行註釋:‘‘‘....‘‘‘或者"""....""" 在linux編程中,要在程序中

if else流程判斷-CLASS-11(Part 1

color failed use log user clas elif 輸入 ger if判斷語句 1 if true: 2 print("true") 3 else: 4 print("false") 猜年齡大小 1 # Author:dd 2 ag

如何兩周達到150行Java程序的能力--part 1

指導 編譯 這也 結構 初始化 private rst 能力 知識點 面向對象程序先導課是體系化面向對象課程的重要組成部分,其目標是幫助那些有一定C語言基礎,但對面向對象概念陌生,基本沒碰過Java編程的同學。該課程設計為暑期選修課,因為沒有其他課程,我們設計為現場訓練性質

數據庫學習-part 1 約束

alter 主鍵 reat sql 關鍵字 alt table use ons 約束--待續 1,分類-實現            類型 關鍵字 建表實現方式 單獨實現方式 註意點 主鍵 primary key create table user (user_id

Writing a Bootloader Part 1

sam zone destroy .org 64 bit rac disk control bin This article series explains how to write a tiny 32-bit x86 operating system kernel. We

Python階段復習 - part 1 - Python基礎練習題

sort 階段 += art cnblogs .so range else 方法 1、實現1-100的所有的和 # 方法1: sum = 0 for i in range(1,101): sum += i print(sum) # 方法2: num

逆向破解 H.Koenig 遙控器 Part 1

body x64 模塊 做了 目前 完成 努力 而且 優惠 逆向破解 H.Koenig 遙控器(Part 1) 最近我正在嘗試一研究些自動吸塵器機器人。iRobot公司的Roomba貌似是該領域的領導者,但是作為實驗來講的話這些東西真是太昂貴了,我也找不到任何的折

C++ and OO Num. Comp. Sci. Eng. - Part 1.

nim num 內容 general -o 編譯時間 增加 radi gpo 本文參考自 《C++ and Object-Oriented Numeric Computing for Scientists and Engineers》。 序言 書中主要討論的問題是面向對象的

day 61 Django part-1 django的安裝,以及初學者三件套

true utf8 new 再看 gpo 停止 常用 筆記 red 老師的筆記: day61 1.前情回顧 1. pymysql 使用: 安裝 pip install pymysql

Smobiler 4.4 更新預告 Part 1(Smobiler能讓你在Visual Studio上開發APP)

p s source info 設置 屬性 mbr thum 詳情 thumb 在4.4版本中,大家對產品優化的一些建議和意見進行了相應的優化和修復,同時,還新增了一些令人激動的功能和插件。 下面先為大家介紹4.4版本中Smobiler的優化和修復: 優化 1, P

持續集成與持續部署寶典Part 1:將構建環境容器化

成熟 curl命令 設置 doc 包括 探討 完成 2.7 mage 介 紹隨著Docker項目及其相關生態系統逐漸成熟,容器已經開始被更多企業用在了更大規模的項目中。因此,我們需要一套連貫的工作流程和流水線來簡化大規模項目的部署。在本指南中,我們將從代碼開發、持續集成

Introductory: Seeing through Statistics - Part 1

比較 tween vat ESS oba ive 隨機 調查 simple ---------------------Chapter 1. The benefits and risks of using statistics----------------- 1. Stat

Django 教程 Part 1:請求與響應

arm pattern 處理 指導 一個 接收 網絡通信 生成 star 版本說明: 因為在撰寫本教程的時候,正逢Django從1.11向2.0轉變的時期,而教程的編寫是從17年8月開始的,前後共花了5個月左右的時間,所以使用的是1.11版本,局面非常尷尬。 實際上Djan

初級字典樹查找在 Emoji、關鍵字檢索上的運用 Part-1

行修改 諸多 解決 enume ref 數值 長度 關於 定位 系列索引 Unicode 與 Emoji 字典樹 TrieTree 與性能測試 生產實踐 前言 通常用戶自行修改資料是很常見的需求,我們規定昵稱長度在2到10之間。假設用戶試圖使用表情符號 ????????