寻求展开立方体顶点跨面移动的优雅实现方案
立方体跨面位置偏移的数学化优雅实现方案
我创建了一个各面拥有独立顶点集合的立方体,需实现立方体某一面上的2D位置偏移后跨面处理。例如正面的点A(5,3)偏移(+5,+0)后,会溢出到右侧面的(2,3)位置。当前通过大量条件判断(针对6个面各4种溢出情况)实现此逻辑,虽能正常运行,但希望找到类似石头剪刀布那种简洁高效的数学式优雅方案,替代冗余的条件判断。
现有顶点生成代码
Vertices = new Vector3[size * size * 6]; float vertexSpacing = 1.0f / ((float)size - 1.0f); for (int i = 0; i < size*size*6; i++) { int faceNumber = i / (size * size); int gridI = i - (faceNumber * size * size); int gridX = gridI % (size); int gridY = gridI / (size); //Console.WriteLine("Actual I: " + i + " | GridX: " + gridX + " | GridY: " + gridY ); float x; float y; float z; if (faceNumber == 0) //left face { x = -0.5f; y = -0.5f + (gridY * vertexSpacing); z = -0.5f + (gridX * vertexSpacing); //Console.WriteLine("Grid XY: {0}, {1} | Grid Index: {2} | Actual Index: {3}", gridX, gridY, gridI, i); } else if (faceNumber == 1) //front face { x = -0.5f + (gridX * vertexSpacing); y = -0.5f + (gridY * vertexSpacing); z = 0.5f; } else if (faceNumber == 2) //right face { x = 0.5f; y = -0.5f + (gridY * vertexSpacing); z = 0.5f - (gridX * vertexSpacing); } else if (faceNumber == 3) //back face { x = 0.5f - (gridX * vertexSpacing); y = -0.5f + (gridY * vertexSpacing); z = -0.5f; } else if (faceNumber == 4) //top Face { x = -0.5f + (gridX * vertexSpacing); y = 0.5f; z = 0.5f - (gridY * vertexSpacing); } else //bottom face { x = -0.5f + (gridX * vertexSpacing); y = -0.5f; z = -0.5f + (gridY * vertexSpacing); } Vector3 pos = new Vector3(x,y,z); float x2 = pos.X * pos.X; float y2 = pos.Y * pos.Y; float z2 = pos.Z * pos.Z; Vector3 s = new Vector3 { X = pos.X * (float)Math.Sqrt(1f - y2 / 2f - z2 / 2f + y2 * z2 / 3f), Y = pos.Y * (float)Math.Sqrt(1f - z2 / 2f - x2 / 2f + x2 * z2 / 3f), Z = pos.Z * (float)Math.Sqrt(1f - x2 / 2f - y2 / 2f + x2 * y2 / 3f) }; s = s.Normalized(); Vertices[i] = s * scale; }
当前跨面处理的部分代码
int sourceFace = chunk.Face; int targetFace = -1; int segmentX = chunk.SegmentIndex % faceSize + (int)x; int segmentY = chunk.SegmentIndex / faceSize + (int)y; bool sideFace = (sourceFace < 4); if (sideFace) { if (segmentX < 0) { if (sourceFace == 3) targetFace = 0; else targetFace = sourceFace - 1; segmentX += faceSize; } if (segmentX >= faceSize) { if (sourceFace == 3) targetFace = 0; else targetFace = sourceFace + 1; segmentX -= faceSize; } if (segmentY < 0) { } if (segmentY > faceSize) { } }
简洁数学化实现方案
核心思路是利用模运算处理循环邻接,用预定义的坐标转换规则替代条件判断,把每个面的溢出逻辑抽象成统一的数学计算。
1. 定义面的邻接与坐标转换规则
先明确各面的编号(和现有代码一致):
- 0: 左 | 1: 前 | 2: 右 | 3: 后 | 4: 顶 | 5: 底
用数组存储邻接面信息和坐标转换映射关系,替代分支判断:
// 邻接面映射:[sourceFace][direction] = targetFace // direction: 0=X负方向溢出, 1=X正方向溢出, 2=Y负方向溢出, 3=Y正方向溢出 int[,] adjFaces = new int[6,4] { {3, 1, 5, 4}, // 左面:X负→后,X正→前,Y负→底,Y正→顶 {0, 2, 5, 4}, // 前面:X负→左,X正→右,Y负→底,Y正→顶 {1, 3, 5, 4}, // 右面:X负→前,X正→后,Y负→底,Y正→顶 {2, 0, 5, 4}, // 后面:X负→右,X正→左,Y负→底,Y正→顶 {0, 2, 1, 3}, // 顶面:X负→左,X正→右,Y负→前,Y正→后 {0, 2, 3, 1} // 底面:X负→左,X正→右,Y负→后,Y正→前 }; // 坐标转换规则索引:[sourceFace][direction] = 规则编号 // 规则0: newX = x + size; newY = y // 规则1: newX = x - size; newY = y // 规则2: newX = y; newY = size-1 - x // 规则3: newX = size-1 - y; newY = x // 规则4: newX = x; newY = y - size // 规则5: newX = x; newY = y + size int[,] coordRules = new int[6,4] { {2, 2, 5, 4}, // 左面X负→规则2,X正→规则2,Y负→规则5,Y正→规则4 {0, 1, 5, 4}, // 前面X负→规则0,X正→规则1,Y负→规则5,Y正→规则4 {2, 2, 5, 4}, // 右面X负→规则2,X正→规则2,Y负→规则5,Y正→规则4 {1, 0, 5, 4}, // 后面X负→规则1,X正→规则0,Y负→规则5,Y正→规则4 {0, 1, 2, 2}, // 顶面X负→规则0,X正→规则1,Y负→规则2,Y正→规则2 {0, 1, 3, 3} // 底面X负→规则0,X正→规则1,Y负→规则3,Y正→规则3 };
2. 统一处理溢出的函数
通过循环判断溢出方向,结合预定义映射直接计算目标面和新坐标:
(int targetFace, int newX, int newY) HandleCrossFaceOffset(int sourceFace, int originalX, int originalY, int offsetX, int offsetY, int size) { int x = originalX + offsetX; int y = originalY + offsetY; int face = sourceFace; // 处理X轴溢出 while (x < 0 || x >= size) { int dir = x < 0 ? 0 : 1; face = adjFaces[face, dir]; (x, y) = ApplyCoordRule(x, y, size, coordRules[sourceFace, dir]); } // 处理Y轴溢出 while (y < 0 || y >= size) { int dir = y < 0 ? 2 : 3; face = adjFaces[face, dir]; (x, y) = ApplyCoordRule(x, y, size, coordRules[sourceFace, dir]); } return (face, x, y); } // 应用坐标转换规则 (int x, int y) ApplyCoordRule(int x, int y, int size, int rule) { return rule switch { 0 => (x + size, y), 1 => (x - size, y), 2 => (y, size - 1 - x), 3 => (size - 1 - y, x), 4 => (x, y - size), 5 => (x, y + size), _ => (x, y) }; }
3. 调用示例
// 正面(1)的点(5,3)偏移(+5,0),size假设为8 var result = HandleCrossFaceOffset(1, 5, 3, 5, 0, 8); // 返回结果:(2, 2, 3) → 右侧面(2)的(2,3),符合需求
这种方式把所有条件判断转化为数组查找和数学计算,逻辑清晰且易于维护,新增或修改面的规则只需调整映射数组即可,完全避免了冗余的分支判断。
内容的提问来源于stack exchange,提问作者servvs
相关产品推荐
相关产品推荐

