我正在尝试打击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
之前describe
为string
吗?因此数字因格式而改变,但代表位置的数字只允许有1个小数位......无论数字是否识别出变化。