Rebuild one Unity 3D scene in Godot with a player body, follow camera, and collisions. Start by checking the coordinate system, then add the nodes in an order you can test. The guide covers character movement, model imports, lighting, and collision callbacks.
How Godot 3D Differs from Unity 3D
Unity separates a GameObject from the components attached to it: a Transform, a CharacterController, a MeshRenderer, and your scripts all sit side by side on the same object, and a prefab is a saved template of that object graph. Godot collapses most of that into the node itself. A Node3D already carries its own transform; a CharacterBody3D is simultaneously the transform, the physics body, and the attachment point for a script, and a .tscn scene is the equivalent of a prefab, but it is also just a tree of nodes you can open, edit, and instance anywhere, including inside another scene.
Godot 4.6 made Jolt Physics the default for new 3D projects; Godot 4.4 introduced it as a built-in option. Existing projects can retain a different backend. Check the selected engine and retune forces, masses, and joints rather than assuming Unity’s PhysX settings will produce the same behavior.
Fix Coordinate Systems, Handedness, and Units First
This is the trap that quietly breaks imported rotations, forward-facing logic, and follow cameras, so fix it before writing any movement code. Unity uses a left-handed coordinate system: Y is up, Z is forward, and X is right. Godot's 3D space follows the OpenGL convention instead: X is right, Y is up, and Z is nominally the forward axis, but the documentation is explicit that -Z is forward in practice, which makes Godot right-handed. Both engines put Y up, so vertical is not the problem. The handedness flip and the reversed forward axis are.
- A model authored facing +Z in Unity will often face backward in Godot until you rotate it 180 degrees on import or in the scene, because Godot's forward is -Z.
- Mirrored rotations are the usual symptom of a handedness mismatch: a turn that reads correctly in Unity can read as spinning the wrong way once the same angles are applied in Godot's right-handed basis.
- Unity's 1 unit equals 1 meter convention carries over loosely. Godot does not enforce a unit system, but CharacterBody3D's velocity is documented as meters per second, so treat 1 unit as 1 meter and re-check import scale on every FBX or glTF asset rather than assuming it matched on the first try.
Confirm this early with something you can see: instance a single imported mesh, add a CharacterBody3D with a forward-facing arrow or debug mesh, and turn it using your own script before you build a whole level around assumptions borrowed from Unity's axes. Read the engine comparison for the wider set of conceptual differences before you invest a timeline in the rebuild.
Rebuild the 3D Scene in the Right Order
Sequence the 3D rebuild
Click each step in the order you would tackle it.
Your order will appear here.
A Unity 3D scene usually grows GameObject by GameObject, in whatever order features were added. Rebuilding that same scene in Godot goes faster when you deliberately reverse the instinct to import everything at once: stand up the player body first, give it a shape to collide with, frame it with a camera, light the empty box so you can actually see it, then bring in real meshes, and tune movement last once every earlier piece already exists to react to it.
Use the planner below to order your scene setup. Add a player body and shape, a floor, and a camera before testing movement. That makes it easier to identify a wrong forward axis, misplaced collider, or camera offset before imported art complicates the scene.
Replace the CharacterController with CharacterBody3D
Unity's CharacterController exposes a Move() call and CollisionFlags, and it applies its own capsule-based collision resolution outside the main physics simulation. Godot's equivalent is CharacterBody3D: your script owns a Vector3 velocity property, and you call move_and_slide() once per physics step so the body moves and resolves collisions against the world in one pass. move_and_slide() takes no arguments. It reads and updates the node’s velocity and returns true if the body collided with something, so trust the return value and is_on_floor() instead of tracking collision state yourself.
# player.gd — CharacterBody3D replacing a CharacterController
extends CharacterBody3D
@export var speed := 5.0
@export var jump_velocity := 4.5
@export var gravity := 9.8
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity.y -= gravity * delta
elif Input.is_action_just_pressed("jump"):
velocity.y = jump_velocity
var input_dir := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
velocity.x = direction.x * speed
velocity.z = direction.z * speed
move_and_slide()Notice that direction is built from the body's own basis rather than a world-space axis, which is what keeps movement facing the way the character is actually turned instead of a fixed compass direction. This is also where a wrong coordinate-system assumption shows up fastest: if forward feels reversed, check the input sign, the model orientation, and the -Z convention from the previous section.
Set Up Camera3D and Follow Behavior
Camera3D registers itself with the nearest Viewport, and only one camera can be current per viewport at a time; call make_current() if you need to switch explicitly, though a single Camera3D in a simple scene becomes current automatically. Godot has no built-in Cinemachine equivalent, so a Unity project that leaned on virtual cameras for framing and follow behavior needs that logic rebuilt as a small script rather than a drop-in package.
# camera_rig.gd — simple third-person follow, parented under the player
extends Node3D
@export var target: Node3D
@export var follow_speed := 6.0
func _process(delta: float) -> void:
if target:
global_position = global_position.lerp(target.global_position, follow_speed * delta)
look_at(target.global_position + Vector3.UP * 1.0)Put Camera3D under the rig so its local position sets the height and distance while the rig handles following. Check the basic lerp and look_at behavior before adding spring arms, collision-avoidance raycasts, or shake.
Import Models Through the glTF Pipeline
Godot imports FBX files directly through its built-in ufbx library, so a model exported from Unity's source DCC tool as FBX will generally import without an external converter. glTF 2.0 remains the format the documentation recommends when you have a choice, because it round-trips materials, skinning, and animation more predictably than FBX or Collada. If your source files still live in Blender or Maya, re-exporting the ones you actually reuse as glTF is worth the extra step rather than routing everything through FBX by habit.
- Check import scale using an object with known dimensions. Export settings can change the result even when both projects use one unit per meter.
- Verify a forward-facing character or prop actually faces -Z once imported; rotate the imported scene's root, not the mesh data, if it is turned around.
- Confirm skeletons and animations survive the import by playing one clip before wiring up gameplay code against it, since a broken rig is much cheaper to catch on one test mesh than after a dozen scripts depend on it.
Bring in one representative mesh before batch-importing the rest of the art. Cross-check anything you are unsure how to translate against the equivalents reference and the broader asset pipeline guide rather than guessing from Unity import settings that do not carry over.
Light the Scene with WorldEnvironment and Lights
WorldEnvironment holds an Environment resource for the background, ambient lighting, and post-processing. Keep one active WorldEnvironment per scene. A Camera3D can override the environment for its own view. Add a basic environment and light before evaluating imported materials, since missing illumination can make a valid import look wrong.
For direct light, add a DirectionalLight3D and rotate it. Light travels along the node’s local -Z axis; changing its position does not aim the light or change its distance from the scene. Unity directional lights also use direction rather than location.
Move Physics Callbacks to Signals
Unity's OnCollisionEnter and OnTriggerEnter are virtual methods Unity calls on your MonoBehaviour. Godot's closest equivalents are signals: an Area3D emits body_entered(body: Node3D) and body_exited(body: Node3D) for physics bodies passing through it, and area_entered(area: Area3D) / area_exited(area: Area3D) for overlaps with other areas, while the Area3D's monitoring property is enabled. Connect a method to the signal instead of overriding a callback method Godot calls for you.
# pickup.gd — Area3D replacing an OnTriggerEnter callback
extends Area3D
signal collected(points: int)
@export var points := 10
func _ready() -> void:
body_entered.connect(_on_body_entered)
func _on_body_entered(body: Node) -> void:
if body.is_in_group("player"):
collected.emit(points)
queue_free()A solid collision between two physics bodies, rather than an overlap, is read from CharacterBody3D's own move_and_slide() result and its slide-collision queries instead of a signal. There is no per-body OnCollisionEnter equivalent for CharacterBody3D. Reach for Area3D signals when you need trigger-style overlap notifications, and read is_on_floor(), is_on_wall(), and the slide collision data directly when you need to react to the character's own solid contacts. The signal flow guide covers who should own the emitted event once you have more than one listener.
Practice and Sources
Sequence your own scene with the planner above, then rebuild it in that order in a small test level before touching the rest of your Unity project's 3D content. Cross-check unfamiliar calls against the general porting playbook and the physics guide if collision behavior still feels unpredictable once CharacterBody3D is in place. The official sources below verify the coordinate system, CharacterBody API, import pipeline, and physics backend claims in this guide; use the scene checks above to confirm those details in your own project.
Need a small Godot scene to compare with your Unity setup? Build the 3D practice room, use the lighting and materials guide, then compare rendering methods for your target hardware.
Frequently asked questions
- Is Godot's 3D coordinate system the same as Unity's?
- Both are Y-up, but they are not identical. Unity is left-handed with +Z as forward. Godot follows the OpenGL convention: X is right, Y is up, and -Z is forward, which makes it right-handed. Rotations and imported forward-facing assets can end up mirrored or facing backward if you assume the two are interchangeable.
- What replaces Unity's CharacterController in Godot?
- CharacterBody3D. Your script sets its Vector3 velocity property and calls move_and_slide() once per physics frame; the node then exposes is_on_floor(), is_on_wall(), and slide-collision data, similar to what CharacterController's Move() and CollisionFlags gave you.
- Should I import FBX or convert everything to glTF?
- Godot imports FBX directly through the built-in ufbx library, so individual models generally work without conversion. glTF 2.0 is still the format the documentation recommends when you have a choice, because it round-trips materials, skinning, and animation more predictably.
Sources and revision context
Updated September 8, 2026. Clarified 3D migration explanations and linked the room, lighting, and renderer guides. This revision does not establish a full tutorial runtime test.