-
Notifications
You must be signed in to change notification settings - Fork 1
Creating Shapes
Most VoxLib shapes start as a few cuboids joined together. The only real trick is remembering that block-model coordinates use 0 to 16 instead of the 0 to 1 values used internally by VoxelShape.
Minecraft block shapes live in a 16x16x16 grid inside one block. Coordinates run from 0 to 16 on each axis:
-
0on the Y axis is the bottom of the block,16is the top. -
0on the Z axis is the north edge of the block,16is the south edge. -
0on the X axis is the west edge,16is the east edge.
Coordinates may be fractional. A value of 8 is half a block, and 0.5 is one thirty-second of a block. Values from 0 to 16 describe geometry inside the block. VoxLib does not clamp coordinates outside that range.
createCuboidShape is the basic building block. Give it the minimum and maximum coordinates, and it divides them by 16 before delegating to vanilla's Shapes.box.
import com.github.mystery2099.voxlib.combination.VoxelAssembly.createCuboidShape
// A slab covering the bottom 8 units of the block
val slab = createCuboidShape(0, 0, 0, 16, 8, 16)
// A 2x15x2 post in the northwest corner
val post = createCuboidShape(0, 0, 0, 2, 15, 2)
// A half-unit-thick panel, like a glass pane core
val panel = createCuboidShape(7.5, 0, 0, 8.5, 16, 16)The parameters are Number, so Int, Float, and Double all work without conversion.
Java:
import com.github.mystery2099.voxlib.combination.VoxelAssembly;
import net.minecraft.world.phys.shapes.VoxelShape;
VoxelShape slab = VoxelAssembly.INSTANCE.createCuboidShape(0, 0, 0, 16, 8, 16);
VoxelShape panel = VoxelAssembly.INSTANCE.createCuboidShape(7.5, 0, 0, 8.5, 16, 16);The parameters still accept Number, so autoboxed integers and doubles pass through unchanged.
For comparison, createCuboidShape(0, 0, 0, 16, 8, 16) is the same shape as:
- Mojang-mapped vanilla:
Block.box(0, 0, 0, 16, 8, 16)orShapes.box(0.0, 0.0, 0.0, 1.0, 0.5, 1.0) - Yarn-mapped vanilla:
Block.createCuboidShape(0, 0, 0, 16, 8, 16)
There is no new geometry system hiding here. createCuboidShape exists so your code can use familiar block units instead of 0 to 1 fractions, and so the VoxLib call looks the same under either mapping set.
A block's shape is queried many times per frame for outlines, raycasts, and collision. Create the shape once and store it:
class FancyTableBlock(properties: Properties) : Block(properties) {
companion object {
val SHAPE: VoxelShape = createCuboidShape(0, 0, 0, 16, 12, 16) +
createCuboidShape(2, 0, 2, 14, 10, 14)
}
}You can construct shapes inside getShape or getCollisionShape, but you generally should not. That repeats allocation and cache lookups on every query. VoxLib's caching can soften the cost, while a stored constant avoids it entirely.
VoxLib does not clamp coordinates. Values below 0 or above 16 create geometry outside the owning block because VoxLib divides them by 16 and passes them straight to Shapes.box.
Minecraft allows this for some block behaviors, but it is easy to get surprising results. Test selection, collision, neighbor interaction, and rendering carefully. VoxLib unions preserve out-of-block geometry, including unions that contain a full cube.
- Combining shapes: join multiple cuboids into one shape
- Common shapes: slabs, tables, chairs, stairs, fences, and pillars already built
- Rotating and flipping shapes: turn one shape into all four facings