pointSize property being ignored

Hello,


I'm trying to render a point cloud using SceneKit (ultimately for ARKit). However, I'm finding the pointSize (and minimumPointScreenSpaceRadius) properties are ignored when trying to modify the SCNGeometryElement. No matter what pointSize I put in, the points are the same size. This is roughly how my code is laid out. I'm wondering if I'm doing something wrong with my GeometryElement setup?


     var index: Int = 0
        for x_pos in stride(from: start , to: end, by: increment) {
            for y_pos in stride(from: start , to: end, by: increment) {
                for z_pos in stride(from: start , to: end, by: increment) {
                    let pos:SCNVector3 = SCNVector3(x: x_pos, y: y_pos, z: z_pos)
                    positions.append(pos)
                    normals.append(normal)
                    indices.append(index)
                    index = index + 1
                }
            }
        }
       
        let pt_positions : SCNGeometrySource = SCNGeometrySource.init(vertices: positions)
        let n_positions: SCNGeometrySource = SCNGeometrySource.init(normals: normals)
       
        let pointer = UnsafeRawPointer(indices)
        let indexData = NSData(bytes: pointer, length: MemoryLayout<Int32>.size * indices.count)
       
        let elements = SCNGeometryElement(data: indexData as Data, primitiveType: .point, primitiveCount: positions.count, bytesPerIndex: MemoryLayout<Int>.size)
        elements.pointSize = 10.0 //being ignored
        elements.minimumPointScreenSpaceRadius = 10 //also being ignored
        let pointCloud = SCNGeometry (sources: [pt_positions, n_positions], elements: [elements])
        pointCloud.firstMaterial?.lightingModel = SCNMaterial.LightingModel.constant
       
       
        let ptNode = SCNNode(geometry: pointCloud)
        scene.rootNode.addChildNode(ptNode)

Replies

     let elements = SCNGeometryElement(data: indexData as Data, primitiveType: .point, primitiveCount: positions.count, bytesPerIndex: MemoryLayout<Int>.size)
        elements.pointSize = 10.0 //being ignored
        elements.minimumPointScreenSpaceRadius = 10 //also being ignored



I would (a) toss some nslog/print statements in there to confirm those lines are being hit and (b), be consistent with 10.0 vs. 10


>This is roughly how my code is laid out.


I'd hope that means the code snippet you shared isn't pseudo.

This works for me, but draw a 50 points big dot…


geometryElements.pointSize = 10.0
geometryElements.minimumPointScreenSpaceRadius = 50.0

Interesting! So I tried a range from 10.0 to 500.0 and there was no visible change. I'm wondering if I'm not setting up my geometryElements incorrectly. Do you mind showing me how you setup the geometryElements variable?

/
let point1LB:SCNVector3 = SCNVector3Make(0.0, 0.0, 0.0)
let point1RB:SCNVector3 = SCNVector3Make(0.25, 0.0, 0.0)
let point1LT:SCNVector3 = SCNVector3Make(0.0, 0.25, 0.0)
let point1RT:SCNVector3 = SCNVector3Make(0.25, 0.25, 0.0)
let point2LB:SCNVector3 = SCNVector3Make(0.5, 0.5, 0.0)
let point2RB:SCNVector3 = SCNVector3Make(0.75, 0.5, 0.0)
let point2LT:SCNVector3 = SCNVector3Make(0.5, 0.75, 0.0)
let point2RT:SCNVector3 = SCNVector3Make(0.75, 0.75, 0.0)
let verticesArray:[SCNVector3] = [point1LB,point1LT,point1RT,point1RB,
                                  point2LB,point2LT,point2RT,point2RB]    / 
let lineGeometrySource = SCNGeometrySource(vertices:verticesArray)
/
let indexBufferArray:[UInt8] = [0,3,1,2  ,2,4,  4,7,5,6]    /
let indexBufferData:Data = Data(bytes:indexBufferArray, count:(MemoryLayout<UInt8>.size * indexBufferArray.count))
let geometryElements:SCNGeometryElement = SCNGeometryElement(data:indexBufferData,
                                                             primitiveType:SCNGeometryPrimitiveType.point,
                                                             primitiveCount:(indexBufferArray.count - 2),
                                                             bytesPerIndex:MemoryLayout<UInt8>.size)
geometryElements.pointSize = 1.0    /
geometryElements.minimumPointScreenSpaceRadius = 10.0
geometryElements.maximumPointScreenSpaceRadius = 10.0
/
let lineGeometry:SCNGeometry = SCNGeometry(sources:[lineGeometrySource], elements:[geometryElements])
let lineMaterial:SCNMaterial = lineGeometry.firstMaterial!
lineMaterial.lightingModel = SCNMaterial.LightingModel.constant
lineMaterial.diffuse.contents = NSColor.green
lineMaterial.isLitPerPixel = false
lineMaterial.isDoubleSided = true    /
lineMaterial.writesToDepthBuffer = false
let lineNode:SCNNode = SCNNode(geometry:lineGeometry)
scene.rootNode.addChildNode(lineNode)

Thanks! So I ran this code verbatim and am still getting tiny green dots instead of large ones with

geometryElements.pointSize = 10.0    / 
geometryElements.minimumPointScreenSpaceRadius = 50.0

I also made sure I wasn't running OpenGL by mistake, but that's not the case.


Super odd.

A different approach:


Assign a metal shader with the following essentials:


struct SimpleVertex
{
    float  pointsize[[point_size]];
};


In vertex shader portion:

     SimpleVertex vert;
     vert.pointsize = 16.0
     return vert;


fragment shader portion:

fragment MyFragmentOutput myVertFragment(SimpleVertex in [[stage_in]],
                           float2 pointCoord [[point_coord]])
{
    MyFragmentOutput frag;
    float l = length(pointCoord - float2(0.5));
    if (l > 0.5) { //to create round 'points' instead of the default square
        discard_fragment();
    }
     return frag;
}


I hope this helps.

This works for me

Code Block Swift
   particles.pointSize = 10.0
    particles.minimumPointScreenSpaceRadius = 2.5
    particles.maximumPointScreenSpaceRadius = 2.5


You need to increase the min/max values as stated in the doc


Discussion
Some visual effects call for rendering a geometry as a collection of individual points—that is, a point cloud, not a solid surface or wireframe mesh. When you use this option, SceneKit can render each point as a small 2D surface that always faces the camera. By applying a texture or custom shader to that surface, you can efficiently render many small objects at once.
To render a geometry element as a point cloud, you must set three properties: pointSize, minimumPointScreenSpaceRadius, and maximumPointScreenSpaceRadius. Use pointSize to determine how large each point appears in world space, so that points farther away appear as smaller 2D surfaces. Use the minimum and maximum radius properties to ensure that the on-screen rendering of each point fits within a certain range of pixel sizes.
For example, to render a point cloud where each point is always one pixel wide (like a field of stars), set both the minimum and maximum sizes to one pixel. To render a group of objects whose screen sizes vary with perspective (like a set of images representing planets), set the minimum size to one pixel and the maximum size to a much larger value.