Opengl 在SceneKit中,当与另一个对象几何体相交时,剪裁一个对象几何体
我正在尝试确定如何用一个对象剪裁另一个对象 球体是静止的,但平面在场景周围移动,并应在球体通过时剪裁球体。一切都在工作,直到平面剪辑球体的部分 SceneKit是否可以在不使用自定义Opengl 在SceneKit中,当与另一个对象几何体相交时,剪裁一个对象几何体,opengl,scenekit,Opengl,Scenekit,我正在尝试确定如何用一个对象剪裁另一个对象 球体是静止的,但平面在场景周围移动,并应在球体通过时剪裁球体。一切都在工作,直到平面剪辑球体的部分 SceneKit是否可以在不使用自定义SCNProgram着色器的情况下完成此任务 进度更新 计算平面方程 不是100%确定这是完全正确的。在宽笔划中-我有一个“假”切割平面,我保留在周围(并非严格必要),提取顶点,应用仿射变换,并尝试从中导出平面方程,最后将值传递给顶点着色器 let planeSources = _planeNode?.geomet
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")
}
}
顶点着色器片段
可变浮动剪辑;
#布拉格体
均匀vec4平面_方程;
浮动距离=点(_geometry.position.xyz,平面方程.xyz)+平面方程.w;
if(distance算法应如下所示(抽象描述,因为我不熟悉该API):
设Mi
为球体的反转模型矩阵(任何向量代数API似乎都提供了一些计算矩阵反转的方法)
设Ax+By+Cz+D=0
为世界坐标系中裁剪平面(CP)的方程(我猜您的意思是,平面方程在世界空间中描述)
乘法转置(反转(mat3_从mat4(Mi))*(A,B,C)
产生N'=(A',B',C')
设P
为某点,属于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
sh可以通过使用转置(mat3\u来自mat4(MVM(球体))*转置(反转(mat3\u来自mat4(MVM(平面)))
快速伪代码中的计划进行预乘变换
最简单的方案是测量与表示标记的平面和即将渲染的顶点之间的距离
计算平面方程
计算有符号距离-在顶点着色器中
如果距离小于或等于零,碎片将被丢弃,否则请执行您通常执行的操作。也许我遗漏了一些内容,但是:您的剪裁平面是无限的,因此您的实际平面(带有MVM)也是无限的吗?在这种情况下,我建议将vec3(0,1,0)或vec3(0,0,1)与mat3(MVM)相乘得到法线的平面,乘以向量4(0,0,0,1)使用MVM获取平面原点,然后使用将其转换为平面方程。我将此作为注释发布,因为我不太懂数学,这可能是非常错误的。@CameronLowellPalmer那么您需要在球体对象空间坐标中使用剪辑平面方程吗?我指的是摆脱同质c的标准化协调。还要注意,使用了modelMatrix
而不是我在gist上注意到的modelViewMatrix
。那么modelMatrix的值是什么?
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
}
// 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)
// Given the plane equation
let distance = planeEquation.x * vertex.x +
planeEquation.y * vertex.y +
planeEquation.z * vertex.z +
w