MCR*_*MCR 5 3d objective-c ios scenekit swift
我得到了三分,需要绘制一个平滑的3D抛物线.问题是曲线是不稳定的,并且有一些奇怪的凹陷

这是我的代码......
func drawJump(jump: Jump){
let halfDistance = jump.distance.floatValue/2 as Float
let tup = CalcParabolaValues(0.0, y1: 0.0, x2: halfDistance, y2: jump.height.floatValue, x3: jump.distance.floatValue, y3: 0)
println("tuple \tup")
var currentX = 0 as Float
var increment = jump.distance.floatValue / Float(50)
while currentX < jump.distance.floatValue - increment {
let x1 = Float(currentX)
let x2 = Float((currentX+increment))
let y1 = calcParabolaYVal(tup.a, b: tup.b, c: tup.c, x: x1)
let y2 = calcParabolaYVal(tup.a, b: tup.b, c: tup.c, x: x2)
drawLine(x1, y1: y1, x2: x2, y2: y2)
currentX += increment
}
}
func CalcParabolaValues(x1: Float, y1: Float, x2: Float, y2: Float, x3: Float, y3: Float) -> (a: Float, b: Float, c: Float) {
println(x1, y1, x2, y2, x3, y3)
let a = y1/((x1-x2)*(x1-x3)) + y2/((x2-x1)*(x2-x3)) + y3/((x3-x1)*(x3-x2))
let b = (-y1*(x2+x3)/((x1-x2)*(x1-x3))-y2*(x1+x3)/((x2-x1)*(x2-x3))-y3*(x1+x2)/((x3-x1)*(x3-x2)))
let c = (y1*x2*x3/((x1-x2)*(x1-x3))+y2*x1*x3/((x2-x1)*(x2-x3))+y3*x1*x2/((x3-x1)*(x3-x2)))
return (a, b, c)
}
func calcParabolaYVal(a:Float, b:Float, c:Float, x:Float)->Float{
return a * x * x + b * x + c
}
func drawLine(x1: Float, y1: Float,x2: Float, y2: Float) {
println("drawLine \(x1) \(y1) \(x2) \(y2)")
let positions: [Float32] = [
x1, y1, 0,
x2, y2, 0
]
let positionData = NSData(bytes: positions, length: sizeof(Float32)*positions.count)
let indices: [Int32] = [0, 1]
let indexData = NSData(bytes: indices, length: sizeof(Int32) * indices.count)
let source = SCNGeometrySource(data: positionData, semantic: SCNGeometrySourceSemanticVertex, vectorCount: indices.count, floatComponents: true, componentsPerVector: 3, bytesPerComponent: sizeof(Float32), dataOffset: 0, dataStride: sizeof(Float32) * 3)
let element = SCNGeometryElement(data: indexData, primitiveType: SCNGeometryPrimitiveType.Line, primitiveCount: indices.count, bytesPerIndex: sizeof(Int32))
let line = SCNGeometry(sources: [source], elements: [element])
self.rootNode.addChildNode( SCNNode(geometry: line))
}
func renderer(aRenderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: NSTimeInterval) {
glLineWidth(20)
}
Run Code Online (Sandbox Code Playgroud)
我还必须弄清楚如何从左到右动画弧.有人可以帮我吗?Swift或Objective C很好.任何帮助表示赞赏.谢谢!
ric*_*ter 28
我建议使用SCNShape创建你的抛物线.首先,您需要将抛物线表示为Bézier曲线.你可以用UIBezierPath它.对于动画,我个人发现着色器修饰符非常适合这样的情况.
但请注意 - 您可能想要一条仅代表弧线开放行程的路径.如果您这样做:
let path = UIBezierPath()
path.moveToPoint(CGPointZero)
path.addQuadCurveToPoint(CGPoint(x: 100, y: 0), controlPoint: CGPoint(x: 50, y: 200))
Run Code Online (Sandbox Code Playgroud)
你会得到一个填充抛物线,就像这样(在调试器快速浏览中看到2D,然后用3D挤压SCNShape):


