Working with Vectors - juniverse1103/ARKitStudy GitHub Wiki

Working with Vectors

Use vectors to calculate geometric values, calculate dot products and cross products, and interpolate between values.


Overview

  • A vector is comparable to a fixed-length array containing integer or floating-point values.

  • The simd library provides support for small vectors, that is, vectors that contain up to eight double-precision or sixteen single-precision values.

  • You can use vectors to represent data such as:

    • Color
      • R,G,B, and Alpha
    • Position
      • Coordinates in 2D or 3D space
  • simd library example for two vectors containing 4 elements

    let a = simd_float4(x: 2, y: 4, z: 5, w: 8)
    let b = simd_float4(x: 5, y: 6, z: 7, w: 8)
    
  • Sum vectors with + operator

    let c = a + b // c = (7.0, 10.0, 12.0, 16.0)
    

Calculate Luminance

  • Calculate the luminance of a color by multiplying each of its red, green, and blue color channels by a certain coefficient, and create a grayscale representation of the color by adding the three products together.

  • Below code uses Rec.709 luma coefficients for the color-to-grayscale conversion.

  • func lumaForColor(red: Float, green: Float, blue: Float){
    let luma = (red*0.2126) + (green*0,7152) + (blue*0.0722)
    return luma
    }
    
  • simd library simflities this code by treating the color and the coefficients as vecotrs, and returning the dot product of the vectors.

  • let rec709Luma = simd_float3(0.2126, 0.7152, 0.0722)
    func lumaForColor(red: Float, green: Float, blue: Float){
        let luma = simd_dot(rec709Luma, simd_float3(red,blue,green))
        return luma
    }
    
    

Calculate Length and Distance

  • Calculate the distance between two points using the Pythagorean theorem.
  • simd library provides functions for calcuating length and distance in two, three and four dimensions.

Calculate Length

  • Length functions, e.g. simd_length(_:) return the length of a vector.

Calculate Distance

  • Distance functions, e.g. simd_distance(_:_:) return the distance between two vectors.

  • let a = simd_float2(x:3, y:4)
    let b = simd_float2(x:0, y:0)
    
    let dist = simd_distance(a,b)
    let len = simd_length(a)
    

Compare Distances

  • Comparing vectors' distance or length with comparing the square of those.
let target = simd_float2(x:5, y:2)

if simd_distance_squared(a, target) < simd_distance_squared(b,target){
    // 'a' is closest to 'target'
} else{
    // 'b' is closest to 'target'
}

Calculate Reflection and Refraction Vectors

  • The simd library provides functions for calculating vectors that describe reflections and refractions in two-, three-, and four- dimensional space.

  • The image below shows:

    • An incident ray, described by the vector simd_double2(x:1.5, y:-1), traveling toward the center of the image.
    • A normal, described by the vector simd_double2(x:0, y:1), that's perpendicular to the interface between the two media.
    • The reflected ray, computed by simd, traveling away from the center of the image.

Normalize Vectors

  • Normalize the vectors(calculate a vector with the same direction as the original, but with a length of 1) passed to the reflect and refract functions to achieve the correct results.

  • Given the values above, the code defines normalized vectors for the incident ray and normal:

    let incident = simd_normalize(simd_double2(x: 1.5, y: -1))
    let normal = simd_normalize(simd_double2(x: 0, y: 1))
    

Calculate Reflection

  • You get the reflected vector with simd_reflect(_:_:):

  • let reflected = simd_reflect(incident, normal)
    

Calculate Refraction

  • For the refraction function, pass an additional parameter(eta) that models the index of refraction for physicacl materials:

  • let air = 1.0 // refractive index for air
    let glass = 1.5 // refractive index for glass
    let refracted = simd_refract(incident, normal, air/glass)
    

Calculate the Normal of a Triangle

  • The normal of a triangle is the vector perpendicular to its surface.

  • Use the simd library's cross product function to calculate the normal of a triangle.

  • This is a common task in 3D graphics programming and is used when calculating the shading of surfaces.

  • In the image below, the triangle's normal is shown as a red line that's perpendicular to the surface of the triangle.

    The following code defines the three vertices of the triangle:

    let vertex1 = simd_float3(-1.5, 0.5, 0)
    let vertex2 = simd_float3(1,0,3)
    let vertex3 = simd_float3(0.5,-0.5, -1,5)
    
  • First step in calculating the normal of the triangle is to create two vectors defined by the difference between the vertices - representing two sides of the triangle:

  • let vector1 = vertex2 - vertex3
    let vector2 = vertex2 - vertex1
    
  • The simd_cross function returns the vector that's perpendicular to the two vectors. Normalize the result to get unit vector of the normal of the triangle to get only the direcitonl.

  • let normal = simd_normalize(simd_cross(vector1, vector2))
    

Interpolate Between Values

  • Interpolation adds new, intermediate data points between known values.
  • The simd library provides functions to linearly and smoothly interpolate between scalar and vector values.
  • Smooth interpolation is commonly used in animation, and you can, for example, use the functions described below to define the timingFunction of a SpriteKit action.
  • example illustration of linear and smooth interpolation between boundary values.

Linearly interpolate

  • Linear interpolation is provided by the simd_mix function.

  • The first two parameters specify the range, and the third parameter specifies the normalized(between 0 and 1) position in the range.

  • The following code shows how to populate an array with 1024 elements. The first element in the array has a value of -100, and the last element of the array has a value of 100.

  • Intermediate elements linearly interpolate between the first and last values:

  • let linear: [Float] = stride(from:0.0, to: 1.0, by: 1/1024).map{
        x in return simd_mix(-100,100,x)
    }
    

Smoothly Interpolate

  • Smooth interpolation is provided by the simd_smoothstep function.

  • This function uses Hermite interpolation based on the following code:

  • simd_double4 simd_smoothstep(simd_double4 edge0, simd_double4 edge1, simd_double4 x){
        simd_double4 t = simd_clamp((x-edge0)/(edge1-edge0),0,1);
        return t*t*(3-2*t);
    }
    
  • The first two parameters specify the range, and the third parameter specifies the position in the range.

  • Unlike the mix function, the position isn't normalized, but the return value is.

  • The following code shows how to populate an array with 1024 elements.

  • The first element in the array has a value of 0, and the last element of the array has a value of 1. Intermediate elements smoothly interpolate between the first and last valued:

  • let smooth:[Float] = (-512..<512).map{
        x in return simd_smoothstep(-512,512,Float(x))
    }