DOCUMENTATION

Blender Modeling Guide

This is a modeling guide for AI agents that build models in Blender through MifBlender, the free Blender add-on and MCP server. It covers how to choose a method for a shape, how to build each kind of shape with typed calls, how to make materials read as real, how to check your own work, and how to hand a finished model to a game engine. Every call named here is in MifBlender 1.3.

Download it for your agent: MifBlender-Modeling-Guide.zip holds this guide as a Claude Code skill (mifblender-modeling/SKILL.md, with the full text beside it) and as a single AGENTS.md file for Cursor, Codex, Windsurf or any other agent. The README inside says where each one goes.

Words used on this page:

  • Profile: a list of [radius, height] points that a lathe spins round an axis to make a round object.
  • Pivot: the point a game engine places and rotates a model around. Blender calls it the origin.
  • Bake: rendering a material's look into image files (texture maps) on the model's UV layout, so any engine can show it.
  • UV layout: how a model's surface is unfolded flat onto an image, so a texture knows where each pixel goes.
  • Albedo: the base color of a surface with no lighting in it.
  • Linear and sRGB: two ways of storing a number in an image. Color maps are sRGB; data maps such as roughness, metallic, normal and AO are linear.

The loop that makes models good

Models come out simple when the work stops at the first shape. Detailed, believable models come from a loop, run many times:

  1. Build one part with typed calls.
  2. Look at it: bl_render_still with return_image: true shows you the render, for about 800 tokens. A file path in a reply shows you nothing.
  3. Compare it with the reference: proportions first, then the details, then the material.
  4. Fix the worst thing you see, and look again.

Two rules hold for every step:

  • Read every reply. A refused call changes nothing and says what to send instead. A reply can be ok: true and still say something went wrong in a field you did not ask about, such as nameWasSuffixed: true (your name was taken, and the object is now Name.001).
  • Measure what you can. bl_object_info gives dimensionsBU, the real size in meters. bl_mesh_quality counts open, flipped and degenerate geometry. A look tells you how it reads; a measurement tells you what is there.

Before the first call

Work in real units. One Blender unit is one meter. Look up or estimate the real size first: a gold pan is about 36 cm across, a 10 liter pail about 27 cm tall, a nugget 2 to 4 cm, a drawstring pouch 12 to 15 cm. A model at the wrong size lights wrong, simulates wrong, and is wrong in every engine.

Get a reference. If the person gave you images, list what each one shows before you start: silhouette, the parts it is made of, where the edges are soft or sharp, what the surface looks like up close, and how shiny it is. If there is no reference, describe the object to yourself in that order and build to the description.

Ask what it is for. A hero prop held up close can carry 20,000 to 30,000 triangles. A pickup the player sees many of wants 1,000 to 5,000. A background prop wants as few as still read. Decide before you start, because it changes the method.

Rotations are radians. bl_transform_object and every create call take radians: 90 degrees is 1.5708. Sending 90 turns the object 90 radians, with no error.

Choose a method by the shape

Most objects belong to one of a few shape families, and each family has a method that fits it far better than pushing primitives around.

The shape Examples Method Main calls
Round, turned on a lathe bucket, pan, bottle, vase, barrel, lamp, chess piece Write the cross-section as a profile and revolve it bl_build_lathe
A flat outline with thickness sign, plate, bracket, cookie cutter, logo Draw the outline and extrude it bl_mesh_from_outline
Hard-surface, boxy crate, machine, console, furniture Primitives, then edit: inset, extrude, loop cut, bevel, boolean bl_create_primitive, bl_inset_faces, bl_extrude_mesh, bl_loop_cut, bl_bevel_edges, bl_boolean_op
Organic and lumpy rock, nugget, potato, tree knot A dense sphere, displaced at two scales, smoothed bl_create_primitive (icosphere), bl_create_texture, a DISPLACE modifier, bl_smooth_vertices
Soft goods and cloth pouch, sack, cushion, bag, folded cloth Generate the mesh yourself, ring by ring, with functions for folds bl_create_mesh
Wire, rope, cord, pipe, handle bucket bail, drawstring, cable, railing A curve with a round bevel, converted to mesh bl_create_curve, bl_convert_object
A feature on part of a surface riffles, vents, grooves, stitching, panel lines A generated patch faded into the surface, or displacement along lines bl_create_mesh, bl_displace_by_rule
Many copies of a part fence, chain links, bolts round a flange Model one, then an ARRAY or MIRROR modifier bl_add_modifier, bl_apply_modifier

Real objects are usually a mix: a bucket is a lathe body, two hard-surface ears, rivets and a curve for the handle. Build each part with its own method, then join them with bl_join_objects.

