如何缩小游戏世界(AR)而不会失去精确度

时间:2018-03-06 14:08:23

标签: ios swift position scale scenekit

我正在尝试打击z-fighting,其中cpu / gpu在大型世界中渲染对象时遇到问题。正如现在的数学一样,整个世界都在MKMapPoints中表示......然后应用2.12732213757614 meters/unit的比例。如果没有z战斗,这个规模远远不够好。然后我必须拿出比例并乘以1000以使z战斗停止。

scale = Float(coordinateConverter.unitSizeInMeters) * 1000.0

我通过划分各种地图点相关值来应用比例。例如,在这里我将它应用到我在网格中的位置:

myPosition.x = (xValue / Double(topFivePoints.count)) / Double(scale)
myPosition.y = (yValue / Double(topFivePoints.count)) / Double(scale)

对于这些值,我会有这样的数字:

-0.00041963615298460055 //myPosition.x
-0.00051179784578082345 //myPosition.y

问题是,这些数字太小而无法被游戏网格检测为变化。我已经调查了它,它不仅仅是我的数字的格式 - 我在缩放过程中以某种方式失去了一些精度...所以对于被渲染对象的位置 - 它们由这样的数字表示:

-38144.5 //x
-46725.4 //y

上面的数字没有达到足够的小数位数,以使我的位置和虚拟对象之间的差异足够明显到网格(我的位置编号,即-0.00041963615298460055,太小而无法生效对象所代表的数字,即-46725.4,因为它们只会到达一个小数位,精度会丢失。这就是我如何改变对象相对于我的位置的位置:

for node in scene.rootNode.childNodes {

    node.simdPosition = simd_float3(-Float(myPosition.x! - lastPosition.x!) + node.position.x, node.position.y, -Float(myPosition.y! - lastPosition.y!) + node.position.z)

}

对于上面的代码,当我从iBeacon收到新的邻近读数时,比例应用于myPosition(如上面第二段代码所示)。

初始节点位置是这样创建的(在循环中):

node.position = SCNVector3Make(-Float(transformerFromPDFToMk.tx) / scale + node.position.x, node.position.y, -Float(transformerFromPDFToMk.ty) / scale + node.position.z)

我还没有将比例应用到node.position ...也许我应该......但它似乎按照原始比例填充对象,因为对象间距正确。 transformerFromPDFToMk.tx / transformerFromPDFToMk.ty是我的场景的起源,相对于我在地球上的位置,MKMapKit点。该对象最初从(0,0)开始,因此必须将它们调整为相对于世界MKMapPoint坐标出现在正确的位置。

我的最终问题是,如何在不失去对象坐标数精度的情况下缩小世界(即-46725.4)?或者我怎样才能占据我所处的世界(而不是整个世界)的一大块......并保持精确度?我将发布的最后一个代码是我从这个cool open source project修改的关于室内定位的代码。我使用它coordinateConverter来获得世界原始变换所需的值(有两个用于定位的锚点和一个用于定向世界的旋转)。所以也许在这段代码的某个地方,我可以根据我所处的位置将世界分成一小块:

...


init(anchors: GeoAnchorPair) {
    self.anchors = anchors

    /*
        Next, to compute the direction between two geographical coordinates,
        we first need to convert to MapKit coordinates...
    */
    let fromAnchorMercatorCoordinate = MKMapPointForCoordinate(anchors.fromAnchor.latitudeLongitudeCoordinate)
    let toAnchorMercatorCoordinate = MKMapPointForCoordinate(anchors.toAnchor.latitudeLongitudeCoordinate)

    let pdfDisplacement = CGPoint(x: anchors.toAnchor.pdfPoint.x - anchors.fromAnchor.pdfPoint.x, y: anchors.toAnchor.pdfPoint.y - anchors.fromAnchor.pdfPoint.y)

    /*
        ...so that we can use MapKit's Mercator coordinate system where +x
        is always eastward and +y is always southward. Imagine an arrow
        connecting fromAnchor to toAnchor...
    */
    let anchorDisplacementMapKitX = (toAnchorMercatorCoordinate.x - fromAnchorMercatorCoordinate.x)
    let anchorDisplacementMapKitY = (toAnchorMercatorCoordinate.y - fromAnchorMercatorCoordinate.y)

    /*
        What is the angle of this arrow (geographically)?
        atan2 always returns:
          exactly 0.0 radians if the arrow is exactly in the +x direction
                ("MapKit's +x" is due East).
          positive radians as the arrow is rotated toward and through the +y
                direction ("MapKit's +y" is due South).
        In the case of MapKit, this is radians clockwise from due East.
    */
    let radiansClockwiseOfDueEast = atan2(anchorDisplacementMapKitY, anchorDisplacementMapKitX)

    /*
        That means if we rotate pdfDisplacement COUNTER-clockwise by this
        value, it will be facing due east. In the CG coordinate frame,
        positive radians is counter-clockwise because in a PDF +x is
        rightward and +y is upward.
    */
    let cgDueEast = CGVector(dx: pdfDisplacement.x, dy: pdfDisplacement.y).rotatedByRadians(CGFloat(radiansClockwiseOfDueEast))

    // Now, get the distance (in meters) between the two anchors...
    let distanceBetweenAnchorsMeters = CLLocationDistance.distanceBetweenLocationCoordinates2D(anchors.fromAnchor.latitudeLongitudeCoordinate, b: anchors.toAnchor.latitudeLongitudeCoordinate)

    // ...and rescale so that it's exactly one meter in length.
    oneMeterEastwardVector = cgDueEast.scaledByFloat(CGFloat(1.0 / distanceBetweenAnchorsMeters))

    /*
        Lastly, due south is PI/2 clockwise of due east.
        In the CG coordinate frame, clockwise rotation is NEGATIVE radians
        because in a PDF +x is rightward and +y is upward.
    */
    oneMeterSouthwardVector = oneMeterEastwardVector.rotatedByRadians(-.pi / 2)

    /*
        We'll choose the midpoint between the two anchors to be our "tangent
        point". This is the MKMapPoint that will correspond to both
        tangentLatitudeLongitudeCoordinate on Earth and _tangentPDFPoint
        in the PDF.
    */
    let tangentMercatorCoordinate = MKMapPoint.midpoint(fromAnchorMercatorCoordinate, b: toAnchorMercatorCoordinate)

    tangentLatitudeLongitudeCoordinate = MKCoordinateForMapPoint(tangentMercatorCoordinate)

    tangentPDFPoint = CGPoint.pointAverage(anchors.fromAnchor.pdfPoint, b: anchors.toAnchor.pdfPoint)

}

...

func transformerFromPDFToMk() -> CGAffineTransform {
    let metersPerMapPoint = MKMetersPerMapPointAtLatitude(tangentLatitudeLongitudeCoordinate.latitude)
    let tangentMercatorCoordinate = MKMapPointForCoordinate(tangentLatitudeLongitudeCoordinate)

    /*
        CGAffineTransform operations are easier to construct in reverse-order.
        Start with the last operation:
    */
    let resultOfTangentMercatorCoordinate = CGAffineTransform(translationX: CGFloat(tangentMercatorCoordinate.x), y: CGFloat(tangentMercatorCoordinate.y))

    /*
        Revise the AffineTransform to first scale by 
        (1.0 / metersPerMapPoint), and then perform the above translation.
    */
    let resultOfEastSouthDistanceMeters = resultOfTangentMercatorCoordinate.scaledBy(x: CGFloat(1.0 / metersPerMapPoint), y: CGFloat(1.0 / metersPerMapPoint))

    /*
        Revise the AffineTransform to first scale by 
        (1.0 / dotProduct(...)) before performing the transform so far.
    */
    let resultOfDotProduct = resultOfEastSouthDistanceMeters.scaledBy(x: 1.0 / oneMeterEastwardVector.dotProductWithVector(oneMeterEastwardVector),
        y: 1.0 / oneMeterSouthwardVector.dotProductWithVector(oneMeterSouthwardVector))

    /*
        Revise the AffineTransform to first perform dot products aginst our
        reference vectors before performing the  transform so far.
    */
    let resultOfDisplacementFromTangentPoint = CGAffineTransform(
        a: oneMeterEastwardVector.dx, b: oneMeterEastwardVector.dy,
        c: oneMeterSouthwardVector.dx, d: oneMeterSouthwardVector.dy,
        tx: 0.0, ty: 0.0
        ).concatenating(resultOfDotProduct
    )

    /*
        Lastly, revise the AffineTransform to first perform the initial
        subtraction before performing the remaining operations.
        Each meter is about (1.0 / metersPerMapPoint) 'MKMapPoint's, as long
        as we are nearby tangentLatitudeLongitudeCoordinate.
    */
    return resultOfDisplacementFromTangentPoint.translatedBy(x: -tangentPDFPoint.x, y: -tangentPDFPoint.y)
}

以上代码最终是我如何让transformerFromPDFToMk.tx / transformerFromPDFToMk.ty来调整世界。那么,我怎样才能扩展它并且不会失去精度呢?或者我怎样才能把这个世界的相关部分拿走?

更新 我想我找到了一种方法来保持精度,我不得不将整个缩放计算移到simdPosition更改中:

node.simdPosition = simd_float3((-Float(myPosition.x!) + node.simdPosition.x * Float(coordinateConverter.unitSizeInMeters * 1000)) / scale, node.simdPosition.y, (-Float(myPosition.y!) + node.simdPosition.z * Float(coordinateConverter.unitSizeInMeters * 1000)) / scale)

另外,它的那种奇怪,我乘以比例,然后除以比例,我可以看到数字的小变化:

print("\(String(describing: Double(node.position.x))) --- node postion before didRenderScene: x")
print("\(String(describing: Double(node.position.z))) --- node postion before didRenderScene: z")

print("\(myPosition.x) --- my position before in didRenderScene: x")
print("\(myPosition.y) --- my position before didRenderScene: y")

print("\(String(describing: Double(node.simdPosition.x))) --- node postion after didRenderScene: x")
print("\(String(describing: Double(node.simdPosition.z))) --- node postion after didRenderScene: z")

以上陈述返回:

Optional(0.0011671428003945904) --- my position before in didRenderScene: x
Optional(0.0011160162812675013) --- my position before didRenderScene: y

-38144.5859375 --- node postion before didRenderScene: x
-46725.2734375 --- node postion before didRenderScene: z

-38144.58203125 --- node postion after didRenderScene: x
-46725.26953125 --- node postion after didRenderScene: z

所以你可以看到差异,当我的位置被考虑在内时,被识别在-38144.5859375和-38144.58203125,以及-46725.2734375和-46725.26953125之间 - 你可以看到数字有点变化。我只是没有看到我的AR世界的变化,节点保持在他们开始的确切位置。这可能是因为我将simdPosition格式化为Double之前describestring吗?因此数字因格式而改变,但代表位置的数字只允许有1个小数位......无论数字是否识别出变化。

0 个答案:

没有答案