ki.c
ki.c

Reputation: 23

3D Cross Section using ARKit and SceneKit

I am trying to create a sphere with a cross-section view in Swift using ARKit and SceneKit.

When I am clipping/cutting the sphere with two planes, and try to move the device (iPad) around the sphere, the rendering is not as expected. The expected view of the object is a sphere with two planes cut. If I move the device around, I will see the rendering changes as the device moves. The video should show how it behaves when the device moves: https://youtu.be/m-YuHMxJoJk

func applyCrossSection() {
        print("Applying cross section")
        guard !selectedLines.isEmpty,
              let sphereNode = currentSphereNode,
              let sphere = sphereNode.geometry as? SCNSphere else {
        print("Failed to apply cross section: selectedLines count=\(selectedLines.count), sphereNode=\(String(describing: currentSphereNode))")
                return
        }

        // Determine if we use a horizontal or vertical cut.
        let isHorizontal = selectedLines[0].name == "horizontalLine"
        // Choose a fixed axis in world space.
        let fixedAxis: SCNVector3 = isHorizontal ? SCNVector3(0, 1, 0) : SCNVector3(1, 0, 0)
        // Use the sphere's presentation world position to get an up-to-date center.
        let sphereCenter = sphereNode.presentation.worldPosition
        
        // Compute the projection (scalar) of each selected line's first dot along the fixed axis.
        var projections: [Float] = []
        for line in selectedLines {
            if let firstDot = line.childNodes.first {
                let diff = firstDot.worldPosition - sphereCenter
                // Dot product with the fixed axis.
                let proj = diff.x * fixedAxis.x + diff.y * fixedAxis.y + diff.z * fixedAxis.z
                projections.append(proj)
            }
        }
        projections.sort()
        guard let minVal = projections.first, let maxVal = projections.last else {
            print("No valid positions found from selected lines")
            return
        }
        print("minVal:", minVal, ", maxVal:", maxVal)
        // Convert the fixed axis into the sphere's local coordinate system.
        var cutAxisInSphere = sphereNode.convertVector(fixedAxis, from: nil)
        
        let axisLength = sqrt(cutAxisInSphere.x * cutAxisInSphere.x +
                             cutAxisInSphere.y * cutAxisInSphere.y +
                             cutAxisInSphere.z * cutAxisInSphere.z)
        if axisLength != 0 {
           cutAxisInSphere.x /= axisLength
           cutAxisInSphere.y /= axisLength
           cutAxisInSphere.z /= axisLength
        }

        print("Cut axis in sphere:", cutAxisInSphere, "min:", minVal, "max:", maxVal)
        
        // Build shader code using the fixed cut axis.
        let shaderCode = """
        #pragma arguments
        float u_min;
        float u_max;
        float3 u_cutAxis;
        #pragma body
        {
            float d = dot(_surface.position, u_cutAxis);
            if (d < u_min || d > u_max) {
                discard_fragment();
            }
        }
        """
        sphereNode.geometry?.firstMaterial?.shaderModifiers = [.surface: shaderCode]
        sphereNode.geometry?.firstMaterial?.setValue(minVal, forKey: "u_min")
        sphereNode.geometry?.firstMaterial?.setValue(maxVal, forKey: "u_max")
        sphereNode.geometry?.firstMaterial?.setValue(NSValue(scnVector3: cutAxisInSphere), forKey: "u_cutAxis")

  // Optionally update visual cutting planes for debugging.
        addVisualPlanesForCrossSection(
            sphere: sphere,
            sphereNode: sphereNode,
            horizontalPositions: isHorizontal ? projections : [],
            verticalPositions: isHorizontal ? [] : projections
        )
    print("Cross section applied.")
}

I am guessing that it is the problem with the discard_fragment() method in metal? Or something related to the transform? I'm not quite sure on what's going on as I am new to SceneKit and ARKit.

Any help would be highly appreciated, thank you!

Upvotes: 0

Views: 23

Answers (0)

Related Questions