在两点之间绘制 SceneKit 对象 [英] Draw SceneKit object between two points

查看:31
本文介绍了在两点之间绘制 SceneKit 对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题是如果元素在 X 上不对称会发生什么,因此必须旋转 SCNCylinder.我找到了这个例子,但是我无法理解具体细节......它似乎利用了球体对称的事实,因此角度有点消失".

有没有人有一个通用的函数,可以取两个3D点,返回适合设置节点eulerAngle的SCNVector3,或者类似的解决方案?

解决方案

上面提到的两种解决方案都非常有效,我可以为这个问题贡献第三种解决方案.

//扩展代码开始func normalizeVector(_ iv: SCNVector3) ->SCNVector3 {让长度 = sqrt(iv.x * iv.x + iv.y * iv.y + iv.z * iv.z)如果长度 == 0 {返回 SCNVector3(0.0, 0.0, 0.0)}返回 SCNVector3(iv.x/长度,iv.y/长度,iv.z/长度)}扩展 SCNNode {func buildLineInTwoPointsWithRotation(from startPoint: SCNVector3,到终点:SCNVector3,半径:CGFloat,颜色:UIColor)->SCN节点{让 w = SCNVector3(x: endPoint.x-startPoint.x,y:endPoint.y-startPoint.y,z: endPoint.z-startPoint.z)让 l = CGFloat(sqrt(w.x * w.x + w.y * w.y + w.z * w.z))如果 l == 0.0 {//两个点在一起.让球体 = SCNSphere(半径:半径)sphere.firstMaterial?.diffuse.contents = 颜色self.geometry = 球体self.position = startPoint回归自我}让 cyl = SCNCylinder(半径:半径,高度:l)cyl.firstMaterial?.diffuse.contents = 颜色self.geometry = cyl//圆柱体在0,0,0以上的原始向量让 ov = SCNVector3(0, l/2.0,0)//目标向量,在新的协调让 nv = SCNVector3((endPoint.x - startPoint.x)/2.0, (endPoint.y - startPoint.y)/2.0,(endPoint.z-startPoint.z)/2.0)//两个向量之间的轴让 av = SCNVector3( (ov.x + nv.x)/2.0, (ov.y+nv.y)/2.0, (ov.z+nv.z)/2.0)//归一化轴向量让 av_normalized = normalizeVector(av)let q0 = Float(0.0)//cos(angel/2),角度总是180或M_PI让 q1 = Float(av_normalized.x)//x' * sin(angle/2)让 q2 = Float(av_normalized.y)//y' * sin(angle/2)让 q3 = Float(av_normalized.z)//z' * sin(angle/2)让 r_m11 = q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3让 r_m12 = 2 * q1 * q2 + 2 * q0 * q3让 r_m13 = 2 * q1 * q3 - 2 * q0 * q2让 r_m21 = 2 * q1 * q2 - 2 * q0 * q3让 r_m22 = q0 * q0 - q1 * q1 + q2 * q2 - q3 * q3让 r_m23 = 2 * q2 * q3 + 2 * q0 * q1让 r_m31 = 2 * q1 * q3 + 2 * q0 * q2让 r_m32 = 2 * q2 * q3 - 2 * q0 * q1让 r_m33 = q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3self.transform.m11 = r_m11self.transform.m12 = r_m12self.transform.m13 = r_m13self.transform.m14 = 0.0self.transform.m21 = r_m21self.transform.m22 = r_m22self.transform.m23 = r_m23self.transform.m24 = 0.0self.transform.m31 = r_m31self.transform.m32 = r_m32self.transform.m33 = r_m33self.transform.m34 = 0.0self.transform.m41 = (startPoint.x + endPoint.x)/2.0self.transform.m42 = (startPoint.y + endPoint.y)/2.0self.transform.m43 = (startPoint.z + endPoint.z)/2.0self.transform.m44 = 1.0回归自我}}//扩展结束.//在你的代码中,你可以喜欢这个.让 twoPointsNode1 = SCNNode()scene.rootNode.addChildNode(twoPointsNode1.buildLineInTwoPointsWithRotation(从:SCNVector3(1,-1,3),到:​​SCNVector3(7,11,7),半径:0.2,颜色:.cyan))//结尾

您可以参考http://danceswithcode.net/engineeringnotes/quaternions/quaternions.html

顺便说一句,当您使用圆柱体在上述 3 种方法的两点之间绘制一条线时,您将获得相同的结果.但确实,它们会有不同的法线.换句话说,如果在两点之间使用框,框的侧面除了顶部和底部之外,将与上述三种方法面向不同的方向.

如果您需要进一步解释,请告诉我.

Having made some progress in the geometry side of things I'm moving on to putting together an entire scene. That scene has a couple dozen objects, each defined by a bounding cube whose corners are specified by two SCNVector3s (originally two sets of x,y,z).