要创建一个仅为弧形的闭合形状,您需要追溯到曲线上,与原始曲线稍微偏离:
let path = UIBezierPath()
path.moveToPoint(CGPointZero)
path.addQuadCurveToPoint(CGPoint(x: 100, y: 0), controlPoint: CGPoint(x: 50, y: 200))
path.addLineToPoint(CGPoint(x: 99, y: 0))
path.addQuadCurveToPoint(CGPoint(x: 1, y: 0), controlPoint: CGPoint(x: 50, y: 198))
Run Code Online (Sandbox Code Playgroud)


那更好.
如何实际制作3D?只需按照SCNShape您喜欢的挤出深度制作:
let shape = SCNShape(path: path, extrusionDepth: 10)
Run Code Online (Sandbox Code Playgroud)
并在场景中设置它:
shape.firstMaterial?.diffuse.contents = SKColor.blueColor()
let shapeNode = SCNNode(geometry: shape)
shapeNode.pivot = SCNMatrix4MakeTranslation(50, 0, 0)
shapeNode.eulerAngles.y = Float(-M_PI_4)
root.addChildNode(shapeNode)
Run Code Online (Sandbox Code Playgroud)
这里我使用a pivot来使形状围绕抛物线的y = 0主轴旋转,而不是平面Bézier曲线的轴.并使它变蓝.此外,root这只是我为视图的场景根节点创建的快捷方式.
抛物线的形状并不需要通过动画来改变 - 你只需要一个沿着x轴逐渐显示它的视觉效果.着色器修改器非常适合这种情况,因为您可以为每个像素而不是每个顶点制作动画效果,并在GPU上执行所有昂贵的工作.
这是一个着色器片段,它使用一个progress参数,从0到1不等,根据x位置设置不透明度:
// declare a variable we can set from SceneKit code
uniform float progress;
// tell SceneKit this shader uses transparency so we get correct draw order
#pragma transparent
// get the position in model space
vec4 mPos = u_inverseModelViewTransform * vec4(_surface.position, 1.0);
// a bit of math to ramp the alpha based on a progress-adjusted position
_surface.transparent.a = clamp(1.0 - ((mPos.x + 50.0) - progress * 200.0) / 50.0, 0.0, 1.0);
Run Code Online (Sandbox Code Playgroud)
将其设置为Surface入口点的着色器修改器,然后您可以为progress变量设置动画:
let modifier = "uniform float progress;\n #pragma transparent\n vec4 mPos = u_inverseModelViewTransform * vec4(_surface.position, 1.0);\n _surface.transparent.a = clamp(1.0 - ((mPos.x + 50.0) - progress * 200.0) / 50.0, 0.0, 1.0);"
shape.shaderModifiers = [ SCNShaderModifierEntryPointSurface: modifier ]
shape.setValue(0.0, forKey: "progress")
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(10)
shape.setValue(1.0, forKey: "progress")
SCNTransaction.commit()
Run Code Online (Sandbox Code Playgroud)

这是您可以粘贴到(iOS)游乐场的表单中的全部内容.一些事情留给读者练习,加上其他注意事项:
将神奇的数字分解出来并制作一个函数或类,这样你就可以改变抛物线的大小/形状.(请记住,您可以相对于其他场景元素缩放SceneKit节点,因此它们不必使用相同的单位.)
将抛物线相对于其他场景元素定位.如果你拿走我设置的线pivot,那shapeNode.position就是抛物线的左端.更改抛物线的长度(或缩放),然后围绕其y轴旋转,您可以使另一端与其他节点对齐.(为了你发射导弹?)
我把它和Swift 2测试版一起扔了,但我不认为那里有任何特定于Swift-2的语法 - 如果你需要尽快部署,那么移植回1.2应该是直截了当的.
如果你也想在OS X上做这个,那就有点麻烦 - 那里,SCNShape使用NSBezierPath,不像UIBezierPath不支持二次曲线.可能一个简单的方法是用椭圆弧伪造它.