When creating a dynamic mesh, if a triangle is axis aligned (i.e. the 3 vertices have identical X,Y or Z values), then it will fail to render properly. If the triangle is normal to the Y or Z axes, the mesh won’t render at all. If the triangle is normal to the X axis, then the side-length of the rendered triangle is too large by a multiple of the actual side length, i.e. if the triangle actually has side length 5, it will be rendered with side length 25. The meshpart properties (like Size, MeshSize, ExtentsSize), all have the correct dimensions, yet it appears much larger.
In all these cases, adjusting one of the vertices along the normal axis by a small amount fixes the problem (it actually appears, and at the right size), it’s only when the triangle becomes exactly axis aligned that it stops rendering properly (but I haven’t tested thoroughly to find other examples).
I don’t know if this is specific to DynamicMesh, or if this is a general bug with Roblox meshes. However this bug report from two years ago suggests it could be a general mesh bug.
Where: I don’t know if this is a studio bug or engine bug, since I can only test DynamicMesh in studio.
I am testing on an M2 mac, with Roblox Studio Version 0.583.2.5831071 (it is the native apple silicon app)
When: I first observed this yesterday, July 15.
Videos and images: Full repro code is at the bottom. This is the result of making the three axis-aligned triangles, as in the repro code. Only the red triangle, normal to the X-axis, is visible, and it is the wrong size (I included balls where the vertices should be). The other two triangles are not visible.
-- This one renders with side length SIZE^2, though it still
-- thinks its extents are Vector3.new(0.05, SIZE, SIZE)
makeMeshPart(
"X-normal",
Color3.new(1,0.6,0.6),
Vector3.new(0, 0, 0),
Vector3.new(0, 0, SIZE),
Vector3.new(0, SIZE, 0)
)
-- This doesn't render at all
makeMeshPart(
"Y-normal",
Color3.new(0.6,1,0.6),
Vector3.new(0, 0, 0),
Vector3.new(0, 0, SIZE),
Vector3.new(SIZE, 0, 0)
)
-- This doesn't render at all
makeMeshPart(
"Z-normal",
Color3.new(0.6,0.6,1),
Vector3.new(0, 0, 0),
Vector3.new(0, SIZE, 0),
Vector3.new(SIZE, 0, 0)
)
Here I have added EPS=0.1 to one of the vertices, in the normal-axis coordinate. This resolves the bug (but of course now the triangles are off-axis).
-- This renders correctly
makeMeshPart(
"X-normal-plus-epsilon",
Color3.new(1,0,0),
Vector3.new(0, 0, 0),
Vector3.new(EPS, 0, SIZE),
Vector3.new(0, SIZE, 0)
)
-- This renders correctly
makeMeshPart(
"Y-normal-plus-epsilon",
Color3.new(0,1,0),
Vector3.new(0, 0, 0),
Vector3.new(0, EPS, SIZE),
Vector3.new(SIZE, 0, 0)
)
-- This renders correctly
makeMeshPart(
"Z-normal-plus-epsilon",
Color3.new(0,0,1),
Vector3.new(0, 0, 0),
Vector3.new(0, SIZE, EPS),
Vector3.new(SIZE, 0, 0)
)
Repro
local HEIGHT = 10
local EPS = 0.1
local SIZE = 5
local function makeMeshPart(name, color, v1, v2, v3)
local dynamicMesh = Instance.new("DynamicMesh")
local index1 = dynamicMesh:AddVertex(v1)
local index2 = dynamicMesh:AddVertex(v2)
local index3 = dynamicMesh:AddVertex(v3)
local u = v2 - v1
local v = v3 - v1
local normal = u:Cross(v).Unit
dynamicMesh:SetVertexNormal(index1, normal)
dynamicMesh:SetVertexNormal(index2, normal)
dynamicMesh:SetVertexNormal(index3, normal)
dynamicMesh:SetVertexColor(index1, color)
dynamicMesh:SetVertexColor(index2, color)
dynamicMesh:SetVertexColor(index3, color)
dynamicMesh:AddTriangle(index1, index2, index3)
-- Second one in different order so it's double-sided.
dynamicMesh:AddTriangle(index1, index3, index2)
dynamicMesh.Parent = workspace
local meshPart = dynamicMesh:CreateMeshPartAsync(Enum.CollisionFidelity.Box)
meshPart.Name = name
meshPart.Anchored = true
meshPart.Position = Vector3.new(0, HEIGHT, 0)
meshPart.Parent = workspace
end
local function makeBall(v)
local ball = Instance.new("Part")
ball.Anchored = true
ball.Shape = Enum.PartType.Ball
ball.Size = Vector3.new(0.5,0.5,0.5)
ball.Position = v
ball.Parent = workspace
end
-- Points of reference
makeBall(Vector3.new(0,HEIGHT,0))
makeBall(Vector3.new(SIZE,HEIGHT,0))
makeBall(Vector3.new(0,SIZE+HEIGHT,0))
makeBall(Vector3.new(0,HEIGHT,SIZE))
-- This one renders with side length SIZE^2, though it still
-- thinks its extents are Vector3.new(0.05, SIZE, SIZE)
makeMeshPart(
"X-normal",
Color3.new(1,0.6,0.6),
Vector3.new(0, 0, 0),
Vector3.new(0, 0, SIZE),
Vector3.new(0, SIZE, 0)
)
-- This doesn't render at all
makeMeshPart(
"Y-normal",
Color3.new(0.6,1,0.6),
Vector3.new(0, 0, 0),
Vector3.new(0, 0, SIZE),
Vector3.new(SIZE, 0, 0)
)
-- This doesn't render at all
makeMeshPart(
"Z-normal",
Color3.new(0.6,0.6,1),
Vector3.new(0, 0, 0),
Vector3.new(0, SIZE, 0),
Vector3.new(SIZE, 0, 0)
)
-- Same as the last three, but with EPS added to normal axis
-- in one of the vertices
-- This renders correctly
makeMeshPart(
"X-normal-plus-epsilon",
Color3.new(1,0,0),
Vector3.new(0, 0, 0),
Vector3.new(EPS, 0, SIZE),
Vector3.new(0, SIZE, 0)
)
-- This renders correctly
makeMeshPart(
"Y-normal-plus-epsilon",
Color3.new(0,1,0),
Vector3.new(0, 0, 0),
Vector3.new(0, EPS, SIZE),
Vector3.new(SIZE, 0, 0)
)
-- This renders correctly
makeMeshPart(
"Z-normal-plus-epsilon",
Color3.new(0,0,1),
Vector3.new(0, 0, 0),
Vector3.new(0, SIZE, EPS),
Vector3.new(SIZE, 0, 0)
)