Here's an example of what I have so far - it's an 11-element log-periodic antenna, like the old school TV antennas from the 70s. Each of the grey lines is an "element", typically made of aluminum rod. I used SCNCylinders from +ve to -ve Y and the entire thing is less than 100 lines (SK is pretty amazing).

The problem is what happens if the elements are not symmetrical across X and thus the SCNCylinder has to be rotated. I found this example, but I can't understand the specifics... it appears to take advantage of the fact that a sphere is symmetric so angles kind of "go away".

Does anyone have a general function that will take two 3D points and return the SCNVector3 suitable for setting the node's eulerAngle, or a similar solution?

解决方案

Both solutions mentioned above work very well and I can contribute third solution to this question.

//extension code starts

func normalizeVector(_ iv: SCNVector3) -> SCNVector3 {
    let length = sqrt(iv.x * iv.x + iv.y * iv.y + iv.z * iv.z)
    if length == 0 {
        return SCNVector3(0.0, 0.0, 0.0)
    }

    return SCNVector3( iv.x / length, iv.y / length, iv.z / length)

}

extension SCNNode {

    func buildLineInTwoPointsWithRotation(from startPoint: SCNVector3,
                              to endPoint: SCNVector3,
                              radius: CGFloat,
                              color: UIColor) -> SCNNode {
        let w = SCNVector3(x: endPoint.x-startPoint.x,
                           y: endPoint.y-startPoint.y,
                           z: endPoint.z-startPoint.z)
        let l = CGFloat(sqrt(w.x * w.x + w.y * w.y + w.z * w.z))

        if l == 0.0 {
            // two points together.
            let sphere = SCNSphere(radius: radius)
            sphere.firstMaterial?.diffuse.contents = color
            self.geometry = sphere
            self.position = startPoint
            return self

        }

        let cyl = SCNCylinder(radius: radius, height: l)
        cyl.firstMaterial?.diffuse.contents = color

        self.geometry = cyl

        //original vector of cylinder above 0,0,0
        let ov = SCNVector3(0, l/2.0,0)
        //target vector, in new coordination
        let nv = SCNVector3((endPoint.x - startPoint.x)/2.0, (endPoint.y - startPoint.y)/2.0,
                            (endPoint.z-startPoint.z)/2.0)

        // axis between two vector
        let av = SCNVector3( (ov.x + nv.x)/2.0, (ov.y+nv.y)/2.0, (ov.z+nv.z)/2.0)

        //normalized axis vector
        let av_normalized = normalizeVector(av)
        let q0 = Float(0.0) //cos(angel/2), angle is always 180 or M_PI
        let q1 = Float(av_normalized.x) // x' * sin(angle/2)
        let q2 = Float(av_normalized.y) // y' * sin(angle/2)
        let q3 = Float(av_normalized.z) // z' * sin(angle/2)

        let r_m11 = q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3
        let r_m12 = 2 * q1 * q2 + 2 * q0 * q3
        let r_m13 = 2 * q1 * q3 - 2 * q0 * q2
        let r_m21 = 2 * q1 * q2 - 2 * q0 * q3
        let r_m22 = q0 * q0 - q1 * q1 + q2 * q2 - q3 * q3
        let r_m23 = 2 * q2 * q3 + 2 * q0 * q1
        let r_m31 = 2 * q1 * q3 + 2 * q0 * q2
        let r_m32 = 2 * q2 * q3 - 2 * q0 * q1
        let r_m33 = q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3

        self.transform.m11 = r_m11
        self.transform.m12 = r_m12
        self.transform.m13 = r_m13
        self.transform.m14 = 0.0

        self.transform.m21 = r_m21
        self.transform.m22 = r_m22
        self.transform.m23 = r_m23
        self.transform.m24 = 0.0

        self.transform.m31 = r_m31
        self.transform.m32 = r_m32
        self.transform.m33 = r_m33
        self.transform.m34 = 0.0

        self.transform.m41 = (startPoint.x + endPoint.x) / 2.0
        self.transform.m42 = (startPoint.y + endPoint.y) / 2.0
        self.transform.m43 = (startPoint.z + endPoint.z) / 2.0
        self.transform.m44 = 1.0
        return self
    }
}

//extension ended.

//in your code, you can like this.
let twoPointsNode1 = SCNNode()
        scene.rootNode.addChildNode(twoPointsNode1.buildLineInTwoPointsWithRotation(
            from: SCNVector3(1,-1,3), to: SCNVector3( 7,11,7), radius: 0.2, color: .cyan))
//end

you can reference http://danceswithcode.net/engineeringnotes/quaternions/quaternions.html

BTW, you will get same result when you use a cylinder to make a line between two points from above 3 methods. But indeed, they will have different normal lines. In another words, if you use box between two points, sides of box, except top and bottom, will face different direction from above 3 methods.

let me know pls if you need further explanation.

这篇关于在两点之间绘制 SceneKit 对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