Godot Version
4.3.stable.mono
Question
Chinese Version(there is an English version below)
我正在设计一个把任意的场景映射到体素网格中的算法。我实现的基本思路是遍历网格的每一个单元格,检测单元格是否与场景(一个Area3D节点)发生碰撞,如果存在碰撞,则将当前正在检测的单元格标记为“被占用”,反之不然。
基于上面的思路,我先写了一个用于检测单个单元格的函数,叫做UnitMapping,它返回一个布尔值来表示单元格与场景是否有碰撞。代码段1给出了该函数的实现代码。
为了测试UnitMapping函数,我在场景根节点的_PhysicsProcess()中写下了代码段2中所示的代码。如果检测到了碰撞,那么就在当前单元格的位置绘制一个绿色的方体,否则就绘制一个红色的方体。
其中detectorPosition是一个Vector3I类型的变量,它表示当前正在检测的单元格在网格中的坐标(显然它的x, y, z都应该是整数)。它可以通过UI进行控制。
GridToWorld函数用于将整数构成的网格坐标转换为浮点数构成的世界坐标,方便碰撞检测时的定位。
MappingMask是场景(一个Area3D节点)所在的物理层。它通过[Export](GDScript中的@export)在编辑器中配置。
当我运行场景并使用UI定位了一个detectorPosition时,我得到了如图1所示的结果。这个单元格显然和场景有重叠的部分,但是检测的结果是“没有碰撞”。我已经被这个问题困扰了好久了,希望有好心人解答我的疑惑。
English Version
I am designing an algorithm to map any scene to a voxel grid. The basic idea I have implemented is to traverse every cell of the grid, detecting whether a cell collides with the scene (an Area3D node). If there is a collision, the cell currently being detected is marked as “occupied”, otherwise it is not.
Based on the above idea, I first wrote a function called UnitMapping() for detecting a single cell, which returns a Boolean value to indicate whether the cell collides with the scene. Code snippet 1 provides the implementation code for this function.
To test the UnitMapping() function, I wrote the code shown in code snippet 2 in the _PhysicsProcess() of the scene root node. If a collision is detected, draw a green cube at the current cell position; otherwise, draw a red cube.
Among them, detectorPosition is a Vector3I variable that represents the coordinates of the cell being detected in the grid (obviously, its x, y, z should all be integers). It can be controlled through the UI.
The GridToWorld() function is used to convert grid coordinates composed of integers into world coordinates composed of floating-point numbers, facilitating collision detection localization.
MappingMask is the physical layer where the scene (an Area3D node) is located. It is configured in the editor through [Export] (@ export in GDScript).
When I ran the scene and used the UI to locate a detectorPosition, I obtained the result shown in Figure 1. This cell clearly overlaps with the scene, but the detection result is no collision. I have been troubled by this question for a long time, and I hope someone kind can answer my doubts.
代码段1(Code snippet 1)
bool UnitMapping(Vector3 center, Vector3 unitSize, uint collisionMask){
bool result = false;
BoxShape3D shape = new BoxShape3D();
shape.Size = unitSize;
Transform3D transform = new Transform3D();
transform.Basis = new Basis();
transform.Origin = center;
PhysicsShapeQueryParameters3D query = new PhysicsShapeQueryParameters3D();
query.CollideWithAreas = true;
query.CollideWithBodies = false;
query.CollisionMask = collisionMask;
query.Shape = shape;
query.Transform = transform;
PhysicsDirectSpaceState3D spaceState = GetWorld3D().DirectSpaceState;
Array<Dictionary> checkResult = spaceState.IntersectShape(query);
if(checkResult.Count == 0) result = false;
else result = true;
return result;
}
代码段2(Code snippet 2)
public override void _PhysicsProcess(double delta)
{
base._PhysicsProcess(delta);
//Test UnitMapping()
Vector3 center = GridToWorld(detectorPosition, UnitSize, Offset);
bool mappingResult = UnitMapping(center, UnitSize, MappingMask);
detectorMeshInstance.QueueFree();
if(mappingResult){
detectorMeshInstance = DrawCube3D(center, UnitSize.X, new Color(0, 1, 0, 0.6f));
} else {
detectorMeshInstance = DrawCube3D(center, UnitSize.X, new Color(1, 0, 0, 0.6f));
}
}