我试图确定如何将一个物体夹在另一个物体上。
球体是静止的,但是平面在场景中移动并且应该在球体穿过时剪切球体。一切正常,直到飞机夹住球体的部分。
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
}
到目前为止,这是基于平面在空间中的旋转而剪切的对象,但不是在平面接触的意义上。
答案 0 :(得分:2)
算法应该如下(抽象地描述,因为我不熟悉该API):
Mi
成为球体的倒置模型矩阵(任何向量代数API似乎都提供了一些计算矩阵求逆的方法); Ax+By+Cz+D=0
成为世界坐标中裁剪平面(CP)的等式(我想你的意思是,平面方程在世界空间中描述); transpose(invert(mat3_from_mat4(Mi)))*(A,B,C)
生成N'=(A',B',C')
; P
属于CP,属于CP。示例:P=(0,0,-D/C)
,提供,C不为零; Mi*(P.x,P.y,P.z,1.0)
生成P'=(A0',B0',C0',W0')
; P'
中的 w - 组件会产生P"=(A0'/W0',B0'/W0',C0'/W0')=(A0",B0",C0")
,这是球体对象空间坐标中的CP点; A'x+B'y+C'z-dot(N',P")=0
。编辑:如果在其局部空间中定义了平面,并且为球体和平面定义了相应的MVM,则算法稍有不同。相反,应首先使用平面的MVM将P
转换为公共眼睛空间,然后使用球体的反转MVM转换所获得的值。 N
应该通过与transpose(mat3_from_mat4(MVM(Sphere)))*transpose(invert(mat3_from_mat4(MVM(Plane))))
进行预乘来进行转换。
答案 1 :(得分:0)
最简单的方案是测量距离表示标记的平面和即将渲染的顶点的距离。
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)
如果距离小于或等于零,则丢弃片段,否则按照通常的方式进行。