Round objects: write a profile

bl_build_lathe spins a list of [radius, height] points round the Z axis into a solid whose every face points outward (it checks this by signed volume). Almost all the quality of a round object is in the profile, so write it carefully.

Walk the profile in one continuous path, and give it thickness. A real bucket wall is sheet metal with an outside and an inside. Walk out along the underside, up the outside wall, over the rim, back down the inside wall a millimeter or so in, and across the inside floor. A profile that goes up the outside and stops makes a paper-thin shell that renders wrong from inside.

Radius 0 is a pole. Start and end on r = 0 to close the bottom and the inside floor. An end with radius above 0 is closed with one flat face when caps is on (the default).

Details are a few points each:

  • A rolled rim is a small circle of points: about 12 points round a 4 to 5 mm radius, placed so the circle sits just outside the top of the wall.
  • A pressed rib or bead is a bump in the radius: r + 0.003 * cos(d / w * pi / 2) over a few points, where d is the distance from the rib's center height and w its half-width. Apply the same bump to the inside wall so it reads as pressed sheet.
  • A recessed bottom with a foot ring: the underside sits up 5 to 10 mm, and a small ring at the edge touches the floor.
  • A fillet where the wall meets the floor: two or three points on a curve, never a hard corner.

No point may repeat. Two identical points make a zero-length edge, and the call is refused with nothing created. When you build the list in code from overlapping ranges, remove duplicates before sending.

Use enough segments. 64 round segments for most props; 96 for something seen from above, like a pan, where the rim's outline is obvious.

A short example, a simple cup with a rolled rim (the points in between are left out here):

{"profile": [[0,0.004],[0.034,0.004],[0.036,0],[0.040,0],[0.042,0.006],
             [0.046,0.090],[0.0485,0.0925],[0.0470,0.0950],[0.0450,0.0920],
             [0.0445,0.090],[0.0405,0.010],[0,0.010]],
 "name": "SM_Cup", "segments": 64, "smooth": true}

Hard-surface objects

Start from a primitive at roughly the right size, then edit it:

  • bl_inset_faces then bl_extrude_mesh for panels, recesses and raised plates.
  • bl_loop_cut to add edges where a shape needs to change, and to hold a bevel's shape.
  • bl_boolean_op for holes, slots and cut lines. The cutter must pass all the way through the part. After a difference, compare the target's bounds before and after: a difference can only shrink a part, so bigger bounds mean the cutter's outside faces were kept. The EXACT solver leaves n-gons around a cut; that is fine for a static prop.
  • bl_bevel_edges on every hard edge before you finish. Real objects have no knife-sharp edges, and nothing reads as "a primitive" faster than perfect corners. Read offsetAppliedBU in the reply, because overlap clamping can make the bevel smaller than you asked.

Thin parts need real thickness. A plate 3 mm thick is a scaled cube. Make it a cube, scale it with bl_transform_object, and bake the scale in with bl_apply_transform before you bevel it, or the bevel comes out stretched.

Small parts sell the model. Rivet heads, screw heads, weld seams, a lip on an edge. Each one is a primitive or two. Without them, even a good silhouette looks like a toy.

Organic objects: displacement worked at the right size

A rock or a nugget is a dense sphere pushed in and out by noise. In MifBlender that is a DISPLACE modifier reading a texture made with bl_create_texture (types such as CLOUDS, VORONOI, MARBLE, MUSGRAVE, DISTORTED_NOISE).

The texture's noise size is fixed at 0.25 units, and that matters. On a 4 cm nugget, 0.25 m noise is bigger than the object and only shifts it a little. So work the shape at a bigger size and scale it back:

  1. Make an icosphere (kind: "icosphere", subdivisions: 5) of radius 0.2.
  2. Stretch it off round with bl_transform_object scale, for example [1.45, 0.95, 0.62], and apply the scale.
  3. Big lumps: a CLOUDS texture and a DISPLACE modifier with strength: 0.15, mid_level: 0.55 and texture_coords: "LOCAL". Apply it.
  4. Smaller pits and folds: scale the object up three times and apply that, so the same noise reads three times smaller. Then a VORONOI texture with a negative strength (pushing in) and mid_level: 0. Apply it.
  5. bl_smooth_vertices with 2 iterations and a factor about 0.35, to soften the noise into worn shapes.
  6. Scale down to the real size, apply the scale, and set the origin with bl_set_origin mode: "bottom" so it rests on the ground.

Look after each displacement. If the lumps are too even, raise contrast on the texture or stretch the object more before displacing. Try two or three seeds (different texture names) and keep the best. Real nuggets, rocks and potatoes are never symmetrical.

