11 KiB
| title | description |
|---|---|
| Model generation | How text prompts and preset schemas can generate both static 3D assets and fully functional models such as vehicles that drive, planes that fly, and weapons that shoot. |
Through text prompts and preset schemas, you (and players in‑experience) can generate both static 3D assets and fully functional models such as vehicles that drive, planes that fly, and weapons that shoot. This guide demonstrates how to use Class.GenerationService:GenerateModelAsync()|GenerateModelAsync() as part of a dynamic, player‑driven creative experience.
Overview
Class.GenerationService:GenerateModelAsync()|GenerateModelAsync() enables generation of multi‑mesh geometries with the following advantages:
- The provided schema defines how the generated geometry will be broken into parts.
- Any object generated in-experience will be replicated and visible to all players, allowing them to build together in real‑time.
- Generated meshes are higher fidelity with better overall forms, silhouettes, more detail, and fewer artifacts. Generated textures are more coherent and detailed, with less graininess and less pronounced baked‑in lighting.
- Generation times have lower latency, enabling quicker and more responsive creation in experiences.
- You and even players during gametime can specify bounding boxes to suggest size and proportions of the generated model.
- An optional max triangle count keeps generated objects performant for your experience.
Schema-based generation
To create articulated, functional objects, the generated geometry must be separated into multiple Class.MeshPart|MeshParts. For example, to create a drivable car with wheels that spin and steer, at least five Class.MeshPart|MeshParts are needed: one for the car body and four for each of the car's wheels. Class.GenerationService:GenerateModelAsync()|GenerateModelAsync() achieves this through a preset schema as shown in the following code snippet:
local GenerationService = game:GetService("GenerationService")
local Workspace = game:GetService("Workspace")
-- Set up inputs for the generated geometry
local inputs = {
TextPrompt = "green dragon car with 4 wheels"
}
-- Set schema to the predefined five-model car chassis
local schema = {
PredefinedSchema = "Car5"
}
-- Make the call to generate the model
local success, result, metadata = pcall(function()
return GenerationService:GenerateModelAsync(inputs, schema)
end)
if success then
-- Scale model to target size and position near world center
local targetSize = 16
local modelSize = result:GetExtentsSize()
local scaleFactor = targetSize / math.max(modelSize.X, modelSize.Y, modelSize.Z)
result:ScaleTo(scaleFactor)
result:PivotTo(CFrame.new(0, result:GetExtentsSize().Y / 2, -40))
-- Anchor all parts so that the meshes don't fall apart
for _, descendant in result:GetDescendants() do
if descendant:IsA("BasePart") then
descendant.Anchored = true
end
end
-- Name the model and parent it to workspace
result.Name = "BasicDragonCarGeneration"
result.Parent = Workspace
else
warn(result)
end
`Class.GenerationService:GenerateModelAsync()|GenerateModelAsync()` currently supports two fixed schemas: `Car5` which produces a car with a body and four wheels, and `Body1` which yields a single `Class.MeshPart` object. Additional schemas will be supported in the future, as well as creator‑customized (open) schemas.
The following image shows the expected output and its construction as it appears in the Explorer hierarchy:
Retargetable scripts
In Roblox, behaviors typically encompass the scripts, attachments, constraints, and other instance types attached to static textured geometries to make them functional. Since Class.GenerationService:GenerateModelAsync()|GenerateModelAsync() generates a wide range of geometries on‑the‑fly, retargetable scripts must be attached to automatically adapt behaviors to expected functionality.
For example, consider an experience where players get to make their own drivable cars. Class.GenerationService:GenerateModelAsync()|GenerateModelAsync() takes the player prompt and generates five distinct meshes (body and four wheels) via the Car5 schema. Then, a preset retargetable script adapts its driving behavior to the size and shape of the model to ensure the car is drivable and its wheels spin realistically.
block-beta
columns 1
block:Main
columns 5
Prompt([" prompt <br /> (creator) "])
Generate{" Geometry <br /> Generator <br />(Roblox)"}
Geometry(("<b>GEOMETRY</b><br /> <span style="font-size:80%; color:white;">single / multi-mesh</span> "))
space:2
Schema([" schema "])
space
Retarget{" Retarget <br />behavior<br />(creator)"}
space
FunctionalModel(((" <b>FUNCTIONAL</b> <br /><b>MODEL</b>")))
Prompt --> Generate
Generate --> Geometry
Geometry --> Retarget
Retarget --> FunctionalModel
Schema --> Generate
end
style Main fill-opacity: 0, stroke-opacity: 0;
style Prompt color:white, fill:RoyalBlue;
style Schema color:white, fill:RoyalBlue;
style Generate color:white, fill:#9933FF, fill-opacity:0.7;
style Retarget color:white, fill:RoyalBlue;
style Geometry color:white, fill:SeaGreen
style FunctionalModel color:white, fill:SeaGreen
To test retargetable scripts:
-
Download the
Behaviors.rbxmfile (right‑click and "save as" to your local system). -
In Studio's Explorer hierarchy, right‑click
Class.ReplicatedStorage, select Insert ⟩ Import Roblox Model, and choose the downloaded file. The model unpacks into several folders.
-
Copy and paste one of the following code snippets into a server
This example generates a functional car with a brake, nitro boost, audio and visual effects, and an on‑screen UI speedometer.Class.ScriptwithinClass.ServerScriptService, depending on the object type you'd like to generate.
To test other generated models with retargetable scripts in the `Car5` schema, change the `TextPrompt` string value on line 7 and playtest again. Ideas include:```lua title="Script in ServerScriptService" local GenerationService = game:GetService("GenerationService") local ReplicatedStorage = game:GetService("ReplicatedStorage") local Workspace = game:GetService("Workspace") -- Set up inputs for the generated geometry local inputs = { TextPrompt = "green dragon car with 4 wheels" } -- Set schema to the predefined five-model car chassis local schema = { PredefinedSchema = "Car5" } -- Make the call to generate the model local success, result, metadata = pcall(function() return GenerationService:GenerateModelAsync(inputs, schema) end) if success then -- Scale model to target size local targetSize = 16 local modelSize = result:GetExtentsSize() local scaleFactor = targetSize / math.max(modelSize.X, modelSize.Y, modelSize.Z) result:ScaleTo(scaleFactor) -- Load "makeFunctional" module for "CarBehavior" local makeFunctional = require(ReplicatedStorage.Behaviors.CarBehavior.makeFunctional) -- Reference car parts by names guaranteed through the "Car5" schema local body = result:FindFirstChild("body") local frontLeftWheel = result:FindFirstChild("front left wheel") local frontRightWheel = result:FindFirstChild("front right wheel") local rearLeftWheel = result:FindFirstChild("rear left wheel") local rearRightWheel = result:FindFirstChild("rear right wheel") -- Set behavioral configuration parameters local config = { seatPosition = "inside", invisibleWhenSeated = false } -- Attach behavior via the "makeFunctional" script local functionalModel = makeFunctional(result, frontLeftWheel, frontRightWheel, rearLeftWheel, rearRightWheel, body, config) -- Position the model near world center functionalModel:PivotTo(CFrame.new(0, functionalModel:GetExtentsSize().Y / 2, -40)) functionalModel.Name = "BasicDragonCarGeneration" functionalModel.Parent = Workspace else warn(result) end ```"yellow sports car with a spoiler""purple bat car with 4 wheels""giant monster truck with spiked roof"
```lua title="Script in ServerScriptService" local GenerationService = game:GetService("GenerationService") local ReplicatedStorage = game:GetService("ReplicatedStorage") local Workspace = game:GetService("Workspace") -- Set up inputs for the generated geometry local inputs = { TextPrompt = "basic paper airplane with two wings" } -- Set schema to the predefined static body local schema = { PredefinedSchema = "Body1" } -- Make the call to generate the model local success, result, metadata = pcall(function() return GenerationService:GenerateModelAsync(inputs, schema) end) if success then -- Scale model to target size local targetSize = 30 local modelSize = result:GetExtentsSize() local scaleFactor = targetSize / math.max(modelSize.X, modelSize.Y, modelSize.Z) result:ScaleTo(scaleFactor) -- Load "makeFunctional" module for "AirplaneBehavior" local makeFunctional = require(ReplicatedStorage.Behaviors.AirplaneBehavior.makeFunctional) -- Set behavioral configuration parameters local config = { seatPosition = "ontop", forwardSpeed = 80, turnSpeed = 8 } -- Attach behavior via the "makeFunctional" script local functionalModel = makeFunctional(result, config) -- Place model slightly above ground to let it fall into place local boundingBox = functionalModel:GetBoundingBox() local location = Vector3.new(0, boundingBox.Y / 2 + 3, -40) functionalModel:PivotTo(CFrame.new(location)) functionalModel.Name = "BasicPlaneGeneration" functionalModel.Parent = Workspace else warn(result) end ```