Creating a Custom Scngeometry Polygon Plane with Scngeometryprimitivetype Polygon Crash/Error

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:

  1. SceneKit (and Metal) only support 32 bit integers as indices (source).
    So the type of your indices array needs to be [Int32].

  2. 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 on SCNGeometryPrimitiveTypePolygon (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.

Sample Image

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



Leave a reply



Submit