在SceneKit中,当与另一个相交时,剪切一个对象几何

时间:2015-08-06 19:59:48

标签: opengl scenekit

我试图确定如何将一个物体夹在另一个物体上。

Plane slicing sphere

球体是静止的,但是平面在场景中移动并且应该在球体穿过时剪切球体。一切正常,直到飞机夹住球体的部分。

SceneKit可以在不使用自定义SCNProgram着色器的情况下完成此操作吗?

进度更新

计算平面方程

不是100%确定这是完全正确的。粗略地说 - 我有一个假的'我保留的切割平面(非必要),提取顶点,应用仿射变换,并尝试从中导出平面方程,最后将值传递给顶点着色器。

let planeSources = _planeNode?.geometry?.geometrySourcesForSemantic(SCNGeometrySourceSemanticVertex)
if let planeSource = planeSources?.first {
    let stride = planeSource.dataStride
    let offset = planeSource.dataOffset
    let componentsPerVector = planeSource.componentsPerVector
    let bytesPerVector = componentsPerVector * planeSource.bytesPerComponent

    let vectors = [SCNVector3](count: planeSource.vectorCount, repeatedValue: SCNVector3Zero)
    let vertices = vectors.enumerate().map({
        (index: Int, _) -> SCNVector3 in
        var vectorData = [Float](count: componentsPerVector, repeatedValue: 0)
        let byteRange = NSMakeRange(index * stride + offset, bytesPerVector)
        planeSource.data.getBytes(&vectorData, range: byteRange)
        return SCNVector3Make(vectorData[0], vectorData[1], vectorData[2])
    })

    let mat4Transform = SCNMatrix4ToMat4(transform)
    let transformedVertices = vertices.map({
        (vertex: SCNVector3) -> vector_float3 in
        let float4Vector = SCNVector4ToFloat4(vertex.to4(1.0))
        let transformedVertex = matrix_multiply(mat4Transform, float4Vector)
        return vector3(transformedVertex.x, transformedVertex.y, transformedVertex.z)
    })

    if transformedVertices.count >= 3 {
        let vertex0 = transformedVertices[0]
        let vertex1 = transformedVertices[1]
        let vertex2 = transformedVertices[2]

        let v1v0 = vertex1 - vertex0
        let v2v0 = vertex2 - vertex0
        let normal = vector_cross(v1v0, v2v0)
        let distance = vector_dot(normal, vertex0)
        let planeEquation = -1.0 * vector4(normal, distance)
        let planeEquationValue = NSValue(SCNVector4: SCNVector4FromFloat4(planeEquation))

        self._heartNode?.geometry?.setValue(planeEquationValue, forKey: "plane_equation")
    }
}

顶点着色器片段

varying float clipFragment;

#pragma body
uniform vec4 plane_equation;

float distance = dot(_geometry.position.xyz, plane_equation.xyz) + plane_equation.w;
if (distance <= 0.0) {
    clipFragment = 1.0; // Discard fragment
} else {
    clipFragment = 0.0; // Keep fragment
}

到目前为止,这是基于平面在空间中的旋转而剪切的对象,但不是在平面接触的意义上。

Sliced Heart

2 个答案:

答案 0 :(得分:2)

算法应该如下(抽象地描述,因为我不熟悉该API):

  1. Mi成为球体的倒置模型矩阵(任何向量代数API似乎都提供了一些计算矩阵求逆的方法);
  2. Ax+By+Cz+D=0成为世界坐标中裁剪平面(CP)的等式(我想你的意思是,平面方程在世界空间中描述);
  3. 乘法transpose(invert(mat3_from_mat4(Mi)))*(A,B,C)生成N'=(A',B',C');
  4. P属于CP,属于CP。示例:P=(0,0,-D/C),提供,C不为零;
  5. 乘法Mi*(P.x,P.y,P.z,1.0)生成P'=(A0',B0',C0',W0');
  6. 摆脱P'中的 w - 组件会产生P"=(A0'/W0',B0'/W0',C0'/W0')=(A0",B0",C0"),这是球体对象空间坐标中的CP点;
  7. 所需的等式为A'x+B'y+C'z-dot(N',P")=0
  8. 编辑:如果在其局部空间中定义了平面,并且为球体和平面定义了相应的MVM,则算法稍有不同。相反,应首先使用平面的MVM将P转换为公共眼睛空间,然后使用球体的反转MVM转换所获得的值。 N应该通过与transpose(mat3_from_mat4(MVM(Sphere)))*transpose(invert(mat3_from_mat4(MVM(Plane))))进行预乘来进行转换。

答案 1 :(得分:0)

Swifty Pseudocode中的计划

最简单的方案是测量距离表示标记的平面和即将渲染的顶点的距离。

计算平面方程

tar cpf - site.com|pv -b -a -t|ssh -p 2204 root@removeip "tar xf - -C /destination/"

计算有符号距离 - 在顶点着色器中

// Using something like SKLinearAlgebra for cross(), dot(), and to4()
// The marker vertices - these need to be counter-clockwise?
let origin = vertices[0]
let vector1 = vertices[1]
let vector2 = vertices[2]
let normal = SCNVector3.cross(vector1, vector2)
let distance = SCNVector3.dot(normal, vector0)

let planeEquation = normal.to4(distance)

如果距离小于或等于零,则丢弃片段,否则按照通常的方式进行。