Soft goods: generate the mesh yourself

Cloth and leather are where primitives fail worst. A pouch is a sack shape gathered by a cord into folds, and you can write that shape directly. bl_create_mesh takes a list of vertices and faces, so a few lines of math build it:

  1. A profile of [radius, height] from the bottom pole to the lip, just like a lathe.
  2. Rings round the axis: for each profile point, N vertices (64 to 72) at angles 2 * pi * k / N.
  3. Shape functions move each vertex:
    • flatten scales Y, so a pouch is flat at the belly and rounder at the gathered neck;
    • gather pleats the radius at the neck with a fold function, strongest just above the cord and fading down the belly;
    • wrinkle adds a few gentle sine waves of different frequencies over the body.
  4. Faces: quads between neighboring rings, and triangle fans at the poles.
  5. A rolled lip: the profile goes over the top and a little way down inside, and ends in an inner pole a centimeter below the rim. The opening reads as pinched shut without showing a hole.
  6. One level of subdivision (SUBSURF modifier, applied), then a CLOUDS displacement for soft creases, worked at a bigger size as above.

Make every variation continuous, or the surface tears. Random folds of random width and height look right, but two neighboring folds must meet at the same point. The way to get that: let the valley between folds depend only on height, and give each fold its own ridge height that falls to zero at its edges, for example ridge = strength_i * sin(pi * f) ** 0.7 with f running 0 to 1 across the fold. If a fold's own strength also scales the valley, each fold boundary becomes a step in the mesh.

Make the lip uneven. Give each fold its own small height offset at the rim. A perfectly level lip makes leather look like a fluted vase.

Wire, rope and cord: curves

bl_create_curve with a bevel depth makes a round tube along a path. The bevel depth is the tube's radius: bevel_depth: 0.0022 is a 4.4 mm wire.

  • Use POLY with points you smoothed yourself. A NURBS curve does not pass through its first and last points, so a cord meant to start inside a knot stops short and floats. Generate a smooth path through your control points (a Catmull-Rom spline is a few lines) and send it as spline_type: "POLY".
  • Hooks and loops are just more points: a wire handle that hooks through an eye bends down and in for its last two or three points.
  • Convert to mesh with bl_convert_object before joining it to other parts. A curve cannot be joined to a mesh.
  • Hide the open ends. A tube has open ends. Put each one inside another part, such as a knot, an eye or a wall, rather than leaving it showing.

A knot at a cord's end is a slightly squashed sphere centered on the last point, with a short, slightly fatter piece of tube past it for the frayed end.

Features on part of a surface

Riffles on one side of a pan, vents on a panel, a pressed logo: these sit on part of a surface. Two ways work well:

  • A generated patch: build a grid with bl_create_mesh that follows the surface, lift it 0.05 to 0.1 mm off the surface, and give the feature its height. Fade the feature to zero over its last 10 to 15 degrees or few millimeters at every edge, so it presses into the surface and has no cut ends. Do not give the patch thickness with a Solidify modifier: the thickness shows as an outline round the patch. Join it to the main mesh.
  • Displacement along lines: bl_displace_by_rule sinks SEAM grooves and STITCH dashes into a dense mesh along a polyline or along marked edges. This is how seams, stitching and panel lines go into a high-poly model before a bake.

Materials that read as real

Every material starts with bl_create_material, and bl_add_procedural_texture adds patterns with no image files: noise, voronoi, wave, magic, brick, checker, gradient and more. Then the bake turns it all into images for the engine.

Decide what it is made of first. Metal (metallic: 1) or not (metallic: 0). There is nothing in between in real life, apart from dirt on metal. "Make it look less shiny" usually means "it is not metal": set metallic to 0 and roughness to 0.6 or more.

Starting values that work (linear base color, roughness):

Surface Base color Metallic Roughness What adds realism
Native gold about [1.0, 0.56, 0.11] 1 0.20 to 0.35 warm color variation; very fine grain bump
Galvanized steel about [0.60, 0.61, 0.62] 1 0.30 to 0.55 voronoi "spangle" in roughness, faint mottling in color
Plain steel about [0.55, 0.55, 0.56] 1 0.25 to 0.45 noise in roughness for wear
Matte painted or plastic any, kept below 0.8 0 0.6 to 0.85 soft noise in color, a little dirt
Black leather about [0.01 to 0.03] 0 0.30 to 0.55 sheen variation in roughness, fine pebble grain bump
Brown leather about [0.08, 0.04, 0.02] 0 0.40 to 0.60 the same, plus darker creases
Rope or cord dark to mid, by fiber 0 0.80 a wave bump for the twist

