Stroke Width with a SceneKit line primitive type
SceneKit doesn't provide controls for this. However, SceneKit draws using OpenGL ES, which does.
When you're drawing with GL in the GL_LINES
mode, the glLineWidth
call changes the line width. (Watch out: the argument is in actual pixels, not UI-layout points, so you'll need a larger width than you might think if you don't want super-thin hairlines on a Retina display.)
So, where do you call that in your SceneKit app? You have a few options there. In a simple scene like yours, where you're only rendering one thing, you can just set it before the scene renders. Set a delegate for your view, then implement renderer:willRenderSceneAtTime:
and call glLineWidth
there.
However, OpenGL line rendering is pretty limited — if you want to customize rendering more, you'll need a different approach. Just which approach works best depends on exactly what you're going for, so here are a few ideas for you to research:
- Make your "lines" from narrow triangle strips
- Make them from primitive SCN geometries like boxes and cylinders
- Keep a simple cube geometry, but use a fragment shader (or shader modifier snippet) to draw only near the edges of each polygon
iOS Metal line width
Short answer would be there is no way to control line width in the same way as a point size in Metal. Even in OpenGL graphics API, the function to do this (which used to exist as gllinewidth function) is now deprecated.
An option would be to draw the line as a quad (a box), with two triangles. This would let you control the width of the line.
If you want to stick to the line primitive itself, for some particular reason, the equivalent OpenGL question has been asked on StackOverflow already as seen here. The shader can be simple translated to Metal shading API.
SceneKit- Cannot query using bitmask
SceneKit
In SceneKit you can use bitmasks in context of [SCNHitTestResult]. hitTest(_:options:)
instance method is not deprecated yet and it works in iOS 15.4.
let sceneView = ARSCNView(frame: .zero)
enum HitTestType: Int {
case object_A = 0b00000001
case object_B = 0b00000010
}
let point: CGPoint = gesture.location(in: self.sceneView)
let bitMask = HitTestType.object_A.rawValue | HitTestType.object_B.rawValue
let results = sceneView.hitTest(point, options: [.categoryBitMask: bitMask])
P.S.
Only hitTest(_:types:) is deprecated at the moment.
RealityKit
In RealityKit you can use bitmasks in CollisionCastHit's context:
let arView = ARView(frame: .zero)
let point: CGPoint = gesture.location(in: self.arView)
let (origin, direction) = arView.ray(through: point)!
let raycasts: [CollisionCastHit] = arView.scene.raycast(origin: origin,
direction: direction,
length: 50,
query: .any,
mask: .default,
relativeTo: nil)
...or this way:
let raycasts: [CollisionCastHit] = arView.hitTest(point,
query: .any,
mask: .default)
I need help to draw an icosahedron 3D object in an UIKit app
to build an icosahedron you can use SCNSphere
and set its geodesic
property to YES
.
Using shader modifiers to draw the wireframe (as described in Stroke Width with a SceneKit line primitive type) is a good idea.
But in your case lines are not always plain or dotted — it depends on the orientation of the icosahedron. To solve that you can rely on gl_FrontFacing
to determine whether the edge belongs to a front-facing or back-facing triangle.
SCNGeometry / SCNCylinder render edges / border only (Store color, clear content)
The WWDC 2014 presentation showed orbiting cubes that had only wireframes. The technique was to use an image with green edges but transparent interior as the material. From AAPLSlideScenegraphSummary.m:
// A node that will help visualize the position of the stars
_wireframeBoxNode = [SCNNode node];
_wireframeBoxNode.rotation = SCNVector4Make(0, 1, 0, M_PI_4);
_wireframeBoxNode.geometry = [SCNBox boxWithWidth:1 height:1 length:1 chamferRadius:0];
_wireframeBoxNode.geometry.firstMaterial.diffuse.contents = [NSImage imageNamed:@"box_wireframe"];
_wireframeBoxNode.geometry.firstMaterial.lightingModelName = SCNLightingModelConstant; // no lighting
_wireframeBoxNode.geometry.firstMaterial.doubleSided = YES; // double sided
For a similar effect with SCNCylinder, you might need to pass an array of materials, some with border and some without.
Edit
For High Sierra/iOS 11 and higher, the answer by @mnuages is a simpler/better approach.
Related Topics
Afnetworking 2.2.0 Upload Image on Server Issues
How to Connect SQLite Database in iOS
How to Clear/Reset All Coredata in One-To-Many Relationship
Expandable Uitableview Cell Using Autolayout Results in Uiviewalertforunsatisfiableconstraints
Check If Username Already Exist'S:Swift, Firebase
How to Properly Structure Firebase Database to Allow Easy Reading and Removal
Avassetwriter Avvideoexpectedsourceframeratekey (Frame Rate) Ignored
Firebase Queryorderedbychild() Method Not Giving Sorted Data
API Facebook iPhone , Possible to Post to a Friend's Wall
Swipe Left or Right to Load the View Controller with the Collection View Cell Highlight
Always Got Nil Value from the Function in iOS
How to Make Alamofire Download Progress Run in Background iOS
iOS Nsnotificationcenter to Check Whether the App Came from Background to Foreground
Non-Nominal Type X Does Not Support Explicit Initialization
Are Storyboards Going to Work on iOS 4
Application Is "Ready to Sale" But Not Reflected on Itunes Store