SceneKit - Для чего нужен самый низкий ряд элементов в SCNMatrix4? - PullRequest
0 голосов
/ 12 сентября 2018

В SCNMatrix4 struct последний элемент m44 используется для однородных координат.

Я хотел бы знать, что такое элементы m41, m42 и m43 в SCNMatrix4? И для чего именно я могу использовать эти три элемента?

init(m11: Float, m12: Float, m13: Float, m14: Float, 
     m21: Float, m22: Float, m23: Float, m24: Float, 
     m31: Float, m32: Float, m33: Float, m34: Float, 
     m41: Float, m42: Float, m43: Float, m44: Float)

enter image description here

Ответы [ 3 ]

0 голосов
/ 13 сентября 2018

Основано на ответе @ BlackMirrorz.

Очевидное практическое преимущество использования элементов m41, m42 и m43 в SCNMatrix4 появляется при использовании проекции камеры SceneKit.

0 голосов
/ 13 сентября 2018

Нижний ряд используется для переводов и для проекций, таких как перспектива или усечение просмотра камеры.Несмотря на то, что это не код Apple, следующий источник (лицензированный по лицензии MIT), взятый из https://referencesource.microsoft.com/#System.Numerics/System/Numerics/Matrix4x4.cs,78a107de58a17946 (начиная со строки 864), показывает «[как создать] матрицу перспективной проекции на основе поля зрения, аспекта».отношение, а также расстояние до плоскости ближнего и дальнего обзора. "

    /// <summary>
    /// Creates a perspective projection matrix based on a field of view, aspect ratio, and near and far view plane distances. 
    /// </summary>
    /// <param name="fieldOfView">Field of view in the y direction, in radians.</param>
    /// <param name="aspectRatio">Aspect ratio, defined as view space width divided by height.</param>
    /// <param name="nearPlaneDistance">Distance to the near view plane.</param>
    /// <param name="farPlaneDistance">Distance to the far view plane.</param>
    /// <returns>The perspective projection matrix.</returns>
    public static Matrix4x4 CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance)
    {
        if (fieldOfView <= 0.0f || fieldOfView >= Math.PI)
            throw new ArgumentOutOfRangeException("fieldOfView");

        if (nearPlaneDistance <= 0.0f)
            throw new ArgumentOutOfRangeException("nearPlaneDistance");

        if (farPlaneDistance <= 0.0f)
            throw new ArgumentOutOfRangeException("farPlaneDistance");

        if (nearPlaneDistance >= farPlaneDistance)
            throw new ArgumentOutOfRangeException("nearPlaneDistance");

        float yScale = 1.0f / (float)Math.Tan(fieldOfView * 0.5f);
        float xScale = yScale / aspectRatio;

        Matrix4x4 result;

        result.M11 = xScale;
        result.M12 = result.M13 = result.M14 = 0.0f;

        result.M22 = yScale;
        result.M21 = result.M23 = result.M24 = 0.0f;

        result.M31 = result.M32 = 0.0f;
        result.M33 = farPlaneDistance / (nearPlaneDistance - farPlaneDistance);
        result.M34 = -1.0f;

        result.M41 = result.M42 = result.M44 = 0.0f;
        result.M43 = nearPlaneDistance * farPlaneDistance / (nearPlaneDistance - farPlaneDistance);

        return result;
    }

Этот фрагмент равен ARKit - он получает положение камеры ... https://gist.github.com/fisherds/a2a75c914c293213f594daf5fd940d3d

@IBAction func pressedAddEarth(_ sender: Any) {

    guard let pointOfView = sceneView.pointOfView else {return}
    let transform = pointOfView.transform
    let orientation = SCNVector3(-transform.m31, -transform.m32, -transform.m33)
    let location = SCNVector3(transform.m41, transform.m42, transform.m43)
    let currentPositionOfCamera = orientation + location

    // other stuff   
}    

func +(left: SCNVector3, right: SCNVector3) -> SCNVector3 {
  return SCNVector3Make(left.x + right.x, left.y + right.y, left.z + right.z)
}
0 голосов
/ 13 сентября 2018

Я могу ошибаться, но я думаю, что m41, m42 и m43 могут быть использованы для получения позиционных данных и по сути то же самое, что и result.worldTransform.columns.3 при выполнении hitTest.

Таким образом, при размещении SCNNode посредством выполнения ARSCNHitTest вы могли бы использовать либо:

let hitTestTransform = SCNMatrix4(result.worldTransform)
let positionFromMatrix4 = SCNVector3(hitTestTransform.m41, hitTestTransform.m42, hitTestTransform.m43)
let positionFromColumns =  SCNVector3(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z) 

Приведенный ниже пример должен помочь прояснить ситуацию:

/// Places Our Model At The Position Of An Existining ARPlaneAnchor
///
/// - Parameter gesture: UITapGestureRecognizer
@IBAction func placeModel(_ gesture: UITapGestureRecognizer){

    //1. Get The Touch Location
    let touchLocation = gesture.location(in: self.augmentedRealityView)

    //2. Perform An ARSCNHitTest For Any Existing Planes
    guard let result = self.augmentedRealityView.hitTest(touchLocation, types: [.existingPlane, .existingPlaneUsingExtent]).first else { return }

        //3. Get The World Transform
        let hitTestTransform = SCNMatrix4(result.worldTransform)

        //4. Initialize Our Position Either From .m41, .m42, .m43 Or From Columns.3
        let positionFromMatrix4 = SCNVector3(hitTestTransform.m41, hitTestTransform.m42, hitTestTransform.m43)
        let positionFromColumns =  SCNVector3(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z)

        //5. Log Them To Check I'm Not Being A Moron
        print(
            """
            Position From Matrix 4 == \(positionFromMatrix4)
            Position From Columns == \(positionFromColumns)
            """)

        /*
        Position From Matrix 4 == SCNVector3(x: -0.39050543, y: -0.004766479, z: 0.08107365)
        Position From Columns == SCNVector3(x: -0.39050543, y: -0.004766479, z: 0.08107365)
        */

        //6. Add A Node At The Position & Add It To The Hierachy
        let boxNode = SCNNode(geometry: SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0))
        boxNode.geometry?.firstMaterial?.diffuse.contents = UIColor.cyan
        boxNode.position = positionFromMatrix4
        self.augmentedRealityView.scene.rootNode.addChildNode(boxNode)
}

Надеюсь, это поможет ...

...