Black is darker than you think. A base color of 0.04 already renders mid-grey under bright studio light, and Blender's AgX view (the default from 4.2) shows dark colors about two stops lighter. Black leather wants 0.01 to 0.03.

Metals need a saturated base color. Gold reflecting a grey studio looks like pale brass unless its base color is a strong orange-yellow.

Variation is the realism, and it should be gentle. A color ramp from one shade to a slightly different one looks like a real surface. A ramp from dark to light looks like granite. Keep color variation within about 20 to 30 percent of the base value.

How bl_add_procedural_texture behaves:

  • Use space: "object" and pass scale as three numbers, [s, s, s]. One number scales only X and Y, and the pattern stretches on any face that does not face up.
  • Blender's Noise output stays between about 0.26 and 0.73, not 0 to 1. Put color ramp stops inside that band, or a stop is never reached.
  • Color ramp stops are objects: {"position": 0.5, "color": [r, g, b]}.
  • input: "normal" builds a bump. Always pass a distance in meters for fine detail: 0.0003 to 0.001 for grain, a few millimeters for dents. Without it the bump can be a full meter deep.
  • To change a pattern you already added, call again with the same node name (node_name: "Grain", say) and replace: true. A new name adds a second pattern beside the first.

Bumps for fine detail, geometry for shape. Riffles, ribs, folds and rims are geometry: they change the silhouette and catch shadows. Grain, pores, spangle and scratches are a bump in the material, and the bake turns them into a normal map.

How to look at your work

A good look needs a consistent studio:

  • World: bl_set_world with an hdri from Blender's own files, <Blender>/<version>/datafiles/studiolights/world/studio.exr, at strength about 0.7. Metals need something to reflect; a flat grey world makes every metal look flat.
  • Lights: three area lights with bl_create_light: a key above and to one side, a weaker fill on the other side, and a rim behind.
  • Floor: a large plane with a dark-grey matte material, so the object has a shadow and a horizon.
  • Engine: bl_set_render_settings with engine: "CYCLES", 64 to 96 samples and use_denoising: true. Judge metal and glass in Cycles. A 1024 px Cycles still takes about 20 to 30 seconds on a typical desktop GPU or CPU, which is cheap next to a wrong model.
  • Camera: put it where the object fills about two thirds of the frame. For a lens of L mm on a 36 mm sensor, the distance for an object of size s is about 0.62 * s / tan(atan(18 / L)). Delete the old camera and make a new one with look_at: [x, y, z] on the object's center and make_active: true, so you never render from a stale camera.

Look from at least two angles: one at a three-quarter view from slightly above, and one that shows the side or back you have not looked at yet. Render settings stay in the scene after a render, so set them once.

Game-ready

Before a model leaves Blender:

  1. One object, real size, transforms applied. Join the parts with bl_join_objects (each keeps its material slot). Check the size with bl_object_info.
  2. The pivot at the bottom center, so the model stands on the ground at Z = 0: bl_set_origin with mode: "bottom".
  3. A clean UV layout: bl_recipe_game_ready with apply_transform: true, unwrap: true, force_unwrap: true, uv_method: "SMART" and pivot: "bottom". It applies the transforms, sets the pivot, unwraps, and then checks the result. force_unwrap: true replaces a lathe's or generator's own UVs, which are often outside the 0 to 1 tile.
  4. Check the mesh with bl_mesh_quality and read its checks:
    • nonManifoldEdges, windingFlippedEdges, degenerateFaces and insideOutParts should all be 0.
    • boundaryEdges counts open edges. On a closed model it should be 0. Some are fine when you know where they are, such as the hidden ends of a cord, but name them.
    • notMeasured lists what it did not check. A concern count of 0 does not cover what was not measured.
  5. The triangle budget. Faces in the reply are mostly quads; triangles are about twice the quad count. If it is over budget, bl_decimate_mesh with target_tris: 3000 (or your budget) reduces it, and bl_build_lod_chain writes lower versions for distance.
  6. Name it the way the engine's project does, commonly SM_ for a static mesh.

Bake and export

Bake with bl_bake_texture_set. It bakes several maps in one job, in a second Blender so the session stays free, and names them T_<object>_<suffix>. The reply has a jobId; call bl_bake_texture_set with job_id: "<that id>" every 10 seconds or so until complete is true, and stop with an error if it never is.

  • Maps for a non-metal: DIFFUSE (the color map, suffix BC), ROUGHNESS, NORMAL when the material has a bump, and AO.
  • Maps for a metal: add METALLIC. A DIFFUSE bake reads color times (1 minus metallic), so on a metal it comes out black. Bake the color with the material's metallic set to 0 for that one bake (bl_set_material_properties), then set it back and bake the rest.
  • pack_orm: true also writes T_<object>_ORM: occlusion in red, roughness in green, metallic in blue, which Unreal and many shaders want.
  • 2048 px for a hero prop, 1024 for a small one. Roughness and normal need only 1 or 2 samples; AO wants 32 to 64.
  • Look at the maps. A color map with sensible islands and no black holes, and an AO that darkens the creases, means the bake worked.

