Creating a custom SCNGeometry polygon
When use polygon , you have to use
init(data: Data?, primitiveType: SCNGeometryPrimitiveType, primitiveCount: Int, bytesPerIndex: Int)
to init the SCNGeometryElement. See apple doc for details.
SCNGeometry with polygon as primitiveType
You have two problems:
SceneKit (and Metal) only support 32 bit integers as indices (source).
So the type of your indices array needs to be[Int32]
.SceneKit needs two pieces of information for polygons: The number of points in the polygon and the index of the point in the vertex array.
From Apple's documentation onSCNGeometryPrimitiveTypePolygon
(which only exists in Objective-C):
The element’s data property holds two sequences of values.
- The first sequence has a number of values equal to the geometry element’s
primitiveCount value. Each value in this sequence specifies the number of vertices in a polygon primitive. For example, if the first sequence is [5, 3], the geometry element contains a pentagon followed by a triangle.- The rest of the data is a sequence of vertex indices. Each entry in the first sequence specifies a corresponding number of entries in the second sequence. For example, if the first sequence includes the values [5, 3], the second sequence includes five indices for the pentagon, followed by three indices for the triangle.
You need to change your index array to:
let indices: [Int32] = [7, /* We have a polygon with seven points */,
0,1,2,3,4,5,6 /* The seven indices for our polygon */
]
Then, set the primitiveCount
to 1 (we have one polygon to draw) and change the size of the buffer:
let indexData = Data(bytes: indices,
count: indices.count * MemoryLayout<Int32>.size)
// Now without runtime error
let element = SCNGeometryElement(data: indexData,
primitiveType: .polygon,
primitiveCount: 1,
bytesPerIndex: MemoryLayout<Int32>.size)
How to generating a concave or convex polygon plane in SceneKit from SCNVector3
The SCNShape
class creates a suited triangulation on your behalf.
Using SCNGeometryTessellator with a SCNGeometry that uses a custom SCNProgram?
Once you add a tessellator
an SCNGeometry
, your SCNProgram
needs to use a post-tessellation vertex function instead of a standard vertex function. The only doc I've found that really covers this is Apple's metal tessellation programming guide
While I'm not an expect on Metal tessellation, here's my understanding of the issue:
Let's say your normal vertex function looks something like this:
struct VertexInput {
float3 position [[attribute(SCNVertexSemanticPosition)]];
float3 normal [[attribute(SCNVertexSemanticNormal)]];
float2 texCoords [[attribute(SCNVertexSemanticTexcoord0)]];
};
vertex ColorInOut myVertexShader(VertexInput in [[ stage_in ]], ...) {
...
}
The error about Attribute 0 incompatible with MTLStepFunctionPerPatchControlPoint
is explaining that your input type (VertexInput
) does not match the expected vertex input for the current render pipeline. This is because once you add tessellation, the render pipeline changes to use a special post tessellation vertex function instead of a standard vertex function.
A post tessellation vertex function takes input from the tessellator instead of from your geometry. Here's the above vertex shader converted to a post tessellation vertex function:
struct PatchIn {
patch_control_point<VertexInput> control_points;
};
[[patch(triangle, 3)]]
vertex ColorInOut myVertexShader(PatchIn patchIn [[stage_in]],
float3 patch_coord [[ position_in_patch ]], ...)
{
// We have to compute the correct input positions from the tessellation data
// Note that there's probably a cleaner/better way to do this
// Barycentric coordinates
float u = patch_coord.x;
float v = patch_coord.y;
float w = patch_coord.z;
// Convert to cartesian coordinates
const float3 pos = float3(
u * patchIn.control_points[0].position.x + v * patchIn.control_points[1].position.x + w * patchIn.control_points[2].position.x,
u * patchIn.control_points[0].position.y + v * patchIn.control_points[1].position.y + w * patchIn.control_points[2].position.y,
u * patchIn.control_points[0].position.z + v * patchIn.control_points[1].position.z + w * patchIn.control_points[2].position.z);
...
}
After rewriting the vertex function to a post tessellation vertex function, your geometry should render with tessellation and your custom SCNProgram
How to draw curved polygon in ARKit?
You can draw a curved Polygonal Model in ARKit
/SceneKit
using several polygons, not single one. For nice curvature 30 to 100 polygons needed.
But if you meant whether ARKit
/SceneKit
supports NURBS Models like Maya or 3dsMax does – the answer is NO. You have an API only for Poly Modeling.
For further information please read the following SO post.
Related Topics
Swift - Get Nsbundle for Test Target
Core Data: Could Not Cast Value of Type 'Mytype_Mytype_2' to Mytype
Show Folder's Contents in Finder Using Swift
Use a Function to Find Common Elements in Two Sequences in Swift
How Are Optional Values Implemented in Swift
Count Number of Decimal Places in a Float (Or Decimal) in Swift
Propertywrappers and Protocol Declaration
Multi-Component Picker (Uipickerview) in Swiftui
How to Utilize Nslock to Prevent a Function from Firing Twice
How to Resume Audio After Interruption in Swift
Peak Detection for Growing Time Series Using Swift
Using "If Let" with Logical "Or" Operator