public void XYZ() { VoxelRotation rot = new VoxelRotation(); Assert.AreEqual(0, rot.y); Assert.AreEqual(0, rot.x); Assert.AreEqual(0, rot.z); rot.x = 3; rot.y = 2; rot.z = 1; Assert.AreEqual(3, rot.x); Assert.AreEqual(2, rot.y); Assert.AreEqual(1, rot.z); rot.x -= 1; Assert.AreEqual(2, rot.x); Assert.AreEqual(2, rot.y); Assert.AreEqual(1, rot.z); rot.y += 1; Assert.AreEqual(2, rot.x); Assert.AreEqual(3, rot.y); Assert.AreEqual(1, rot.z); rot.z += 1; Assert.AreEqual(2, rot.x); Assert.AreEqual(3, rot.y); Assert.AreEqual(2, rot.z); }
public void Z() { VoxelRotation rot = new VoxelRotation(); Assert.AreEqual(0, rot.x); Assert.AreEqual(0, rot.y); Assert.AreEqual(0, rot.z); rot.z = 3; Assert.AreEqual(3, rot.z); rot.z -= 1; Assert.AreEqual(2, rot.z); }
public void Blank() { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { var rot = new VoxelRotation() { x = i, y = j, z = k }; bool empty = i == 0 && j == 0 && k == 0; Assert.AreEqual(empty, rot.isBlank, $"Rotation isBlank method returned an unexpected result for x={i},y={j},z={k}"); } } } }
private void AddMeshDataForVoxel(ushort id, int3 position, bool rotated, VoxelRotation rotation) { var meshID = data.meshDatabase.voxelTypeToMeshTypeMap[id]; var faceZRange = data.voxelTypeDatabase.voxelTypeToZIndicesRangeMap[id]; var materialID = data.meshDatabase.voxelTypeToMaterialIDMap[id]; var meshRange = data.meshDatabase.meshTypeRanges[meshID]; //Update the material run tracker runTracker.Update(materialID, data.materialRuns, data.allTriangleIndices); if (rotated) { //Add single rotated voxels data for (byte dir = 0; dir < numDirections; dir++) { var rotatedDirection = (byte)directionHelper.GetDirectionAfterRotation((Direction)dir, rotation); var faceIsSolid = data.meshDatabase.isFaceSolid[meshRange.start + rotatedDirection]; if (IncludeFace(id, position, rotatedDirection, faceIsSolid)) { AddFaceRotated(meshID, data.voxelTypeDatabase.zIndicesPerFace[faceZRange.start + dir], dir, position, rotation); } } } else { //Add single voxel's data for (int dir = 0; dir < numDirections; dir++) { var faceIsSolid = data.meshDatabase.isFaceSolid[meshRange.start + dir]; if (IncludeFace(id, position, dir, faceIsSolid)) { AddFace(meshID, data.voxelTypeDatabase.zIndicesPerFace[faceZRange.start + dir], dir, position); } } } }
public void Inverse() { using (var directionHelper = DirectionRotatorExtensions.Create()) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { for (int k = 0; k < 4; k++) { var rotation = new VoxelRotation() { x = i, y = j, z = k }; var testDirection = Direction.north; var thereAndBackAgain = directionHelper.GetDirectionBeforeRotation(directionHelper.GetDirectionAfterRotation(testDirection, rotation), rotation); Assert.AreEqual(testDirection, thereAndBackAgain, $"Failed to invert rotation {rotation}"); } } } } }
public void Execute() { //Sort the rotated voxels so that they are in the order of iteration if (data.rotatedVoxels.Length > 0) { data.rotatedVoxels.Sort(new RotatedVoxelComparer()); } int currentRotatedIndex = 0; runTracker = new MaterialRunTracker(); int i = 0;//current index into voxelData for (int z = 0; z < data.dimensions.z; z++) { for (int y = 0; y < data.dimensions.y; y++) { for (int x = 0; x < data.dimensions.x; x++) { var voxelTypeID = data.voxels[i]; if (voxelTypeID != VoxelTypeID.AIR_ID) { bool rotated = false; VoxelRotation rotation = default; if (data.rotatedVoxels.Length > 0 && data.rotatedVoxels[currentRotatedIndex].flatIndex == i) { //This voxel is rotated rotated = true; rotation = data.rotatedVoxels[currentRotatedIndex].rotation; AdvanceRotatedIndex(ref currentRotatedIndex); } if (data.voxelTypeDatabase.voxelTypeToIsPassableMap[voxelTypeID]) { //Save non-collidable voxels for later, so that they appear contiguously in the mesh arrays nonCollidableQueue.Add(new DoLater() { position = new int3(x, y, z), typeID = voxelTypeID, rotated = rotated, rotation = rotation }); } else { AddMeshDataForVoxel(voxelTypeID, new int3(x, y, z), rotated, rotation); } } i++; } } } //Record length of collidable mesh section data.collisionSubmesh.Record(data.vertices.Length, data.allTriangleIndices.Length, data.materialRuns.Length); runTracker.EndRun(data.materialRuns, data.allTriangleIndices); //Process non collidable section for (int j = 0; j < nonCollidableQueue.Length; j++) { var item = nonCollidableQueue[j]; AddMeshDataForVoxel(item.typeID, item.position, item.rotated, item.rotation); } runTracker.EndRun(data.materialRuns, data.allTriangleIndices); }
private void AddFaceRotated(int meshID, float uvZ, int direction, int3 position, VoxelRotation rotation) { //Lighting Color vertexColourValue = new Color(); if (data.includeLighting) { var directionVector = directionHelper.DirectionVectors[direction]; var lightForFace = GetLightValue(position + directionVector, data.lights, data.dimensions, data.neighbourData); vertexColourValue = lightForFace.ToVertexColour(); } var meshRange = data.meshDatabase.meshTypeRanges[meshID]; var usedNodesSlice = data.meshDatabase.nodesUsedByFaces[meshRange.start + direction]; var currentIndex = data.vertices.Length; var rotationQuat = directionHelper.GetRotationQuat(rotation); //NOTE vertex definitions start from 0,0,0 in the bottom left of the cube, so an offset is needed for rotations float3 rotationOffset = new float3(.5f, .5f, .5f); //Add all the nodes used by this face for (int i = usedNodesSlice.start; i < usedNodesSlice.end; i++) { var node = data.meshDatabase.allMeshNodes[i]; var rotatedVert = math.mul(rotationQuat, node.vertex - rotationOffset) + rotationOffset; var adjustedVert = rotatedVert + position; data.vertices.Add(adjustedVert); if (data.includeLighting) { data.vertexColours.Add(vertexColourValue); } data.uvs.Add(new float3(node.uv, uvZ)); var adjustedNorm = math.mul(rotationQuat, node.normal); data.normals.Add(adjustedNorm); } //Add the triangleIndices used by this face var relativeTrianglesSlice = data.meshDatabase.relativeTrianglesByFaces[meshRange.start + direction]; for (int i = relativeTrianglesSlice.start; i < relativeTrianglesSlice.end; i++) { data.allTriangleIndices.Add(data.meshDatabase.allRelativeTriangles[i] + currentIndex); } }
private FaceDescriptor makeFaceDescriptor(VoxelTypeID typeId, Direction originalDirection, LightValue lightValue, VoxelRotation rotation = default) { if (typeId == VoxelTypeID.AIR_ID) { return(nullFace); } var faceDirection = originalDirection; if (!rotation.isBlank) { ///Face direction needs to be the direction index of the face currently pointing in the original ///direction. Therefore it is the direction such that applying the rotation gives the original direction. faceDirection = directionRotator.GetDirectionBeforeRotation(originalDirection, rotation); } FaceDescriptor faceDescriptor = new FaceDescriptor() { typeId = typeId, faceDirection = faceDirection, rotation = rotation, lightValue = lightValue }; return(faceDescriptor); }
private void Update() { if (UImanager.CursorInUseByUI) { return;//Don't run block placement logic when UI is using the cursor. } blockToPlace = hotbar.Selected; Ray ray = Camera.main.ViewportPointToRay(new Vector3(.5f, .5f, 0)); //Ray ray = new Ray(transform.position, Camera.main.transform.forward); RaycastHit raycastHit; bool hitAnything = Physics.Raycast(ray, out raycastHit, MaxPlacementDistance, LayerMask.GetMask("Voxels")); if (hitAnything) { Indicator.SetActive(true); Indicator.transform.position = WorldInterface.CenterOfVoxelAt(raycastHit.point + -0.1f * raycastHit.normal); Indicator.transform.rotation = Quaternion.Euler(0, 0, 0); LocationToPlaceBlock = raycastHit.point + 0.1f * raycastHit.normal; LocationToDeleteBlock = raycastHit.point + -0.1f * raycastHit.normal; } else { Indicator.SetActive(false); return; } //Delete block if (Input.GetMouseButtonDown((int)BreakButton)) { if (hitAnything) { WorldInterface.RemoveVoxel(LocationToDeleteBlock); } } //Place block if (Input.GetMouseButtonDown((int)PlaceButton)) { if (hitAnything) { //Simple rotation calculation based on the normal of the face the player is looking at rotationZ = Mathf.RoundToInt(Vector3.Dot(raycastHit.normal, Vector3.left)); if (rotationZ == -1) { rotationZ = 3; } rotationX = Mathf.RoundToInt(Vector3.Dot(raycastHit.normal, Vector3.forward)); if (rotationX == -1) { rotationX = 3; } rotationY = 0; var rotation = new VoxelRotation() { x = rotationX, y = rotationY, z = rotationZ }; if (blockToPlace.rotationConfiguration != null && blockToPlace.rotationConfiguration.RotationValid(rotation)) { WorldInterface.PlaceVoxel(LocationToPlaceBlock, blockToPlace, rotation); } else { WorldInterface.PlaceVoxel(LocationToPlaceBlock, blockToPlace); } } } if (Input.GetMouseButtonDown((int)PickButton)) { if (hitAnything) { if (WorldInterface.TryGetVoxelTypeAndID(LocationToDeleteBlock, out var voxelType, out var ID)) { hotbar.SetCurrentItem(new InventoryItem() { ID = ID, typeDefinition = voxelType }); } } } }