Export both formats:

  • bl_export_mesh writes FBX: pass mesh_smooth_type: "FACE", use_tspace: true, local_space: true, and path_mode: "STRIP" so the file does not point at your disk. Textures go beside it as the PNGs.
  • bl_export_scene with a .glb file writes glTF binary with the material and its textures embedded, which Godot, three.js and many tools open directly.
  • Check that each file is new: its size and its time. An old file from an earlier run can sit at the same path.

Tell the engine how to read the maps. Write a short README beside the files with the size, pivot, triangles, material slots and maps:

  • Unity: smoothness is 1 minus roughness, stored in the alpha of the metallic map in URP.
  • Unreal: the ORM map goes in with sRGB off, and the normal map needs Flip Green Channel, because the bake writes the OpenGL convention (green up).
  • Godot: reads the GLB as is.

Traps that cost a round trip

  • Names get suffixed. Creating Floor when a Floor exists makes Floor.001, with ok: true. Use the name the reply returns. Re-running a build script without deleting the first result doubles everything.
  • Exact names are exact. The primitive is uvsphere, and a subdivision modifier added as SUBSURF is named Subsurf. When you are not sure of a parameter or value, ask with bl_describe_op, or send the call: a refusal lists what it accepts, and nothing changes.
  • A wrong parameter name is refused before anything runs, and the error lists the real ones. Fix the name and send it again; do not guess a second time.
  • Deleting an object can leave its data holding the name. Pass purge_orphans: true to bl_delete_object when you will reuse the name, such as a camera you replace every shot.
  • Scripts on Windows: when you generate Python or JSON with file paths in it, use forward slashes (D:/models/out). A backslash followed by a digit or certain letters becomes a different character inside a string.
  • Look before you report. A model is done when the render shows it is done, the mesh check is clean and the files are on disk, and only then.

The finished checklist

  • Real size in meters, checked with bl_object_info.
  • Built with the method that fits each part's shape, with real thickness where real objects have it.
  • Bevels or soft edges where the real object has them; small parts such as rivets, seams and knots present.
  • Materials chosen as metal or not, with gentle variation, checked in a Cycles render from two angles against the reference.
  • One object, transforms applied, pivot at the bottom center.
  • UVs inside the 0 to 1 tile; bl_mesh_quality clean, or every open edge accounted for.
  • Within the triangle budget, or with an LOD.
  • Maps baked and looked at; FBX and GLB exported and checked as new files.
  • A README beside the files with the size, pivot, triangles, maps and how to set them up.

Worked examples

These four props were built with exactly the methods above, each in a few dozen calls.

  • A gold pan, 36 cm.
    • The body is a lathe: a flat bottom, a 40-degree wall, a rolled rim of 12 points, and a 1 mm sheet with the inside wall offset along the wall's normal.
    • Riffles: seven sawtooth ridges (a 2.6 mm lip, then a slope back) in a generated grid over a 120-degree side of the inner wall, each ridge fading out over 15 degrees.
    • Material: matte, metallic 0, roughness 0.6 to 0.8.
    • About 10,700 triangles.
  • A gold nugget, 3.5 cm.
    • An icosphere stretched 1.45 : 0.95 : 0.62, with a CLOUDS displacement for lumps at 10 times size, then a VORONOI displacement inward for pits at 30 times size, then smoothed.
    • Gold metal with warm color noise and a fine bump.
    • 5,120 triangles.
  • A leather drawstring pouch, 14 cm.
    • A generated ring mesh: 14 folds of random width gathered at the neck, each with its own ridge height, length down the belly and lip height, and valleys that depend on height only.
    • A rolled lip into a pinched opening, one subdivision level, and soft creases from a CLOUDS displacement.
    • A cord loop with two tails as smoothed POLY curves, each ending in a knot.
    • About 26,000 triangles.
  • A galvanized pail, 27 cm.
    • A lathe body with two pairs of ribs 3.2 mm proud, a rolled rim and a recessed bottom.
    • Beveled ears tilted to the wall, with rivets and ring eyes.
    • A 4.4 mm wire bail curve hooked through the eyes.
    • Voronoi spangle in roughness and bump.
    • About 16,000 triangles.