Skip to content

Instantly share code, notes, and snippets.

@nightcycle
Last active September 2, 2024 15:58
Show Gist options
  • Save nightcycle/703d477738ca26a02ac37f706df4aa61 to your computer and use it in GitHub Desktop.
Save nightcycle/703d477738ca26a02ac37f706df4aa61 to your computer and use it in GitHub Desktop.
Allows for mass porting of decals into surfaceAppearances under quads.
--!strict
-- NEEDS TO BE RUN IN PLUGIN OR COMMAND LINE
--!strict
local STEP = 0.005
local quadTemplate = game:GetService("ServerStorage"):WaitForChild("Quad") :: MeshPart
-- Function to get surface CFrame and Vector2 size
function getSurfaceCFrameAndSize(normalId: Enum.NormalId, cframe: CFrame, size: Vector3): (CFrame, Vector2)
local surfaceCFrame = cframe * CFrame.new(Vector3.FromNormalId(normalId) * size / 2)
local x, y, z = size.X, size.Y, size.Z
local surfaceSize
if normalId == Enum.NormalId.Top or normalId == Enum.NormalId.Bottom then
surfaceSize = Vector2.new(x, z)
elseif normalId == Enum.NormalId.Front or normalId == Enum.NormalId.Back then
surfaceSize = Vector2.new(x, y)
else -- Right or Left
surfaceSize = Vector2.new(z, y)
end
if normalId == Enum.NormalId.Right then
surfaceCFrame *= CFrame.fromEulerAnglesXYZ(0,math.rad(0), math.rad(-90)) * CFrame.Angles(0,math.rad(-90),0)
elseif normalId == Enum.NormalId.Left then
surfaceCFrame *= CFrame.fromEulerAnglesXYZ(0,math.rad(0), math.rad(90)) * CFrame.Angles(0,math.rad(90),0)
elseif normalId == Enum.NormalId.Front then
surfaceCFrame *= CFrame.fromEulerAnglesXYZ(math.rad(-90),0, 0) * CFrame.Angles(0,math.rad(180),0)
elseif normalId == Enum.NormalId.Back then
surfaceCFrame *= CFrame.fromEulerAnglesXYZ(math.rad(90), 0, 0) * CFrame.Angles(0,math.rad(180),0)
elseif normalId == Enum.NormalId.Bottom then
surfaceCFrame *= CFrame.fromEulerAnglesXYZ(math.rad(180), 0, 0) * CFrame.Angles(0,math.rad(180),0)
end
-- Return the new surface CFrame and size
return surfaceCFrame, surfaceSize
end
function toQuad(texture: string, size: Vector2, cf: CFrame, color: Color3): MeshPart
local quad = quadTemplate:Clone()
local surfaceAppearance = quad:WaitForChild("SurfaceAppearance") :: SurfaceAppearance
surfaceAppearance.ColorMap = texture
surfaceAppearance.Color = color
surfaceAppearance.AlphaMode = Enum.AlphaMode.Transparency
surfaceAppearance.Parent = nil :: any
task.wait()
surfaceAppearance.Parent = quad
quad.Size = Vector3.new(size.X, 0, size.Y)
quad.Color = Color3.new(1,1,1)
quad.CFrame = cf + cf.UpVector * STEP
return quad
end
function decalToSurface(part: Part, isRemovingDecalOnCompletion: boolean): {[Enum.NormalId]: MeshPart}
assert(part:IsA("Part"), `part must be a "Part" class, received {part.ClassName}`)
assert(part.Shape == Enum.PartType.Block, `only block shape is currently supported, received {part.Shape}`)
local out: {[Enum.NormalId]: MeshPart} = {}
for i, decal in ipairs(part:GetChildren()) do
if decal:IsA("Decal") then
local texture = decal.Texture
local cf, size = getSurfaceCFrameAndSize(decal.Face, part.CFrame, part.Size)
local quad = toQuad(texture, size, cf, decal.Color3)
quad.Name = decal.Face.Name
quad.Transparency = part.Transparency
quad.Parent = part
out[decal.Face] = quad
if isRemovingDecalOnCompletion then
decal:Destroy()
end
end
end
return out
end
for i, inst in ipairs(workspace:GetDescendants()) do
if inst:IsA("Part") and inst.Shape == Enum.PartType.Block then
decalToSurface(inst, true)
end
end
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
<Meta name="ExplicitAutoJoints">true</Meta>
<External>null</External>
<External>nil</External>
<Item class="MeshPart" referent="RBXC398D59534134F8E9FC08BA92A5C1C3A">
<Properties>
<SharedString name="AeroMeshData">yuZpQdnvvUBOTYh1jqZ2cA==</SharedString>
<bool name="Anchored">true</bool>
<BinaryString name="AttributesSerialize"></BinaryString>
<float name="BackParamA">-0.5</float>
<float name="BackParamB">0.5</float>
<token name="BackSurface">0</token>
<token name="BackSurfaceInput">0</token>
<float name="BottomParamA">-0.5</float>
<float name="BottomParamB">0.5</float>
<token name="BottomSurface">0</token>
<token name="BottomSurfaceInput">0</token>
<CoordinateFrame name="CFrame">
<X>11.6760864</X>
<Y>1.04459703</Y>
<Z>-39.3944588</Z>
<R00>1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<bool name="CanCollide">true</bool>
<bool name="CanQuery">true</bool>
<bool name="CanTouch">true</bool>
<SecurityCapabilities name="Capabilities">0</SecurityCapabilities>
<bool name="CastShadow">true</bool>
<string name="CollisionGroup">Default</string>
<int name="CollisionGroupId">0</int>
<Color3uint8 name="Color3uint8">4288914085</Color3uint8>
<PhysicalProperties name="CustomPhysicalProperties">
<CustomPhysics>false</CustomPhysics>
</PhysicalProperties>
<bool name="DefinesCapabilities">false</bool>
<bool name="DoubleSided">false</bool>
<bool name="EnableFluidForces">true</bool>
<token name="FluidFidelityInternal">0</token>
<float name="FrontParamA">-0.5</float>
<float name="FrontParamB">0.5</float>
<token name="FrontSurface">0</token>
<token name="FrontSurfaceInput">0</token>
<bool name="HasJointOffset">false</bool>
<bool name="HasSkinnedMesh">false</bool>
<Vector3 name="InitialSize">
<X>200</X>
<Y>3.24249268e-05</Y>
<Z>200</Z>
</Vector3>
<Vector3 name="JointOffset">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<float name="LeftParamA">-0.5</float>
<float name="LeftParamB">0.5</float>
<token name="LeftSurface">0</token>
<token name="LeftSurfaceInput">0</token>
<bool name="Locked">false</bool>
<bool name="Massless">false</bool>
<token name="Material">272</token>
<string name="MaterialVariantSerialized"></string>
<Content name="MeshId"><url>rbxassetid://15721480240</url></Content>
<string name="Name">Quad</string>
<SharedString name="PhysicalConfigData">XYNkkNmQJBtLFib0J/b+yQ==</SharedString>
<BinaryString name="PhysicsData"></BinaryString>
<CoordinateFrame name="PivotOffset">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<float name="Reflectance">0</float>
<token name="RenderFidelity">1</token>
<float name="RightParamA">-0.5</float>
<float name="RightParamB">0.5</float>
<token name="RightSurface">0</token>
<token name="RightSurfaceInput">0</token>
<int name="RootPriority">0</int>
<Vector3 name="RotVelocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<int64 name="SourceAssetId">-1</int64>
<BinaryString name="Tags"></BinaryString>
<Content name="TextureID"><null></null></Content>
<float name="TopParamA">-0.5</float>
<float name="TopParamB">0.5</float>
<token name="TopSurface">0</token>
<token name="TopSurfaceInput">0</token>
<float name="Transparency">0</float>
<Vector3 name="UnscaledCofm">
<X>NAN</X>
<Y>NAN</Y>
<Z>NAN</Z>
</Vector3>
<Vector3 name="UnscaledVolInertiaDiags">
<X>NAN</X>
<Y>NAN</Y>
<Z>NAN</Z>
</Vector3>
<Vector3 name="UnscaledVolInertiaOffDiags">
<X>NAN</X>
<Y>NAN</Y>
<Z>NAN</Z>
</Vector3>
<float name="UnscaledVolume">NAN</float>
<Vector3 name="Velocity">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
</Vector3>
<int name="VertexCount">0</int>
<Vector3 name="size">
<X>1</X>
<Y>0.00100000005</Y>
<Z>1</Z>
</Vector3>
</Properties>
<Item class="SurfaceAppearance" referent="RBXD11C4BF848B44BDEAC13CB522060F4B9">
<Properties>
<token name="AlphaMode">0</token>
<BinaryString name="AttributesSerialize"></BinaryString>
<SecurityCapabilities name="Capabilities">0</SecurityCapabilities>
<Color3 name="Color">
<R>1</R>
<G>1</G>
<B>1</B>
</Color3>
<Content name="ColorMap"><null></null></Content>
<bool name="DefinesCapabilities">false</bool>
<Content name="MetalnessMap"><null></null></Content>
<string name="Name">SurfaceAppearance</string>
<Content name="NormalMap"><null></null></Content>
<Content name="RoughnessMap"><null></null></Content>
<int64 name="SourceAssetId">-1</int64>
<BinaryString name="Tags"></BinaryString>
<Content name="TexturePack"><null></null></Content>
</Properties>
</Item>
</Item>
<SharedStrings>
<SharedString md5="XYNkkNmQJBtLFib0J/b+yQ==">Q1NHUEhTBwAAAAIAACBBAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAIA/EAAA
AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAACAPwwAAAAEAAAAAADIwgAAiDcA
AMjCAADIwgAAiLcAAMhCAADIQgAAiDcAAMjCAADIQgAAiLcAAMhCDAAAAAAAAAABAAAAAwAA
AAAAAAADAAAAAgAAAAAAAAACAAAAAwAAAAAAAAADAAAAAQAAAA==</SharedString>
<SharedString md5="yuZpQdnvvUBOTYh1jqZ2cA=="></SharedString>
</SharedStrings>
</roblox>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment