mirror of
https://github.com/godotengine/godot-docs.git
synced 2025-12-31 17:49:03 +03:00
More Godot 4 rename fixes (#6315)
* Spatial -> 3D, Transform, Quaternion * File -> FileAccess * Camera -> Camera3D * Update references to MeshInstance and MultiMeshInstance * ImmediateGeometry -> ImmediateMesh, misc renames
This commit is contained in:
@@ -334,3 +334,5 @@ source,destination
|
||||
/tutorials/viewports/using_viewport_as_texture.html,/tutorials/shaders/using_viewport_as_texture.html
|
||||
/tutorials/viewports/viewports.html,/tutorials/rendering/viewports.html
|
||||
/tutorials/physics/using_kinematic_body_2d.html,/tutorials/physics/using_character_body_2d.html
|
||||
/tutorials/plugins/editor/spatial_gizmos.html,/tutorials/plugins/editor/3d_gizmos.html
|
||||
/tutorials/3d/procedural_geometry/immediategeometry.html,/tutorials/3d/procedural_geometry/immediatemesh.html
|
||||
|
||||
|
@@ -185,7 +185,7 @@ Procedural geometry series:
|
||||
- :ref:`doc_arraymesh`
|
||||
- :ref:`doc_surfacetool`
|
||||
- :ref:`doc_meshdatatool`
|
||||
- :ref:`doc_immediategeometry`
|
||||
- :ref:`doc_immediatemesh`
|
||||
|
||||
Optimization
|
||||
^^^^^^^^^^^^
|
||||
|
||||
@@ -21,8 +21,8 @@ Node2D
|
||||
|
||||
.. image:: img/Node2D.png
|
||||
|
||||
Spatial
|
||||
-------
|
||||
Node3D
|
||||
------
|
||||
|
||||
.. image:: img/Spatial.png
|
||||
|
||||
|
||||
@@ -59,11 +59,11 @@ where resource_type is one of:
|
||||
|
||||
Below every heading comes zero or more ``key = value`` pairs. The
|
||||
values can be complex datatypes such as Arrays, Transforms, Colors, and
|
||||
so on. For example, a spatial node looks like:
|
||||
so on. For example, a Node3D looks like:
|
||||
|
||||
::
|
||||
|
||||
[node name="Cube" type="Spatial" parent="."]
|
||||
[node name="Cube" type="Node3D" parent="."]
|
||||
transform=Transform( 1.0, 0.0, 0.0 ,0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 )
|
||||
|
||||
|
||||
@@ -92,10 +92,10 @@ the path should be ``"."``. Here is an example scene tree
|
||||
|
||||
::
|
||||
|
||||
[node name="Player" type="Spatial"] ; The scene root
|
||||
[node name="Arm" parent="." type="Spatial"] ; Parented to the scene root
|
||||
[node name="Hand" parent="Arm" type="Spatial"]
|
||||
[node name="Finger" parent="Arm/Hand" type="Spatial"]
|
||||
[node name="Player" type="Node3D"] ; The scene root
|
||||
[node name="Arm" parent="." type="Node3D"] ; Parented to the scene root
|
||||
[node name="Hand" parent="Arm" type="Node3D"]
|
||||
[node name="Finger" parent="Arm/Hand" type="Node3D"]
|
||||
|
||||
|
||||
Similar to the internal resource, the document for each node is currently
|
||||
@@ -110,7 +110,7 @@ save a file with that node in it. Some example nodes are:
|
||||
transform = Transform( 1.0 , 0.0 , -0.0 , 0.0 , -4.371138828673793e-08 , 1.0 , -0.0 , -1.0 , -4.371138828673793e-08 ,0.0 ,0.0 ,-0.0 )
|
||||
|
||||
|
||||
[node type="MeshInstance" name="Sphere" parent="SpherePhysics"]
|
||||
[node type="MeshInstance3D" name="Sphere" parent="SpherePhysics"]
|
||||
|
||||
mesh = SubResource(9)
|
||||
transform = Transform( 1.0 , 0.0 , -0.0 , 0.0 , 1.0 , -0.0 , -0.0 , -0.0 , 1.0 ,0.0 ,0.0 ,-0.0 )
|
||||
@@ -141,13 +141,13 @@ NodePath
|
||||
|
||||
A tree structure is not enough to represent the whole scene. Godot uses a
|
||||
``NodePath(Path/To/Node)`` structure to refer to another node or attribute of
|
||||
the node anywhere in the scene tree. For instance, MeshInstance uses
|
||||
the node anywhere in the scene tree. For instance, MeshInstance3D uses
|
||||
``NodePath()`` to point to its skeleton. Likewise, Animation tracks use
|
||||
``NodePath()`` to point to node properties to animate.
|
||||
|
||||
::
|
||||
|
||||
[node name="mesh" type="MeshInstance" parent="Armature001"]
|
||||
[node name="mesh" type="MeshInstance3D" parent="Armature001"]
|
||||
|
||||
mesh = SubResource(1)
|
||||
skeleton = NodePath("..:")
|
||||
@@ -158,7 +158,7 @@ the node anywhere in the scene tree. For instance, MeshInstance uses
|
||||
[sub_resource id=3 type="Animation"]
|
||||
|
||||
...
|
||||
tracks/0/type = "transform
|
||||
tracks/0/type = "transform"
|
||||
tracks/0/path = NodePath("Cube:")
|
||||
...
|
||||
|
||||
@@ -166,7 +166,7 @@ the node anywhere in the scene tree. For instance, MeshInstance uses
|
||||
Skeleton
|
||||
~~~~~~~~
|
||||
|
||||
The Skeleton node inherits the Spatial node, but also may have a list of bones
|
||||
The Skeleton node inherits the Node3D node, but also may have a list of bones
|
||||
described in key-value pairs in the format ``bones/Id/Attribute=Value``. The
|
||||
bone attributes consist of:
|
||||
|
||||
@@ -213,7 +213,7 @@ to a single bone in a Skeleton node. The BoneAttachment has a
|
||||
``bone_name=NameOfBone`` attribute, and the corresponding bone being the parent has the
|
||||
BoneAttachment node in its ``bound_children`` list.
|
||||
|
||||
An example of one MeshInstance parented to a bone in Skeleton:
|
||||
An example of one MeshInstance3D parented to a bone in Skeleton:
|
||||
|
||||
::
|
||||
|
||||
@@ -231,7 +231,7 @@ An example of one MeshInstance parented to a bone in Skeleton:
|
||||
|
||||
bone_name = "Bone"
|
||||
|
||||
[node name="Cylinder" type="MeshInstance" parent="Armature/BoneAttachment"]
|
||||
[node name="Cylinder" type="MeshInstance3D" parent="Armature/BoneAttachment"]
|
||||
|
||||
mesh = SubResource(1)
|
||||
transform = Transform(1.0, 0.0, 0.0, 0.0, 1.86265e-09, 1.0, 0.0, -1.0, 0.0, 0.0219986, -0.0343127, 2.25595)
|
||||
@@ -262,7 +262,7 @@ AnimationPlayer. The root node is stored as
|
||||
Resources
|
||||
---------
|
||||
|
||||
Resources are components that make up the nodes. For example, a MeshInstance
|
||||
Resources are components that make up the nodes. For example, a MeshInstance3D
|
||||
node will have an accompanying ArrayMesh resource. The ArrayMesh resource
|
||||
may be either internal or external to the TSCN file.
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ the jump and squash mechanics.
|
||||
For now, we're going to create a basic rig for our character's 3D model. This
|
||||
will allow us to rotate the model later via code while it plays an animation.
|
||||
|
||||
Add a *Spatial* node as a child of *Player* and name it *Pivot*. Then, in the
|
||||
Add a *Node3D* node as a child of *Player* and name it *Pivot*. Then, in the
|
||||
FileSystem dock, expand the ``art/`` folder by double-clicking it and drag and
|
||||
drop ``player.glb`` onto the *Pivot* node.
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ call its ``normalize()`` method.
|
||||
if (direction != Vector3.Zero)
|
||||
{
|
||||
direction = direction.Normalized();
|
||||
GetNode<Spatial>("Pivot").LookAt(Translation + direction, Vector3.Up);
|
||||
GetNode<Node3D>("Pivot").LookAt(Translation + direction, Vector3.Up);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ Here is the complete ``Player.gd`` code for reference.
|
||||
if (direction != Vector3.Zero)
|
||||
{
|
||||
direction = direction.Normalized();
|
||||
GetNode<Spatial>("Pivot").LookAt(Translation + direction, Vector3.Up);
|
||||
GetNode<Node3D>("Pivot").LookAt(Translation + direction, Vector3.Up);
|
||||
}
|
||||
|
||||
// Ground velocity
|
||||
@@ -346,7 +346,7 @@ Adding a camera
|
||||
|
||||
Let's add the camera next. Like we did with our *Player*\ 's *Pivot*, we're
|
||||
going to create a basic rig. Right-click on the *Main* node again and select
|
||||
*Add Child Node* this time. Create a new *Position3D*, name it *CameraPivot*,
|
||||
*Add Child Node* this time. Create a new *Marker3D*, name it *CameraPivot*,
|
||||
and add a *Camera* node as a child of it. Your scene tree should look like this.
|
||||
|
||||
|image3|
|
||||
|
||||
@@ -10,7 +10,7 @@ Let's design the monsters themselves in a new scene. The node structure is going
|
||||
to be similar to the *Player* scene.
|
||||
|
||||
Create a scene with, once again, a *CharacterBody3D* node as its root. Name it
|
||||
*Mob*. Add a *Spatial* node as a child of it, name it *Pivot*. And drag and drop
|
||||
*Mob*. Add a *Node3D* node as a child of it, name it *Pivot*. And drag and drop
|
||||
the file ``mob.glb`` from the *FileSystem* dock onto the *Pivot* to add the
|
||||
monster's 3D model to the scene. You can rename the newly created *mob* node
|
||||
into *Character*.
|
||||
|
||||
@@ -44,7 +44,7 @@ viewport.
|
||||
Adding placeholder cylinders
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Let's add the placeholder meshes. Add a new *Spatial* node as a child of the
|
||||
Let's add the placeholder meshes. Add a new *Node3D* node as a child of the
|
||||
*Main* node and name it *Cylinders*. We'll use it to group the cylinders. As a
|
||||
child of it, add a *MeshInstance* node.
|
||||
|
||||
@@ -101,7 +101,7 @@ last one.
|
||||
|
||||
|image12|
|
||||
|
||||
In the *Inspector*, expand the *Material* section and assign a *SpatialMaterial*
|
||||
In the *Inspector*, expand the *Material* section and assign a *StandardMaterial3D*
|
||||
to slot *0*.
|
||||
|
||||
|image13|
|
||||
|
||||
@@ -418,7 +418,7 @@ Finally, the longest script, ``Player.gd``.
|
||||
if (direction != Vector3.Zero)
|
||||
{
|
||||
direction = direction.Normalized();
|
||||
GetNode<Spatial>("Pivot").LookAt(Translation + direction, Vector3.Up);
|
||||
GetNode<Node3D>("Pivot").LookAt(Translation + direction, Vector3.Up);
|
||||
}
|
||||
|
||||
_velocity.x = direction.x * Speed;
|
||||
|
||||
@@ -232,7 +232,7 @@ at the end of ``_physics_process()``.
|
||||
public override void _PhysicsProcess(float delta)
|
||||
{
|
||||
// ...
|
||||
var pivot = GetNode<Spatial>("Pivot");
|
||||
var pivot = GetNode<Node3D>("Pivot");
|
||||
pivot.Rotation = new Vector3(Mathf.Pi / 6f * _velocity.y / JumpImpulse, pivot.Rotation.y, pivot.Rotation.z);
|
||||
}
|
||||
|
||||
@@ -394,7 +394,7 @@ Here's the *Player* script.
|
||||
if (direction != Vector3.Zero)
|
||||
{
|
||||
direction = direction.Normalized();
|
||||
GetNode<Spatial>("Pivot").LookAt(Translation + direction, Vector3.Up);
|
||||
GetNode<Node3D>("Pivot").LookAt(Translation + direction, Vector3.Up);
|
||||
GetNode<AnimationPlayer>("AnimationPlayer").PlaybackSpeed = 4;
|
||||
}
|
||||
else
|
||||
@@ -427,7 +427,7 @@ Here's the *Player* script.
|
||||
}
|
||||
}
|
||||
|
||||
var pivot = GetNode<Spatial>("Pivot");
|
||||
var pivot = GetNode<Node3D>("Pivot");
|
||||
pivot.Rotation = new Vector3(Mathf.Pi / 6f * _velocity.y / JumpImpulse, pivot.Rotation.y, pivot.Rotation.z);
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ opening the project, you should see an empty editor.
|
||||
.. image:: img/nodes_and_scenes_01_empty_editor.png
|
||||
|
||||
In an empty scene, the Scene dock on the left shows several options to add a
|
||||
root node quickly. "2D Scene" adds a Node2D node, "3D Scene" adds a Spatial
|
||||
root node quickly. "2D Scene" adds a Node2D node, "3D Scene" adds a Node3D
|
||||
node, and "User Interface" adds a Control node. These presets
|
||||
are here for convenience; they are not mandatory. "Other Node" lets you select any
|
||||
node to be the root node. In an empty scene, "Other Node" is equivalent to pressing
|
||||
|
||||
@@ -152,7 +152,7 @@ cover the scene with the volume as you do with ``GIProbe``:
|
||||
Setting up meshes
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
For a **MeshInstance** node to take part in the baking process, it needs to have
|
||||
For a **MeshInstance3D** node to take part in the baking process, it needs to have
|
||||
the **Use in Baked Light** property enabled.
|
||||
|
||||
.. image:: img/baked_light_use.png
|
||||
|
||||
@@ -126,7 +126,7 @@ Our level will contain these objects:
|
||||
- a desk,
|
||||
- a bookshelf.
|
||||
|
||||
Create a scene with a Spatial node as root node.
|
||||
Create a scene with a Node3D node as root node.
|
||||
|
||||
.. tip:: The default lighting of the environment doesn't provide clear shading
|
||||
at some angles. Change the display mode using **Display Overdraw** in
|
||||
@@ -182,7 +182,7 @@ spheres will cut a hole into the mattress.
|
||||
|
||||
.. image:: img/csg_pillow_hole.png
|
||||
|
||||
Try to re-parent the ``pillow`` node to the root ``Spatial`` node; the hole will
|
||||
Try to re-parent the ``pillow`` node to the root ``Node3D`` node; the hole will
|
||||
disappear.
|
||||
|
||||
.. note:: This is to illustrate the effect of CSG processing order.
|
||||
@@ -271,14 +271,14 @@ There are two ways to apply a material to a CSG node:
|
||||
|
||||
To apply triplanar mapping to a CSG node, select it, go to the Inspector, click
|
||||
the **[empty]** text next to **Material Override** (or **Material** for
|
||||
individual CSG nodes). Choose **New SpatialMaterial**. Click the newly created
|
||||
individual CSG nodes). Choose **New StandardMaterial3D**. Click the newly created
|
||||
material's icon to edit it. Unfold the **Albedo** section and load a texture
|
||||
into the **Texture** property. Now, unfold the **Uv1** section and check
|
||||
**Triplanar**. You can change the texture offset and scale on each axis by
|
||||
playing with the **Scale** and **Offset** properties just above. Higher values
|
||||
in the **Scale** property will cause the texture to repeat more often.
|
||||
|
||||
.. tip:: You can copy a SpatialMaterial to reuse it across CSG nodes. To do so,
|
||||
.. tip:: You can copy a StandardMaterial3D to reuse it across CSG nodes. To do so,
|
||||
click the dropdown arrow next to a material property in the Inspector
|
||||
and choose **Copy**. To paste it, select the node you'd like to apply
|
||||
the material onto, click the dropdown arrow next to its material
|
||||
|
||||
@@ -16,19 +16,19 @@ In 3D, math is a little more complex than in 2D, so also checking the
|
||||
developers, not mathematicians or engineers) will help pave the way for you
|
||||
to develop 3D games efficiently.
|
||||
|
||||
Spatial node
|
||||
~~~~~~~~~~~~
|
||||
Node3D node
|
||||
~~~~~~~~~~~
|
||||
|
||||
:ref:`Node2D <class_Node2D>` is the base node for 2D.
|
||||
:ref:`Control <class_Control>` is the base node for everything GUI.
|
||||
Following this reasoning, the 3D engine uses the :ref:`Spatial <class_Spatial>`
|
||||
Following this reasoning, the 3D engine uses the :ref:`Node3D <class_Node3D>`
|
||||
node for everything 3D.
|
||||
|
||||
.. image:: img/tuto_3d1.png
|
||||
|
||||
Spatial nodes have a local transform, which is relative to the parent
|
||||
Node3Ds have a local transform, which is relative to the parent
|
||||
node (as long as the parent node is also of **or inherits from** the type
|
||||
Spatial). This transform can be accessed as a 4×3
|
||||
Node3D). This transform can be accessed as a 4×3
|
||||
:ref:`Transform3D <class_Transform3D>`, or as 3 :ref:`Vector3 <class_Vector3>`
|
||||
members representing location, Euler rotation (X, Y and Z angles) and
|
||||
scale.
|
||||
@@ -56,7 +56,7 @@ entire scenes (exactly as they look in the DCC), including animation,
|
||||
skeletal rigs, blend shapes, etc.
|
||||
|
||||
The second pipeline is by importing simple .OBJ files as mesh resources,
|
||||
which can be then put inside a :ref:`MeshInstance <class_MeshInstance>`
|
||||
which can be then put inside a :ref:`MeshInstance3D <class_MeshInstance3D>`
|
||||
node for display.
|
||||
|
||||
Generated geometry
|
||||
@@ -78,7 +78,7 @@ Immediate geometry
|
||||
|
||||
If, instead, you need to generate simple geometry that
|
||||
will be updated often, Godot provides a special node,
|
||||
:ref:`ImmediateGeometry <class_ImmediateGeometry>`,
|
||||
:ref:`ImmediateMesh <class_ImmediateMesh>`,
|
||||
which provides an OpenGL 1.x style immediate-mode API to create points,
|
||||
lines, triangles, etc.
|
||||
|
||||
@@ -110,7 +110,7 @@ Environments can also be overridden in the Camera.
|
||||
~~~~~~~~~~~
|
||||
|
||||
Editing 3D scenes is done in the 3D tab. This tab can be selected
|
||||
manually, but it will be automatically enabled when a Spatial node is
|
||||
manually, but it will be automatically enabled when a Node3D node is
|
||||
selected.
|
||||
|
||||
.. image:: img/tuto_3d3.png
|
||||
@@ -193,7 +193,7 @@ Cameras
|
||||
-------
|
||||
|
||||
No matter how many objects are placed in the 3D space, nothing will be
|
||||
displayed unless a :ref:`Camera <class_Camera>` is
|
||||
displayed unless a :ref:`Camera3D <class_Camera3D>` is
|
||||
also added to the scene. Cameras can work in either orthogonal or
|
||||
perspective projections:
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
.. _doc_immediategeometry:
|
||||
.. _doc_immediatemesh:
|
||||
|
||||
Using ImmediateGeometry
|
||||
=======================
|
||||
Using ImmediateMesh
|
||||
===================
|
||||
|
||||
Unlike the SurfaceTool or ArrayMesh, :ref:`ImmediateGeometry <class_ImmediateGeometry>` is an actual
|
||||
Unlike the SurfaceTool or ArrayMesh, :ref:`ImmediateMesh <class_ImmediateMesh>` is an actual
|
||||
node. Being a node makes it quick to add to a scene and get visual output. It uses an OpenGL 1.x-style
|
||||
API like SurfaceTool, but it's actually designed to create meshes on the fly.
|
||||
|
||||
@@ -40,7 +40,7 @@ The example code below draws a single triangle.
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
extends ImmediateGeometry
|
||||
extends ImmediateMesh
|
||||
|
||||
func _process(_delta):
|
||||
# Clean up before drawing.
|
||||
|
||||
@@ -14,7 +14,7 @@ it is best to understand each one and how it can be useful in a given situation.
|
||||
arraymesh
|
||||
meshdatatool
|
||||
surfacetool
|
||||
immediategeometry
|
||||
immediatemesh
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -106,19 +106,19 @@ The SurfaceTool allows the creation of Meshes using an OpenGL 1.x immediate mode
|
||||
|
||||
For more information about the SurfaceTool, please see the :ref:`SurfaceTool tutorial <doc_surfacetool>`.
|
||||
|
||||
ImmediateGeometry
|
||||
^^^^^^^^^^^^^^^^^
|
||||
ImmediateMesh
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
ImmediateGeometry is a node that uses an immediate mode style interface (like SurfaceTool) to draw objects. The
|
||||
difference between ImmediateGeometry and the SurfaceTool is that ImmediateGeometry is a node itself that can be
|
||||
ImmediateMesh is a node that uses an immediate mode style interface (like SurfaceTool) to draw objects. The
|
||||
difference between ImmediateMesh and the SurfaceTool is that ImmediateMesh is a node itself that can be
|
||||
added to the scene tree and is drawn directly from the code, while The SurfaceTool generates a Mesh that needs to be added to
|
||||
a MeshInstance3D to be seen.
|
||||
|
||||
ImmediateGeometry is useful for prototyping because of its straightforward API, but it is slow because the geometry
|
||||
ImmediateMesh is useful for prototyping because of its straightforward API, but it is slow because the geometry
|
||||
is rebuilt every frame. It is most useful for adding simple geometry for visual debugging (e.g. by drawing lines to
|
||||
visualize physics raycasts etc.).
|
||||
|
||||
For more information about ImmediateGeometry, please see the :ref:`ImmediateGeometry tutorial <doc_immediategeometry>`.
|
||||
For more information about ImmediateMesh, please see the :ref:`ImmediateMesh tutorial <doc_immediatemesh>`.
|
||||
|
||||
Which one should I use?
|
||||
-----------------------
|
||||
@@ -130,7 +130,7 @@ Both SurfaceTool and ArrayMesh are excellent for generating static geometry (mes
|
||||
Using an ArrayMesh is slightly faster than using a SurfaceTool, but the API is a little more challenging.
|
||||
Additionally, SurfaceTool has a few quality of life methods such as ``generate_normals()`` and ``index()``.
|
||||
|
||||
ImmediateGeometry regenerates the mesh every frame, so it is much slower than ArrayMesh or SurfaceTool. However, if you
|
||||
ImmediateMesh regenerates the mesh every frame, so it is much slower than ArrayMesh or SurfaceTool. However, if you
|
||||
need the geometry to change every frame anyway, it provides a much easier interface that may even be a little faster than generating
|
||||
an ArrayMesh every frame.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Using the SurfaceTool
|
||||
=====================
|
||||
|
||||
The :ref:`SurfaceTool <class_surfacetool>` provides a useful interface for constructing geometry.
|
||||
The interface is similar to the :ref:`ImmediateGeometry <class_immediategeometry>` node. You
|
||||
The interface is similar to the :ref:`ImmediateMesh <class_ImmediateMesh>` node. You
|
||||
set each per-vertex attribute (e.g. normal, uv, color) and then when you add a vertex it
|
||||
captures the attributes.
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ This tutorial explains the parameters present in both materials.
|
||||
|
||||
There are 4 ways to add these materials to an object. A material can be added in
|
||||
the *Material* property of the mesh. It can be added in the *Material* property of
|
||||
the node using the mesh (such as a MeshInstance node), the *Material Override* property
|
||||
the node using the mesh (such as a MeshInstance3D node), the *Material Override* property
|
||||
of the node using the mesh, and the *Material Overlay*.
|
||||
|
||||
.. image:: img/add_material.png
|
||||
@@ -176,7 +176,7 @@ the object. The default is *Burley*. Other modes are also available:
|
||||
(via roughness). Works well for clay-like materials and some types of cloth.
|
||||
* **Toon:** Provides a hard cut for lighting, with smoothing affected by roughness.
|
||||
It is recommended you disable sky contribution from your environment's
|
||||
ambient light settings or disable ambient light in the spatial material
|
||||
ambient light settings or disable ambient light in the StandardMaterial3D
|
||||
to achieve a better effect.
|
||||
|
||||
.. image:: img/spatial_material6.png
|
||||
|
||||
@@ -33,8 +33,8 @@ scene to see an example of how to set up the mesh library.
|
||||
|
||||
.. image:: img/gridmap_meshlibrary1.png
|
||||
|
||||
As you can see, this scene has a :ref:`class_Spatial` node as its root, and
|
||||
a number of :ref:`class_MeshInstance` node children.
|
||||
As you can see, this scene has a :ref:`class_Node3D` node as its root, and
|
||||
a number of :ref:`class_MeshInstance3D` node children.
|
||||
|
||||
If you don't need any physics in your scene, then you're done. However, in most
|
||||
cases you'll want to assign collision bodies to the meshes.
|
||||
@@ -69,7 +69,7 @@ Like all mesh instances, MeshLibrary items can be assigned a :ref:`class_Navigat
|
||||
resource, which can be created manually, or baked as described below.
|
||||
|
||||
To create the NavigationMesh from a MeshLibrary scene export, place a
|
||||
:ref:`class_NavigationRegion3D` child node below the main MeshInstance for the GridMap
|
||||
:ref:`class_NavigationRegion3D` child node below the main MeshInstance3D for the GridMap
|
||||
item. Add a valid NavigationMesh resource to the NavigationRegion3D and some source
|
||||
geometry nodes below and bake the NavigationMesh.
|
||||
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
.. _doc_using_multi_mesh_instance:
|
||||
|
||||
Using MultiMeshInstance
|
||||
-----------------------
|
||||
Using MultiMeshInstance3D
|
||||
-------------------------
|
||||
|
||||
Introduction
|
||||
~~~~~~~~~~~~
|
||||
|
||||
In a normal scenario, you would use a :ref:`MeshInstance <class_MeshInstance>`
|
||||
In a normal scenario, you would use a :ref:`MeshInstance3D <class_MeshInstance3D>`
|
||||
node to display a 3D mesh like a human model for the main character, but in some
|
||||
cases, you would like to create multiple instances of the same mesh in a scene.
|
||||
You *could* duplicate the same node multiple times and adjust the transforms
|
||||
manually. This may be a tedious process and the result may look mechanical.
|
||||
Also, this method is not conducive to rapid iterations.
|
||||
:ref:`MultiMeshInstance <class_MultiMeshInstance>` is one of the possible
|
||||
:ref:`MultiMeshInstance3D <class_MultiMeshInstance3D>` is one of the possible
|
||||
solutions to this problem.
|
||||
|
||||
MultiMeshInstance, as the name suggests, creates multiple copies of a
|
||||
MultiMeshInstance3D, as the name suggests, creates multiple copies of a
|
||||
MeshInstance over a surface of a specific mesh. An example would be having a
|
||||
tree mesh populate a landscape mesh with trees of random scales and orientations.
|
||||
|
||||
Setting up the nodes
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The basic setup requires three nodes: the MultiMeshInstance node
|
||||
and two MeshInstance nodes.
|
||||
The basic setup requires three nodes: the MultiMeshInstance3D node
|
||||
and two MeshInstance3D nodes.
|
||||
|
||||
One node is used as the target, the surface mesh that you want to place multiple meshes
|
||||
on. In the tree example, this would be the landscape.
|
||||
@@ -31,14 +31,14 @@ on. In the tree example, this would be the landscape.
|
||||
The other node is used as the source, the mesh that you want to have duplicated.
|
||||
In the tree case, this would be the tree itself.
|
||||
|
||||
In our example, we would use a :ref:`Spatial <class_Spatial>` node as the root node of
|
||||
In our example, we would use a :ref:`Node3D <class_Node3D>` node as the root node of
|
||||
the scene. Your scene tree would look like this:
|
||||
|
||||
.. image:: img/multimesh_scene_tree.png
|
||||
|
||||
.. note:: For simplicity's sake, this tutorial uses built-in primitives.
|
||||
|
||||
Now you have everything ready. Select the MultiMeshInstance node and look at the
|
||||
Now you have everything ready. Select the MultiMeshInstance3D node and look at the
|
||||
toolbar, you should see an extra button called ``MultiMesh`` next to ``View``.
|
||||
Click it and select *Populate surface* in the dropdown menu. A new window titled
|
||||
*Populate MultiMesh* will pop up.
|
||||
|
||||
@@ -79,14 +79,14 @@ There are a few reasons this may happen:
|
||||
Say no to Euler angles
|
||||
======================
|
||||
|
||||
The result of all this is that you should **not use** the ``rotation`` property of :ref:`class_Spatial` nodes in Godot for games. It's there to be used mainly in the editor, for coherence with the 2D engine, and for simple rotations (generally just one axis, or even two in limited cases). As much as you may be tempted, don't use it.
|
||||
The result of all this is that you should **not use** the ``rotation`` property of :ref:`class_Node3D` nodes in Godot for games. It's there to be used mainly in the editor, for coherence with the 2D engine, and for simple rotations (generally just one axis, or even two in limited cases). As much as you may be tempted, don't use it.
|
||||
|
||||
Instead, there is a better way to solve your rotation problems.
|
||||
|
||||
Introducing transforms
|
||||
----------------------
|
||||
|
||||
Godot uses the :ref:`class_Transform` datatype for orientations. Each :ref:`class_Spatial` node contains a ``transform`` property which is relative to the parent's transform, if the parent is a Spatial-derived type.
|
||||
Godot uses the :ref:`class_Transform3D` datatype for orientations. Each :ref:`class_Node3D` node contains a ``transform`` property which is relative to the parent's transform, if the parent is a Node3D-derived type.
|
||||
|
||||
It is also possible to access the world coordinate transform via the ``global_transform`` property.
|
||||
|
||||
@@ -165,7 +165,7 @@ It is possible to rotate a transform, either by multiplying its basis by another
|
||||
// shortened
|
||||
transform.basis = transform.basis.Rotated(axis, rotationAmount);
|
||||
|
||||
A method in Spatial simplifies this:
|
||||
A method in Node3D simplifies this:
|
||||
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
@@ -217,7 +217,7 @@ There are two different ways to handle this. The first is to *orthonormalize* th
|
||||
|
||||
This will make all axes have ``1.0`` length again and be ``90`` degrees from each other. However, any scale applied to the transform will be lost.
|
||||
|
||||
It is recommended you not scale nodes that are going to be manipulated; scale their children nodes instead (such as MeshInstance). If you absolutely must scale the node, then re-apply it at the end:
|
||||
It is recommended you not scale nodes that are going to be manipulated; scale their children nodes instead (such as MeshInstance3D). If you absolutely must scale the node, then re-apply it at the end:
|
||||
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
@@ -367,8 +367,8 @@ Converting a rotation to quaternion is straightforward.
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
# Convert basis to quaternion, keep in mind scale is lost
|
||||
var a = Quat(transform.basis)
|
||||
var b = Quat(transform2.basis)
|
||||
var a = Quaternion(transform.basis)
|
||||
var b = Quaternion(transform2.basis)
|
||||
# Interpolate using spherical-linear interpolation (SLERP).
|
||||
var c = a.slerp(b,0.5) # find halfway point between a and b
|
||||
# Apply back
|
||||
@@ -377,14 +377,14 @@ Converting a rotation to quaternion is straightforward.
|
||||
.. code-tab:: csharp
|
||||
|
||||
// Convert basis to quaternion, keep in mind scale is lost
|
||||
var a = transform.basis.Quat();
|
||||
var b = transform2.basis.Quat();
|
||||
var a = transform.basis.Quaternion();
|
||||
var b = transform2.basis.Quaternion();
|
||||
// Interpolate using spherical-linear interpolation (SLERP).
|
||||
var c = a.Slerp(b, 0.5f); // find halfway point between a and b
|
||||
// Apply back
|
||||
transform.basis = new Basis(c);
|
||||
|
||||
The :ref:`class_Quat` type reference has more information on the datatype (it
|
||||
The :ref:`class_Quaternion` type reference has more information on the datatype (it
|
||||
can also do transform accumulation, transform points, etc., though this is used
|
||||
less often). If you interpolate or apply operations to quaternions many times,
|
||||
keep in mind they need to be eventually normalized. Otherwise, they will also
|
||||
|
||||
@@ -193,7 +193,7 @@ node with its parent. And there's currently no child of the hand node.
|
||||
With this knowledge let's try again.
|
||||
|
||||
The first step is creating an endpoint node. Any kind of node will do,
|
||||
but :ref:`Position2D <class_Position2D>` is preferred because it's
|
||||
but :ref:`Marker2D <class_Marker2D>` is preferred because it's
|
||||
visible in the editor. The endpoint node will ensure that the last bone
|
||||
has orientation.
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ difficulties in implementation, which are:
|
||||
|
||||
Sometimes materials may not be valid for exporting (e.g. has some unsupported node) or it
|
||||
is using Blender Internal Engine, only the diffuse color and a few flags (e.g. unshaded) are
|
||||
exported and form a Spatial Material.
|
||||
exported and form a StandardMaterial3D.
|
||||
|
||||
|
||||
Generate external materials
|
||||
|
||||
@@ -8,7 +8,7 @@ physics tab:
|
||||
|
||||
.. important::
|
||||
By default, a single Blender object with rigid body enabled will export as
|
||||
three nodes: a PhysicsBody, a CollisionShape, and a MeshInstance.
|
||||
three nodes: a PhysicsBody, a CollisionShape, and a MeshInstance3D.
|
||||
|
||||
Body type
|
||||
---------
|
||||
|
||||
@@ -20,11 +20,11 @@ and keep the imported resources hidden in a ``res://.import`` folder.
|
||||
This means that when trying to access imported assets through code you
|
||||
need to use the :ref:`Resource Loader<class_ResourceLoader>` as it will
|
||||
automatically take into account where the internal files are saved. If you
|
||||
try and access an imported asset using the :ref:`File <class_File>` class
|
||||
try and access an imported asset using the :ref:`FileAccess <class_FileAccess>` class
|
||||
it will work in the editor, but break in the exported project.
|
||||
|
||||
However, the :ref:`Resource Loader<class_ResourceLoader>` cannot access
|
||||
non imported files, only the :ref:`File <class_File>` class can.
|
||||
non imported files, only the :ref:`FileAccess <class_FileAccess>` class can.
|
||||
|
||||
Changing import parameters
|
||||
--------------------------
|
||||
|
||||
@@ -144,7 +144,7 @@ Nodes
|
||||
Root Type
|
||||
^^^^^^^^^
|
||||
|
||||
By default, the type of the root node in imported scenes is "Spatial", but this can be modified.
|
||||
By default, the type of the root node in imported scenes is "Node3D", but this can be modified.
|
||||
|
||||
Root Name
|
||||
^^^^^^^^^
|
||||
@@ -504,7 +504,7 @@ A mesh node with the ``-wheel`` suffix will be imported as a child to a
|
||||
Rigid Body (-rigid)
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A mesh node with the ``-rigid`` suffix will be imported as a :ref:`class_RigidBody`.
|
||||
A mesh node with the ``-rigid`` suffix will be imported as a :ref:`class_RigidBody3D`.
|
||||
|
||||
Animation loop (-loop, -cycle)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -175,7 +175,7 @@ Reverb
|
||||
|
||||
Reverb simulates rooms of different sizes. It has adjustable parameters that can
|
||||
be tweaked to obtain the sound of a specific room. Reverb is commonly outputted
|
||||
from :ref:`Areas <class_Area>`
|
||||
from :ref:`Area3Ds <class_Area3D>`
|
||||
(see :ref:`Reverb buses <doc_audio_streams_reverb_buses>`), or to apply
|
||||
a "chamber" feel to all sounds.
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ your project's features.
|
||||
further references to themselves exist. These are useful in the majority of
|
||||
cases where one needs data in a custom class.
|
||||
|
||||
- **Example:** See the :ref:`File <class_File>` object. It functions
|
||||
- **Example:** See the :ref:`FileAccess <class_FileAccess>` object. It functions
|
||||
just like a regular Object except that one need not delete it themselves.
|
||||
|
||||
- **Advantages:** same as the Object.
|
||||
|
||||
@@ -274,7 +274,7 @@ of Main. In addition, one will need a primary GUI for their game that manages
|
||||
the various menus and widgets the project needs.
|
||||
|
||||
- Node "Main" (main.gd)
|
||||
- Node2D/Spatial "World" (game_world.gd)
|
||||
- Node2D/Node3D "World" (game_world.gd)
|
||||
- Control "GUI" (gui.gd)
|
||||
|
||||
When changing levels, one can then swap out the children of the "World" node.
|
||||
@@ -319,7 +319,7 @@ own place in the hierarchy as a sibling or some other relation.
|
||||
|
||||
In some cases, one needs these separated nodes to *also* position themselves
|
||||
relative to each other. One can use the
|
||||
:ref:`RemoteTransform <class_RemoteTransform>` /
|
||||
:ref:`RemoteTransform <class_RemoteTransform3D>` /
|
||||
:ref:`RemoteTransform2D <class_RemoteTransform2D>` nodes for this purpose.
|
||||
They will allow a target node to conditionally inherit selected transform
|
||||
elements from the Remote\* node. To assign the ``target``
|
||||
@@ -372,7 +372,7 @@ own place in the hierarchy as a sibling or some other relation.
|
||||
information to their children.
|
||||
2. The **imperative** solution: Use the ``set_as_toplevel`` setter for the
|
||||
:ref:`CanvasItem <class_CanvasItem_method_set_as_toplevel>` or
|
||||
:ref:`Spatial <class_Spatial_method_set_as_toplevel>` node. This will make
|
||||
:ref:`Node3D <class_Node3D_method_set_as_toplevel>` node. This will make
|
||||
the node ignore its inherited transform.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -89,12 +89,12 @@ received input, in order:
|
||||
:ref:`Node.set_process_unhandled_input() <class_Node_method_set_process_unhandled_input>`).
|
||||
If any function consumes the event, it can call :ref:`SceneTree.set_input_as_handled() <class_SceneTree_method_set_input_as_handled>`, and the
|
||||
event will not spread any more. The unhandled input callback is ideal for full-screen gameplay events, so they are not received when a GUI is active.
|
||||
4. If no one wanted the event so far, and a :ref:`Camera <class_Camera>` is assigned
|
||||
4. If no one wanted the event so far, and a :ref:`Camera3D <class_Camera3D>` is assigned
|
||||
to the Viewport with :ref:`Object Picking <class_viewport_property_physics_object_picking>` turned on, a ray to the physics world (in the ray direction from
|
||||
the click) will be cast. (For the root viewport, this can also be enabled in :ref:`Project Settings <class_ProjectSettings_property_physics/common/enable_object_picking>`) If this ray hits an object, it will call the
|
||||
:ref:`CollisionObject._input_event() <class_CollisionObject_method__input_event>` function in the relevant
|
||||
physics object (bodies receive this callback by default, but areas do
|
||||
not. This can be configured through :ref:`Area <class_Area>` properties).
|
||||
not. This can be configured through :ref:`Area3D <class_Area3D>` properties).
|
||||
5. Finally, if the event was unhandled, it will be passed to the next
|
||||
Viewport in the tree, otherwise it will be ignored.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Introduction
|
||||
|
||||
Godot has a serialization API based on Variant. It's used for
|
||||
converting data types to an array of bytes efficiently. This API is used
|
||||
in the functions ``get_var`` and ``store_var`` of :ref:`class_File`
|
||||
in the functions ``get_var`` and ``store_var`` of :ref:`class_FileAccess`
|
||||
as well as the packet APIs for :ref:`class_PacketPeer`. This format
|
||||
is *not* used for binary scenes and resources.
|
||||
|
||||
@@ -58,13 +58,13 @@ two bytes contain flags::
|
||||
+--------+--------------------------+
|
||||
| 9 | plane |
|
||||
+--------+--------------------------+
|
||||
| 10 | quat |
|
||||
| 10 | quaternion |
|
||||
+--------+--------------------------+
|
||||
| 11 | aabb |
|
||||
+--------+--------------------------+
|
||||
| 12 | basis |
|
||||
+--------+--------------------------+
|
||||
| 13 | transform |
|
||||
| 13 | transform3d |
|
||||
+--------+--------------------------+
|
||||
| 14 | color |
|
||||
+--------+--------------------------+
|
||||
@@ -244,8 +244,8 @@ This field is padded to 4 bytes.
|
||||
| 16 | 4 | Float | Distance |
|
||||
+----------+-------+---------+---------------+
|
||||
|
||||
10: :ref:`Quat<class_quat>`
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
10: :ref:`Quaternion<class_quaternion>`
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
+----------+-------+---------+---------------+
|
||||
| Offset | Len | Type | Description |
|
||||
@@ -303,8 +303,8 @@ This field is padded to 4 bytes.
|
||||
| 36 | 4 | Float | The Z component of the Z column vector, accessed via [2][2] |
|
||||
+----------+-------+---------+---------------------------------------------------------------+
|
||||
|
||||
13: :ref:`Transform<class_transform>`
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
13: :ref:`Transform3D<class_transform3d>`
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
+----------+-------+---------+---------------------------------------------------------------+
|
||||
| Offset | Len | Type | Description |
|
||||
|
||||
@@ -341,7 +341,7 @@ Here are some important gotchas to know about when using JSON.
|
||||
JSON only offers a limited set of data types. If you have data types
|
||||
that JSON doesn't have, you will need to translate your data to and
|
||||
from types that JSON can handle. For example, some important types that JSON
|
||||
can't parse are: ``Vector2``, ``Vector3``, ``Color``, ``Rect2``, and ``Quat``.
|
||||
can't parse are: ``Vector2``, ``Vector3``, ``Color``, ``Rect2``, and ``Quaternion``.
|
||||
* **Custom logic needed for encoding/decoding:**
|
||||
If you have any custom classes that you want to store with JSON, you will
|
||||
need to write your own logic for encoding and decoding those classes.
|
||||
@@ -351,7 +351,7 @@ Binary serialization
|
||||
|
||||
:ref:`Binary serialization<doc_binary_serialization_api>` is an alternative
|
||||
approach for storing game state, and you can use it with the functions
|
||||
``get_var`` and ``store_var`` of :ref:`class_File`.
|
||||
``get_var`` and ``store_var`` of :ref:`class_FileAccess`.
|
||||
|
||||
* Binary serialization should produce smaller files than JSON.
|
||||
* Binary serialization can handle most common data types.
|
||||
|
||||
@@ -53,8 +53,8 @@ Here is example pseudo-code for going from point A to B using interpolation:
|
||||
{
|
||||
_t += delta * 0.4f;
|
||||
|
||||
Position2D a = GetNode<Position2D>("A");
|
||||
Position2D b = GetNode<Position2D>("B");
|
||||
Marker2D a = GetNode<Marker2D>("A");
|
||||
Marker2D b = GetNode<Marker2D>("B");
|
||||
Sprite2D sprite = GetNode<Sprite2D>("Sprite2D");
|
||||
|
||||
sprite.Position = a.Position.Lerp(b.Position, _t);
|
||||
@@ -94,8 +94,8 @@ Using the following pseudocode:
|
||||
{
|
||||
_t += delta;
|
||||
|
||||
Position3D p1 = GetNode<Position3D>("Position1");
|
||||
Position3D p2 = GetNode<Position3D>("Position2");
|
||||
Marker3D p1 = GetNode<Marker3D>("Position1");
|
||||
Marker3D p2 = GetNode<Marker3D>("Position2");
|
||||
CSGMesh3D monkey = GetNode<CSGMesh3D>("Monkey");
|
||||
|
||||
monkey.Transform = p1.Transform.InterpolateWith(p2.Transform, _t);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
3D Navigation Overview
|
||||
======================
|
||||
|
||||
Godot provides multiple objects, classes and servers to facilitate grid-based or mesh-based navigation and pathfinding for 2D and 3D games.
|
||||
Godot provides multiple objects, classes and servers to facilitate grid-based or mesh-based navigation and pathfinding for 2D and 3D games.
|
||||
The following section provides a quick overview over all available navigation related objects in Godot for 3D scenes and their primary use.
|
||||
|
||||
Godot provides the following objects and classes for 3D navigation:
|
||||
@@ -78,9 +78,9 @@ a NavigationAgent3D for path movement.
|
||||
|
||||
.. image:: img/nav_3d_min_setup_step1.png
|
||||
|
||||
3.) Add a new MeshInstance node as a child of the region node
|
||||
3.) Add a new MeshInstance3D node as a child of the region node
|
||||
|
||||
4.) Select the meshinstance node and add a new PlaneMesh and increase the xy size to 10.
|
||||
4.) Select the MeshInstance3D node and add a new PlaneMesh and increase the xy size to 10.
|
||||
|
||||
5.) Select the region node again and press the "Bake Navmesh" button on the top bar
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ efficient for millions of objects, but for a few thousands, GDScript should be f
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
extends MultiMeshInstance
|
||||
extends MultiMeshInstance3D
|
||||
|
||||
|
||||
func _ready():
|
||||
@@ -77,7 +77,7 @@ efficient for millions of objects, but for a few thousands, GDScript should be f
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public class YourClassName : MultiMeshInstance
|
||||
public class YourClassName : MultiMeshInstance3D
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
|
||||
@@ -66,7 +66,7 @@ For nodes, there are many functions available:
|
||||
* For Viewport, the :ref:`Viewport.get_viewport_rid() <class_Viewport_method_get_viewport_rid>`
|
||||
method will return the viewport RID in the server.
|
||||
* For 3D, the :ref:`World3D <class_World3D>` resource (obtainable in the :ref:`Viewport <class_Viewport>`
|
||||
and :ref:`Spatial <class_Spatial>` nodes)
|
||||
and :ref:`Node3D <class_Node3D>` nodes)
|
||||
contains functions to get the *RenderingServer Scenario*, and the *PhysicsServer Space*. This
|
||||
allows creating 3D objects directly with the server API and using them.
|
||||
* For 2D, the :ref:`World2D <class_World2D>` resource (obtainable in the :ref:`Viewport <class_Viewport>`
|
||||
@@ -132,7 +132,7 @@ The 3D APIs are different from the 2D ones, so the instantiation API must be use
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
extends Spatial
|
||||
extends Node3D
|
||||
|
||||
|
||||
# RenderingServer expects references to be kept around.
|
||||
@@ -193,7 +193,7 @@ and moves a :ref:`CanvasItem <class_CanvasItem>` when the body moves.
|
||||
Physics2DServer.body_set_force_integration_callback(body, self, "_body_moved", 0)
|
||||
|
||||
The 3D version should be very similar, as 2D and 3D physics servers are identical (using
|
||||
:ref:`RigidBody <class_RigidBody>` and :ref:`PhysicsServer <class_PhysicsServer>` respectively).
|
||||
:ref:`RigidBody3D <class_RigidBody3D>` and :ref:`PhysicsServer <class_PhysicsServer>` respectively).
|
||||
|
||||
Getting data from the servers
|
||||
-----------------------------
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
.. _doc_animating_thousands_of_fish:
|
||||
|
||||
Animating thousands of fish with MultiMeshInstance
|
||||
==================================================
|
||||
Animating thousands of fish with MultiMeshInstance3D
|
||||
====================================================
|
||||
|
||||
This tutorial explores a technique used in the game `ABZU <https://www.gdcvault.com/play/1024409/Creating-the-Art-of-ABZ>`_
|
||||
for rendering and animating thousands of fish using vertex animation and
|
||||
static mesh instancing.
|
||||
|
||||
In Godot, this can be accomplished with a custom :ref:`Shader <class_Shader>` and
|
||||
a :ref:`MultiMeshInstance <class_MultiMeshInstance>`. Using the following technique you
|
||||
a :ref:`MultiMeshInstance3D <class_MultiMeshInstance3D>`. Using the following technique you
|
||||
can render thousands of animated objects, even on low end hardware.
|
||||
|
||||
We will start by animating one fish. Then, we will see how to extend that animation to
|
||||
@@ -17,7 +17,7 @@ thousands of fish.
|
||||
Animating one Fish
|
||||
------------------
|
||||
|
||||
We will start with a single fish. Load your fish model into a :ref:`MeshInstance <class_MeshInstance>`
|
||||
We will start with a single fish. Load your fish model into a :ref:`MeshInstance3D <class_MeshInstance3D>`
|
||||
and add a new :ref:`ShaderMaterial <class_ShaderMaterial>`.
|
||||
|
||||
Here is the fish we will be using for the example images, you can use any fish model you like.
|
||||
@@ -181,13 +181,13 @@ find that you can create a wide variety of swim styles using these four motions.
|
||||
Making a school of fish
|
||||
-----------------------
|
||||
|
||||
Godot makes it easy to render thousands of the same object using a MultiMeshInstance node.
|
||||
Godot makes it easy to render thousands of the same object using a MultiMeshInstance3D node.
|
||||
|
||||
A MultiMeshInstance node is created and used the same way you would make a MeshInstance node.
|
||||
For this tutorial, we will name the MultiMeshInstance node ``School``, because it will contain
|
||||
A MultiMeshInstance3D node is created and used the same way you would make a MeshInstance3D node.
|
||||
For this tutorial, we will name the MultiMeshInstance3D node ``School``, because it will contain
|
||||
a school of fish.
|
||||
|
||||
Once you have a MultiMeshInstance add a :ref:`MultiMesh <class_MultiMesh>`, and to that
|
||||
Once you have a MultiMeshInstance3D add a :ref:`MultiMesh <class_MultiMesh>`, and to that
|
||||
MultiMesh add your :ref:`Mesh <class_Mesh>` with the shader from above.
|
||||
|
||||
MultiMeshes draw your Mesh with three additional per-instance properties: Transform (rotation,
|
||||
@@ -212,7 +212,7 @@ Now, set ``instance_count`` to the number of fish you want to have.
|
||||
Next we need to set the per-instance transforms.
|
||||
|
||||
There are two ways to set per-instance transforms for MultiMeshes. The first is entirely in editor
|
||||
and is described in the :ref:`MultiMeshInstance tutorial <doc_using_multi_mesh_instance>`.
|
||||
and is described in the :ref:`MultiMeshInstance3D tutorial <doc_using_multi_mesh_instance>`.
|
||||
|
||||
The second is to loop over all the instances and set their transforms in code. Below, we use GDScript
|
||||
to loop over all the instances and set their transform to a random position.
|
||||
@@ -225,7 +225,7 @@ to loop over all the instances and set their transform to a random position.
|
||||
$School.multimesh.set_instance_transform(i, position)
|
||||
|
||||
Running this script will place the fish in random positions in a box around the position of the
|
||||
MultiMeshInstance.
|
||||
MultiMeshInstance3D.
|
||||
|
||||
.. note:: If performance is an issue for you, try running the scene with GLES2 or with fewer fish.
|
||||
|
||||
@@ -268,7 +268,7 @@ custom value.
|
||||
|
||||
One problem that you will run into at this point is that the fish are animated, but they are not
|
||||
moving. You can move them by updating the per-instance transform for each fish every frame. Although
|
||||
doing so will be faster than moving thousands of MeshInstances per frame, it'll still likely be
|
||||
doing so will be faster than moving thousands of MeshInstance3Ds per frame, it'll still likely be
|
||||
slow.
|
||||
|
||||
In the next tutorial we will cover how to use :ref:`GPUParticles3D <class_GPUParticles3D>` to take advantage
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Controlling thousands of fish with Particles
|
||||
============================================
|
||||
|
||||
The problem with :ref:`MeshInstances <class_MeshInstance>` is that it is expensive to
|
||||
The problem with :ref:`MeshInstance3D <class_MeshInstance3D>` is that it is expensive to
|
||||
update their transform array. It is great for placing many static objects around the
|
||||
scene. But it is still difficult to move the objects around the scene.
|
||||
|
||||
@@ -11,7 +11,7 @@ To make each instance move in an interesting way, we will use a
|
||||
:ref:`GPUParticles3D <class_GPUParticles3D>` node. Particles take advantage of GPU acceleration
|
||||
by computing and setting the per-instance information in a :ref:`Shader <class_Shader>`.
|
||||
|
||||
.. note:: Particles are not available in GLES2, instead use :ref:`CPUParticles <class_CPUParticles>`,
|
||||
.. note:: Particles are not available in GLES2, instead use :ref:`CPUParticles3D <class_CPUParticles3D>`,
|
||||
which do the same thing as Particles, but do not benefit from GPU acceleration.
|
||||
|
||||
First create a Particles node. Then, under "Draw Passes" set the Particle's "Draw Pass 1" to your
|
||||
@@ -52,7 +52,7 @@ These functions come from the default :ref:`ParticleProcessMaterial <class_Parti
|
||||
They are used to generate a random number from each particle's ``RANDOM_SEED``.
|
||||
|
||||
A unique thing about particle shaders is that some built-in variables are saved across frames.
|
||||
``TRANSFORM``, ``COLOR``, and ``CUSTOM`` can all be accessed in the Spatial shader of the mesh, and
|
||||
``TRANSFORM``, ``COLOR``, and ``CUSTOM`` can all be accessed in the shader of the mesh, and
|
||||
also in the particle shader the next time it is run.
|
||||
|
||||
Next, setup your ``vertex`` function. Particles shaders only contain a vertex function
|
||||
|
||||
@@ -58,7 +58,7 @@ of convex shapes. For large and complex objects such as a whole level, we
|
||||
recommend using concave shapes instead.
|
||||
|
||||
You can generate one or several convex collision shapes from the editor by
|
||||
selecting a MeshInstance and using the **Mesh** menu at the top of the 3D
|
||||
selecting a MeshInstance3D and using the **Mesh** menu at the top of the 3D
|
||||
viewport. The editor exposes two generation modes:
|
||||
|
||||
- **Create Single Convex Collision Sibling** uses the Quickhull algorithm. It
|
||||
@@ -97,7 +97,7 @@ have an actual "volume". You can place objects both *outside* of the shape as
|
||||
well as *inside*.
|
||||
|
||||
You can generate a concave collision shape from the editor by selecting a
|
||||
MeshInstance and using the **Mesh** menu at the top of the 3D viewport. The
|
||||
MeshInstance3D and using the **Mesh** menu at the top of the 3D viewport. The
|
||||
editor exposes two options:
|
||||
|
||||
- **Create Trimesh Static Body** is a convenient option. It creates a StaticBody
|
||||
|
||||
@@ -28,7 +28,7 @@ In the physics world, Godot stores all the low level collision and
|
||||
physics information in a *space*. The current 2d space (for 2D Physics)
|
||||
can be obtained by accessing
|
||||
:ref:`CanvasItem.get_world_2d().space <class_CanvasItem_method_get_world_2d>`.
|
||||
For 3D, it's :ref:`Spatial.get_world().space <class_Spatial_method_get_world>`.
|
||||
For 3D, it's :ref:`Node3D.get_world().space <class_Node3D_method_get_world>`.
|
||||
|
||||
The resulting space :ref:`RID <class_RID>` can be used in
|
||||
:ref:`PhysicsServer <class_PhysicsServer>` and
|
||||
@@ -232,8 +232,8 @@ picking. There is not much need to do this because
|
||||
has an "input_event" signal that will let you know when it was clicked,
|
||||
but in case there is any desire to do it manually, here's how.
|
||||
|
||||
To cast a ray from the screen, you need a :ref:`Camera <class_Camera>`
|
||||
node. A ``Camera`` can be in two projection modes: perspective and
|
||||
To cast a ray from the screen, you need a :ref:`Camera3D <class_Camera3D>`
|
||||
node. A ``Camera3D`` can be in two projection modes: perspective and
|
||||
orthogonal. Because of this, both the ray origin and direction must be
|
||||
obtained. This is because ``origin`` changes in orthogonal mode, while
|
||||
``normal`` changes in perspective mode:
|
||||
@@ -249,9 +249,9 @@ To obtain it using a camera, the following code can be used:
|
||||
|
||||
func _input(event):
|
||||
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
|
||||
var camera = $Camera
|
||||
var from = camera.project_ray_origin(event.position)
|
||||
var to = from + camera.project_ray_normal(event.position) * RAY_LENGTH
|
||||
var camera3d = $Camera3D
|
||||
var from = camera3d.project_ray_origin(event.position)
|
||||
var to = from + camera3d.project_ray_normal(event.position) * RAY_LENGTH
|
||||
|
||||
.. code-tab:: csharp
|
||||
|
||||
@@ -261,9 +261,9 @@ To obtain it using a camera, the following code can be used:
|
||||
{
|
||||
if (@event is InputEventMouseButton eventMouseButton && eventMouseButton.Pressed && eventMouseButton.ButtonIndex == 1)
|
||||
{
|
||||
var camera = GetNode<Camera>("Camera");
|
||||
var from = camera.ProjectRayOrigin(eventMouseButton.Position);
|
||||
var to = from + camera.ProjectRayNormal(eventMouseButton.Position) * RayLength;
|
||||
var camera3d = GetNode<Camera3D>("Camera3D");
|
||||
var from = camera3d.ProjectRayOrigin(eventMouseButton.Position);
|
||||
var to = from + camera3d.ProjectRayNormal(eventMouseButton.Position) * RayLength;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@ How to control a rigid body
|
||||
A rigid body's behavior can be altered by setting its properties, such as mass and weight.
|
||||
A physics material needs to be added to the rigid body to adjust its friction and bounce,
|
||||
and set if it's absorbent and/or rough. These properties can be set in the Inspector or via code.
|
||||
See :ref:`RigidBody <class_RigidBody>` and :ref:`PhysicsMaterial <class_PhysicsMaterial>` for
|
||||
See :ref:`RigidBody3D <class_RigidBody3D>` and :ref:`PhysicsMaterial <class_PhysicsMaterial>` for
|
||||
the full list of properties and their effects.
|
||||
|
||||
There are several ways to control a rigid body's movement, depending on your desired application.
|
||||
|
||||
If you only need to place a rigid body once, for example to set its initial location, you can use the methods provided by the :ref:`Spatial <class_Spatial>` node, such as ``set_global_transform()`` or ``look_at()``. However, these methods cannot be called every frame or the physics engine will not be able to correctly simulate the body's state.
|
||||
If you only need to place a rigid body once, for example to set its initial location, you can use the methods provided by the :ref:`Node3D <class_Node3D>` node, such as ``set_global_transform()`` or ``look_at()``. However, these methods cannot be called every frame or the physics engine will not be able to correctly simulate the body's state.
|
||||
As an example, consider a rigid body that you want to rotate so that it points towards another object. A common mistake when implementing this kind of behavior is to use ``look_at()`` every frame, which breaks the physics simulation. Below, we'll demonstrate how to implement this correctly.
|
||||
|
||||
The fact that you can't use ``set_global_transform()`` or ``look_at()`` methods doesn't mean that you can't have full control of a rigid body. Instead, you can control it by using the ``_integrate_forces()`` callback. In this method, you can add *forces*, apply *impulses*, or set the *velocity* in order to achieve any movement you desire.
|
||||
@@ -28,7 +28,7 @@ The fact that you can't use ``set_global_transform()`` or ``look_at()`` methods
|
||||
The "look at" method
|
||||
--------------------
|
||||
|
||||
As described above, using the Spatial node's ``look_at()`` method can't be used each frame to follow a target.
|
||||
As described above, using the Node3D's ``look_at()`` method can't be used each frame to follow a target.
|
||||
Here is a custom ``look_at()`` method that will work reliably with rigid bodies:
|
||||
|
||||
.. tabs::
|
||||
@@ -45,7 +45,7 @@ Here is a custom ``look_at()`` method that will work reliably with rigid bodies:
|
||||
state.angular_velocity = up_dir * (rotation_angle / state.step)
|
||||
|
||||
func _integrate_forces(state):
|
||||
var target_position = $my_target_spatial_node.global_transform.origin
|
||||
var target_position = $my_target_node3d_node.global_transform.origin
|
||||
look_follow(state, global_transform, target_position)
|
||||
|
||||
.. code-tab:: csharp
|
||||
@@ -64,7 +64,7 @@ Here is a custom ``look_at()`` method that will work reliably with rigid bodies:
|
||||
|
||||
public override void _IntegrateForces(PhysicsDirectBodyState state)
|
||||
{
|
||||
var targetPosition = GetNode<Spatial>("my_target_spatial_node").GetGlobalTransform().origin;
|
||||
var targetPosition = GetNode<Node3D>("my_target_node3d_node").GetGlobalTransform().origin;
|
||||
LookFollow(state, GetGlobalTransform(), targetPosition);
|
||||
}
|
||||
}
|
||||
@@ -72,4 +72,4 @@ Here is a custom ``look_at()`` method that will work reliably with rigid bodies:
|
||||
|
||||
This method uses the rigid body's ``angular_velocity`` property to rotate the body. It first calculates the difference between the current and desired angle and then adds the velocity needed to rotate by that amount in one frame's time.
|
||||
|
||||
.. note:: This script will not work with rigid bodies in *character mode* because then, the body's rotation is locked. In that case, you would have to rotate the attached mesh node instead using the standard Spatial methods.
|
||||
.. note:: This script will not work with rigid bodies in *character mode* because then, the body's rotation is locked. In that case, you would have to rotate the attached mesh node instead using the standard Node3D methods.
|
||||
|
||||
@@ -9,11 +9,11 @@ This can for example be used to simulate cloth or to create more realistic chara
|
||||
Basic set-up
|
||||
~~~~~~~~~~~~
|
||||
|
||||
A :ref:`SoftBody <class_SoftBody>` node is used for soft body simulations.
|
||||
A :ref:`SoftBody3D <class_SoftBody3D>` node is used for soft body simulations.
|
||||
|
||||
We will create a bouncy cube to demonstrate the setup of a soft body.
|
||||
|
||||
Create a new scene with a ``Spatial`` node as root. Then, create a ``Softbody`` node. Add a ``CubeMesh`` in the ``mesh`` property of the node in the inspector and increase the subdivision of the mesh for simulation.
|
||||
Create a new scene with a ``Node3D`` node as root. Then, create a ``Softbody`` node. Add a ``CubeMesh`` in the ``mesh`` property of the node in the inspector and increase the subdivision of the mesh for simulation.
|
||||
|
||||
.. image:: img/softbody_cube.png
|
||||
|
||||
|
||||
@@ -342,7 +342,7 @@ uses the mouse pointer. Here is the code for the Player, using ``move_and_slide(
|
||||
shoot()
|
||||
|
||||
func shoot():
|
||||
# "Muzzle" is a Position2D placed at the barrel of the gun.
|
||||
# "Muzzle" is a Marker2D placed at the barrel of the gun.
|
||||
var b = Bullet.instance()
|
||||
b.start($Muzzle.global_position, rotation)
|
||||
get_parent().add_child(b)
|
||||
@@ -386,7 +386,7 @@ uses the mouse pointer. Here is the code for the Player, using ``move_and_slide(
|
||||
|
||||
public void Shoot()
|
||||
{
|
||||
// "Muzzle" is a Position2D placed at the barrel of the gun
|
||||
// "Muzzle" is a Marker2D placed at the barrel of the gun
|
||||
var b = (Bullet)_bullet.Instance();
|
||||
b.Start(GetNode<Node2D>("Muzzle").GlobalPosition, Rotation);
|
||||
GetParent().AddChild(b);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
.. _doc_spatial_gizmo_plugins:
|
||||
.. _doc_3d_gizmo_plugins:
|
||||
|
||||
Spatial gizmo plugins
|
||||
=====================
|
||||
3D gizmo plugins
|
||||
================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Spatial gizmo plugins are used by the editor and custom plugins to define the
|
||||
gizmos attached to any kind of Spatial node.
|
||||
3D gizmo plugins are used by the editor and custom plugins to define the
|
||||
gizmos attached to any kind of Node3D node.
|
||||
|
||||
This tutorial shows the two main approaches to defining your own custom
|
||||
gizmos. The first option works well for simple gizmos and creates less clutter in
|
||||
@@ -16,11 +16,11 @@ your plugin structure, and the second one will let you store some per-gizmo data
|
||||
.. note:: This tutorial assumes you already know how to make generic plugins. If
|
||||
in doubt, refer to the :ref:`doc_making_plugins` page.
|
||||
|
||||
The EditorSpatialGizmoPlugin
|
||||
----------------------------
|
||||
The EditorNode3DGizmoPlugin
|
||||
---------------------------
|
||||
|
||||
Regardless of the approach we choose, we will need to create a new
|
||||
:ref:`EditorSpatialGizmoPlugin <class_EditorSpatialGizmoPlugin>`. This will allow
|
||||
:ref:`EditorNode3DGizmoPlugin <class_EditorNode3DGizmoPlugin>`. This will allow
|
||||
us to set a name for the new gizmo type and define other behaviors such as whether
|
||||
the gizmo can be hidden or not.
|
||||
|
||||
@@ -29,7 +29,7 @@ This would be a basic setup:
|
||||
::
|
||||
|
||||
# MyCustomGizmoPlugin.gd
|
||||
extends EditorSpatialGizmoPlugin
|
||||
extends EditorNode3DGizmoPlugin
|
||||
|
||||
|
||||
func get_name():
|
||||
@@ -49,14 +49,14 @@ This would be a basic setup:
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
add_spatial_gizmo_plugin(gizmo_plugin)
|
||||
add_node3d_gizmo_plugin(gizmo_plugin)
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
remove_spatial_gizmo_plugin(gizmo_plugin)
|
||||
remove_node3d_gizmo_plugin(gizmo_plugin)
|
||||
|
||||
|
||||
For simple gizmos, inheriting :ref:`EditorSpatialGizmoPlugin <class_EditorSpatialGizmoPlugin>`
|
||||
For simple gizmos, inheriting :ref:`EditorNode3DGizmoPlugin <class_EditorNode3DGizmoPlugin>`
|
||||
is enough. If you want to store some per-gizmo data or you are porting a Godot 3.0 gizmo
|
||||
to 3.1+, you should go with the second approach.
|
||||
|
||||
@@ -64,21 +64,21 @@ to 3.1+, you should go with the second approach.
|
||||
Simple approach
|
||||
---------------
|
||||
|
||||
The first step is to, in our custom gizmo plugin, override the :ref:`has_gizmo()<class_EditorSpatialGizmoPlugin_method_has_gizmo>`
|
||||
method so that it returns ``true`` when the spatial parameter is of our target type.
|
||||
The first step is to, in our custom gizmo plugin, override the :ref:`_has_gizmo()<class_EditorNode3DGizmoPlugin_method__has_gizmo>`
|
||||
method so that it returns ``true`` when the node parameter is of our target type.
|
||||
|
||||
::
|
||||
|
||||
# ...
|
||||
|
||||
|
||||
func has_gizmo(spatial):
|
||||
return spatial is MyCustomSpatial
|
||||
func _has_gizmo(node):
|
||||
return node is MyCustomNode3D
|
||||
|
||||
|
||||
# ...
|
||||
|
||||
Then we can override methods like :ref:`redraw()<class_EditorSpatialGizmoPlugin_method_redraw>`
|
||||
Then we can override methods like :ref:`_redraw()<class_EditorNode3DGizmoPlugin_method__redraw>`
|
||||
or all the handle related ones.
|
||||
|
||||
::
|
||||
@@ -94,17 +94,17 @@ or all the handle related ones.
|
||||
func redraw(gizmo):
|
||||
gizmo.clear()
|
||||
|
||||
var spatial = gizmo.get_spatial_node()
|
||||
var node3d = gizmo.get_node3d()
|
||||
|
||||
var lines = PackedVector3Array()
|
||||
|
||||
lines.push_back(Vector3(0, 1, 0))
|
||||
lines.push_back(Vector3(0, spatial.my_custom_value, 0))
|
||||
lines.push_back(Vector3(0, node3d.my_custom_value, 0))
|
||||
|
||||
var handles = PackedVector3Array()
|
||||
|
||||
handles.push_back(Vector3(0, 1, 0))
|
||||
handles.push_back(Vector3(0, spatial.my_custom_value, 0))
|
||||
handles.push_back(Vector3(0, node3d.my_custom_value, 0))
|
||||
|
||||
gizmo.add_lines(lines, get_material("main", gizmo), false)
|
||||
gizmo.add_handles(handles, get_material("handles", gizmo))
|
||||
@@ -113,7 +113,7 @@ or all the handle related ones.
|
||||
# ...
|
||||
|
||||
Note that we created a material in the `_init` method, and retrieved it in the `redraw`
|
||||
method using :ref:`get_material()<class_EditorSpatialGizmoPlugin_method_get_material>`. This
|
||||
method using :ref:`get_material()<class_EditorNode3DGizmoPlugin_method_get_material>`. This
|
||||
method retrieves one of the material's variants depending on the state of the gizmo
|
||||
(selected and/or editable).
|
||||
|
||||
@@ -121,10 +121,10 @@ So the final plugin would look somewhat like this:
|
||||
|
||||
::
|
||||
|
||||
extends EditorSpatialGizmoPlugin
|
||||
extends EditorNode3DGizmoPlugin
|
||||
|
||||
|
||||
const MyCustomSpatial = preload("res://addons/my-addon/MyCustomSpatial.gd")
|
||||
const MyCustomNode3D = preload("res://addons/my-addon/MyCustomNode3D.gd")
|
||||
|
||||
|
||||
func _init():
|
||||
@@ -132,54 +132,54 @@ So the final plugin would look somewhat like this:
|
||||
create_handle_material("handles")
|
||||
|
||||
|
||||
func has_gizmo(spatial):
|
||||
return spatial is MyCustomSpatial
|
||||
func _has_gizmo(node):
|
||||
return node is MyCustomNode3D
|
||||
|
||||
|
||||
func redraw(gizmo):
|
||||
gizmo.clear()
|
||||
|
||||
var spatial = gizmo.get_spatial_node()
|
||||
var node3d = gizmo.get_node3d()
|
||||
|
||||
var lines = PackedVector3Array()
|
||||
|
||||
lines.push_back(Vector3(0, 1, 0))
|
||||
lines.push_back(Vector3(0, spatial.my_custom_value, 0))
|
||||
lines.push_back(Vector3(0, node3d.my_custom_value, 0))
|
||||
|
||||
var handles = PackedVector3Array()
|
||||
|
||||
handles.push_back(Vector3(0, 1, 0))
|
||||
handles.push_back(Vector3(0, spatial.my_custom_value, 0))
|
||||
handles.push_back(Vector3(0, node3d.my_custom_value, 0))
|
||||
|
||||
gizmo.add_lines(lines, get_material("main", gizmo), false)
|
||||
gizmo.add_handles(handles, get_material("handles", gizmo))
|
||||
|
||||
|
||||
# You should implement the rest of handle-related callbacks
|
||||
# (get_handle_name(), get_handle_value(), commit_handle()...).
|
||||
# (_get_handle_name(), _get_handle_value(), _commit_handle(), ...).
|
||||
|
||||
Note that we just added some handles in the redraw method, but we still need to implement
|
||||
the rest of handle-related callbacks in :ref:`EditorSpatialGizmoPlugin <class_EditorSpatialGizmoPlugin>`
|
||||
the rest of handle-related callbacks in :ref:`EditorNode3DGizmoPlugin <class_EditorNode3DGizmoPlugin>`
|
||||
to get properly working handles.
|
||||
|
||||
Alternative approach
|
||||
--------------------
|
||||
|
||||
In some cases we want to provide our own implementation of :ref:`EditorSpatialGizmo<class_EditorSpatialGizmo>`,
|
||||
In some cases we want to provide our own implementation of :ref:`EditorNode3DGizmo<class_EditorNode3DGizmo>`,
|
||||
maybe because we want to have some state stored in each gizmo or because we are porting
|
||||
an old gizmo plugin and we don't want to go through the rewriting process.
|
||||
|
||||
In these cases all we need to do is, in our new gizmo plugin, override
|
||||
:ref:`create_gizmo()<class_EditorSpatialGizmoPlugin_method_create_gizmo>`, so it returns our custom gizmo implementation
|
||||
for the Spatial nodes we want to target.
|
||||
:ref:`_create_gizmo()<class_EditorNode3DGizmoPlugin_method__create_gizmo>`, so it returns our custom gizmo implementation
|
||||
for the Node3D nodes we want to target.
|
||||
|
||||
::
|
||||
|
||||
# MyCustomGizmoPlugin.gd
|
||||
extends EditorSpatialGizmoPlugin
|
||||
extends EditorNode3DGizmoPlugin
|
||||
|
||||
|
||||
const MyCustomSpatial = preload("res://addons/my-addon/MyCustomSpatial.gd")
|
||||
const MyCustomNode3D = preload("res://addons/my-addon/MyCustomNode3D.gd")
|
||||
const MyCustomGizmo = preload("res://addons/my-addon/MyCustomGizmo.gd")
|
||||
|
||||
|
||||
@@ -188,19 +188,19 @@ for the Spatial nodes we want to target.
|
||||
create_handle_material("handles")
|
||||
|
||||
|
||||
func create_gizmo(spatial):
|
||||
if spatial is MyCustomSpatial:
|
||||
func _create_gizmo(node):
|
||||
if node is MyCustomNode3D:
|
||||
return MyCustomGizmo.new()
|
||||
else:
|
||||
return null
|
||||
|
||||
This way all the gizmo logic and drawing methods can be implemented in a new class extending
|
||||
:ref:`EditorSpatialGizmo<class_EditorSpatialGizmo>`, like so:
|
||||
:ref:`EditorNode3DGizmo<class_EditorNode3DGizmo>`, like so:
|
||||
|
||||
::
|
||||
|
||||
# MyCustomGizmo.gd
|
||||
extends EditorSpatialGizmo
|
||||
extends EditorNode3DGizmo
|
||||
|
||||
|
||||
# You can store data in the gizmo itself (more useful when working with handles).
|
||||
@@ -210,17 +210,17 @@ This way all the gizmo logic and drawing methods can be implemented in a new cla
|
||||
func redraw():
|
||||
clear()
|
||||
|
||||
var spatial = get_spatial_node()
|
||||
var node3d = get_node3d()
|
||||
|
||||
var lines = PackedVector3Array()
|
||||
|
||||
lines.push_back(Vector3(0, 1, 0))
|
||||
lines.push_back(Vector3(gizmo_size, spatial.my_custom_value, 0))
|
||||
lines.push_back(Vector3(gizmo_size, node3d.my_custom_value, 0))
|
||||
|
||||
var handles = PackedVector3Array()
|
||||
|
||||
handles.push_back(Vector3(0, 1, 0))
|
||||
handles.push_back(Vector3(gizmo_size, spatial.my_custom_value, 0))
|
||||
handles.push_back(Vector3(gizmo_size, node3d.my_custom_value, 0))
|
||||
|
||||
var material = get_plugin().get_material("main", self)
|
||||
add_lines(lines, material, false)
|
||||
@@ -230,8 +230,8 @@ This way all the gizmo logic and drawing methods can be implemented in a new cla
|
||||
|
||||
|
||||
# You should implement the rest of handle-related callbacks
|
||||
# (get_handle_name(), get_handle_value(), commit_handle()...).
|
||||
# (_get_handle_name(), _get_handle_value(), _commit_handle(), ...).
|
||||
|
||||
Note that we just added some handles in the redraw method, but we still need to implement
|
||||
the rest of handle-related callbacks in :ref:`EditorSpatialGizmo<class_EditorSpatialGizmo>`
|
||||
the rest of handle-related callbacks in :ref:`EditorNode3DGizmo<class_EditorNode3DGizmo>`
|
||||
to get properly working handles.
|
||||
@@ -302,7 +302,7 @@ method. Our sample code is a bit long, so let's split in a few parts:
|
||||
file.close()
|
||||
|
||||
The first part of our import method opens and reads the source file. We use the
|
||||
:ref:`File <class_File>` class to do that, passing the ``source_file``
|
||||
:ref:`FileAccess <class_FileAccess>` class to do that, passing the ``source_file``
|
||||
parameter which is provided by the editor.
|
||||
|
||||
If there's an error when opening the file, we return it to let the editor know
|
||||
@@ -410,7 +410,7 @@ system is scanned, making the custom resource appear on the FileSystem dock. If
|
||||
you select it and focus the Import dock, you can see the only option to select
|
||||
there.
|
||||
|
||||
Create a MeshInstance node in the scene, and for its Mesh property set up a new
|
||||
Create a MeshInstance3D node in the scene, and for its Mesh property set up a new
|
||||
SphereMesh. Unfold the Material section in the Inspector and then drag the file
|
||||
from the FileSystem dock to the material property. The object will update in the
|
||||
viewport with the blue color of the imported material.
|
||||
|
||||
@@ -9,6 +9,6 @@ Editor plugins
|
||||
making_plugins
|
||||
making_main_screen_plugins
|
||||
import_plugins
|
||||
spatial_gizmos
|
||||
3d_gizmos
|
||||
inspector_plugins
|
||||
visual_shader_plugins
|
||||
|
||||
@@ -300,7 +300,7 @@ If you are using ``@tool``:
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
func _ready():
|
||||
var node = Spatial.new()
|
||||
var node = Node3D.new()
|
||||
add_child(node) # Parent could be any node in the scene
|
||||
|
||||
# The line below is required to make the node visible in the Scene tree dock
|
||||
@@ -311,7 +311,7 @@ If you are using ``@tool``:
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
var node = new Spatial();
|
||||
var node = new Node3D();
|
||||
AddChild(node); // Parent could be any node in the scene
|
||||
|
||||
// The line below is required to make the node visible in the Scene tree dock
|
||||
@@ -327,7 +327,7 @@ If you are using :ref:`EditorScript<class_EditorScript>`:
|
||||
func _run():
|
||||
# `parent` could be any node in the scene.
|
||||
var parent = get_scene().find_node("Parent")
|
||||
var node = Spatial.new()
|
||||
var node = Node3D.new()
|
||||
parent.add_child(node)
|
||||
|
||||
# The line below is required to make the node visible in the Scene tree dock
|
||||
@@ -340,7 +340,7 @@ If you are using :ref:`EditorScript<class_EditorScript>`:
|
||||
{
|
||||
// `parent` could be any node in the scene.
|
||||
var parent = GetScene().FindNode("Parent");
|
||||
var node = new Spatial();
|
||||
var node = new Node3D();
|
||||
parent.AddChild(node);
|
||||
|
||||
// The line below is required to make the node visible in the Scene tree dock
|
||||
|
||||
@@ -15,7 +15,7 @@ Particles
|
||||
---------
|
||||
|
||||
GLES2 cannot use the :ref:`GPUParticles3D <class_GPUParticles3D>` or :ref:`GPUParticles2D <class_GPUParticles2D>` nodes
|
||||
as they require advanced GPU features. Instead, use :ref:`CPUParticles <class_CPUParticles>` or
|
||||
as they require advanced GPU features. Instead, use :ref:`CPUParticles3D <class_CPUParticles3D>` or
|
||||
:ref:`CPUParticles2D <class_CPUParticles2D>`, which provides a similar interface to a
|
||||
:ref:`ParticleProcessMaterial <class_ParticleProcessMaterial>`.
|
||||
|
||||
@@ -100,17 +100,17 @@ can only use the first six levels of glow; the seventh one won't do anything.
|
||||
GIProbes
|
||||
--------
|
||||
|
||||
.. FIXME: Removed reference to class_BakedLightmap in master/4.0 version to
|
||||
.. FIXME: Removed references to no longer existing classes in master/4.0 version to
|
||||
silence warning, but the whole page will likely end up rewritten or removed
|
||||
in 4.0.
|
||||
|
||||
:ref:`GIProbes <class_GIProbe>` do not work in GLES2. Instead use Baked Lightmaps.
|
||||
GIProbes do not work in GLES2. Instead use Baked Lightmaps.
|
||||
For a description of how baked lightmaps work see the :ref:`Baked Lightmaps tutorial <doc_baked_lightmaps>`.
|
||||
|
||||
Contact shadows
|
||||
---------------
|
||||
|
||||
The ``shadow_contact`` property of :ref:`Lights <class_Light>` is not supported in GLES2 and so does nothing.
|
||||
The ``shadow_contact`` property of lights is not supported in GLES2 and so does nothing.
|
||||
|
||||
Light performance
|
||||
-----------------
|
||||
|
||||
@@ -108,7 +108,7 @@ Worlds
|
||||
|
||||
For 3D, a :ref:`Viewport <class_Viewport>` will contain a :ref:`World3D <class_World3D>`. This
|
||||
is basically the universe that links physics and rendering together.
|
||||
Spatial-based nodes will register using the :ref:`World3D <class_World3D>` of the closest :ref:`Viewport <class_Viewport>`.
|
||||
Node3D-based nodes will register using the :ref:`World3D <class_World3D>` of the closest :ref:`Viewport <class_Viewport>`.
|
||||
By default, newly created :ref:`Viewports <class_Viewport>` do not contain a :ref:`World3D <class_World3D>` but
|
||||
use the same as their parent :ref:`Viewport <class_Viewport>` (the root :ref:`Viewport <class_Viewport>` always contains a
|
||||
:ref:`World3D <class_World3D>`, which is the one objects are rendered to by default). A :ref:`World3D <class_World3D>` can
|
||||
|
||||
@@ -275,12 +275,12 @@ GDScript C#
|
||||
``get_area()`` ``Area``
|
||||
================ ==================================================================
|
||||
|
||||
Quat
|
||||
----
|
||||
Quaternion
|
||||
----------
|
||||
|
||||
Structs cannot have parameterless constructors in C#. Therefore, ``new Quat()``
|
||||
Structs cannot have parameterless constructors in C#. Therefore, ``new Quaternion()``
|
||||
initializes all primitive members to their default value.
|
||||
Please use ``Quat.Identity`` for the equivalent of ``Quat()`` in GDScript and C++.
|
||||
Please use ``Quaternion.Identity`` for the equivalent of ``Quaternion()`` in GDScript and C++.
|
||||
|
||||
The following methods were converted to a property with a different name:
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Exporting is done by using the ``[Export]`` attribute.
|
||||
|
||||
.. code-block:: csharp
|
||||
|
||||
public class ExportExample : Spatial
|
||||
public class ExportExample : Node3D
|
||||
{
|
||||
[Export]
|
||||
private int Number = 5;
|
||||
|
||||
@@ -561,8 +561,8 @@ in a 3D grid.
|
||||
3D Plane type in normalized form that contains a ``normal`` vector field
|
||||
and a ``d`` scalar distance.
|
||||
|
||||
:ref:`Quat <class_Quat>`
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
:ref:`Quaternion <class_Quaternion>`
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Quaternion is a datatype used for representing a 3D rotation. It's
|
||||
useful for interpolating rotations.
|
||||
@@ -1686,7 +1686,7 @@ to. To create custom signals for a class, use the ``signal`` keyword.
|
||||
Game Programming Patterns ebook.
|
||||
|
||||
You can connect these signals to methods the same way you connect built-in
|
||||
signals of nodes like :ref:`class_Button` or :ref:`class_RigidBody`.
|
||||
signals of nodes like :ref:`class_Button` or :ref:`class_RigidBody3D`.
|
||||
|
||||
In the example below, we connect the ``health_depleted`` signal from a
|
||||
``Character`` node to a ``Game`` node. When the ``Character`` node emits the
|
||||
|
||||
@@ -164,7 +164,7 @@ memory management from the Reference type.
|
||||
This comes with many distinct advantages over alternative data
|
||||
structures, such as JSON, CSV, or custom TXT files. Users can only import these
|
||||
assets as a :ref:`Dictionary <class_Dictionary>` (JSON) or as a
|
||||
:ref:`File <class_File>` to parse. What sets Resources apart is their
|
||||
:ref:`FileAccess <class_FileAccess>` to parse. What sets Resources apart is their
|
||||
inheritance of :ref:`Object <class_Object>`, :ref:`RefCounted <class_RefCounted>`,
|
||||
and :ref:`Resource <class_Resource>` features:
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ generally and, in particular, with the methods outlined in the :ref:`custom post
|
||||
In the previous post-processing tutorial, we rendered the scene to a :ref:`Viewport <class_Viewport>`
|
||||
and then rendered the Viewport in a :ref:`SubViewportContainer <class_SubViewportContainer>`
|
||||
to the main scene. One limitation of this method is that we could not access the
|
||||
depth buffer because the depth buffer is only available in spatial shaders and
|
||||
depth buffer because the depth buffer is only available in shaders and
|
||||
Viewports do not maintain depth information.
|
||||
|
||||
Full screen quad
|
||||
@@ -27,13 +27,13 @@ two main drawbacks of using a Viewport:
|
||||
1. The depth buffer cannot be accessed
|
||||
2. The effect of the post-processing shader is not visible in the editor
|
||||
|
||||
To get around the limitation on using the depth buffer, use a :ref:`MeshInstance <class_MeshInstance>`
|
||||
with a :ref:`QuadMesh <class_QuadMesh>` primitive. This allows us to use a spatial
|
||||
To get around the limitation on using the depth buffer, use a :ref:`MeshInstance3D <class_MeshInstance3D>`
|
||||
with a :ref:`QuadMesh <class_QuadMesh>` primitive. This allows us to use a
|
||||
shader and to access the depth texture of the scene. Next, use a vertex shader
|
||||
to make the quad cover the screen at all times so that the post-processing
|
||||
effect will be applied at all times, including in the editor.
|
||||
|
||||
First, create a new MeshInstance and set its mesh to a QuadMesh. This creates a quad
|
||||
First, create a new MeshInstance3D and set its mesh to a QuadMesh. This creates a quad
|
||||
centered at position ``(0, 0, 0)`` with a width and height of ``1``. Set the width
|
||||
and height to ``2``. Right now, the quad occupies a position in world space at the
|
||||
origin; however, we want it to move with the camera so that it always covers the
|
||||
@@ -156,15 +156,15 @@ screen quad. The reason for this is explained `here <https://michaldrobot.com/20
|
||||
However, the benefit is quite small and only beneficial when running especially
|
||||
complex fragment shaders.
|
||||
|
||||
Set the Mesh in the MeshInstance to an :ref:`ArrayMesh <class_ArrayMesh>`. An
|
||||
Set the Mesh in the MeshInstance3D to an :ref:`ArrayMesh <class_ArrayMesh>`. An
|
||||
ArrayMesh is a tool that allows you to easily construct a Mesh from Arrays for
|
||||
vertices, normals, colors, etc.
|
||||
|
||||
Now, attach a script to the MeshInstance and use the following code:
|
||||
Now, attach a script to the MeshInstance3D and use the following code:
|
||||
|
||||
::
|
||||
|
||||
extends MeshInstance
|
||||
extends MeshInstance3D
|
||||
|
||||
func _ready():
|
||||
# Create a single triangle out of vertices:
|
||||
@@ -194,4 +194,4 @@ Assign the same vertex shader from above and everything should look exactly the
|
||||
The one drawback to using an ArrayMesh over using a QuadMesh is that the ArrayMesh
|
||||
is not visible in the editor because the triangle is not constructed until the scene
|
||||
is run. To get around that, construct a single triangle Mesh in a modelling program
|
||||
and use that in the MeshInstance instead.
|
||||
and use that in the MeshInstance3D instead.
|
||||
|
||||
@@ -21,7 +21,7 @@ shaders can build on themselves each run, unlike other shaders that discard the
|
||||
data they have calculated once they draw to the frame buffer.
|
||||
|
||||
.. note:: Particle shaders are only available in the GLES3 backend. If you need
|
||||
particles in GLES2, use :ref:`CPUParticles <class_CPUParticles>`.
|
||||
particles in GLES2, use :ref:`CPUParticles3D <class_CPUParticles3D>`.
|
||||
|
||||
Render modes
|
||||
^^^^^^^^^^^^
|
||||
|
||||
@@ -15,8 +15,8 @@ of making a procedural planet like the one below:
|
||||
.. note:: This tutorial does not cover how to code a dynamic atmosphere like the one this planet has.
|
||||
|
||||
This tutorial assumes you are familiar with how to set up a basic scene including:
|
||||
a :ref:`Camera <class_Camera>`, a :ref:`light source <class_OmniLight>`, a
|
||||
:ref:`Mesh Instance <class_MeshInstance>` with a :ref:`Primitive Mesh <class_PrimitiveMesh>`,
|
||||
a :ref:`Camera3D <class_Camera3D>`, a :ref:`light source <class_OmniLight>`, a
|
||||
:ref:`MeshInstance3D <class_MeshInstance3D>` with a :ref:`Primitive Mesh <class_PrimitiveMesh>`,
|
||||
and applying a :ref:`StandardMaterial3D <class_StandardMaterial3D>` to the mesh. The focus will be on using
|
||||
the :ref:`Viewport <class_Viewport>` to dynamically create textures that can be applied to the mesh.
|
||||
|
||||
@@ -75,13 +75,13 @@ apply to the sphere.
|
||||
Applying the texture
|
||||
--------------------
|
||||
|
||||
MeshInstance > GeometryInstance > Geometry > Material Override > ``New StandardMaterial3D``:
|
||||
MeshInstance3D > GeometryInstance > Geometry > Material Override > ``New StandardMaterial3D``:
|
||||
|
||||
Now we go into the :ref:`Mesh Instance <class_MeshInstance>` and add a :ref:`StandardMaterial3D <class_StandardMaterial3D>`
|
||||
Now we go into the :ref:`MeshInstance3D <class_MeshInstance3D>` and add a :ref:`StandardMaterial3D <class_StandardMaterial3D>`
|
||||
to it. No need for a special :ref:`Shader Material <class_ShaderMaterial>` (although that would be a good idea
|
||||
for more advanced effects, like the atmosphere in the example above).
|
||||
|
||||
MeshInstance > GeometryInstance > Geometry > Material Override > ``click`` / ``Edit``:
|
||||
MeshInstance3D > GeometryInstance > Geometry > Material Override > ``click`` / ``Edit``:
|
||||
|
||||
Open the newly created :ref:`StandardMaterial3D <class_StandardMaterial3D>` and scroll down to the "Albedo" section
|
||||
and click beside the "Texture" property to add an Albedo Texture. Here we will apply the texture we made.
|
||||
|
||||
@@ -42,26 +42,26 @@ program (e.g. Blender). But Godot also has a few :ref:`PrimitiveMeshes
|
||||
importing Meshes.
|
||||
|
||||
There are multiple node types that you can use to draw a mesh. The main one is
|
||||
:ref:`MeshInstance <class_meshinstance>`, but you can also use :ref:`GPUParticles3D
|
||||
:ref:`MeshInstance3D <class_MeshInstance3D>`, but you can also use :ref:`GPUParticles3D
|
||||
<class_GPUParticles3D>`, :ref:`MultiMeshes <class_MultiMesh>` (with a
|
||||
:ref:`MultiMeshInstance <class_multimeshinstance>`), or others.
|
||||
:ref:`MultiMeshInstance3D <class_MultiMeshInstance3D>`), or others.
|
||||
|
||||
Typically, a material is associated with a given surface in a mesh, but some
|
||||
nodes, like MeshInstance, allow you to override the material for a specific
|
||||
nodes, like MeshInstance3D, allow you to override the material for a specific
|
||||
surface, or for all surfaces.
|
||||
|
||||
If you set a material on the surface or mesh itself, then all MeshInstances that
|
||||
If you set a material on the surface or mesh itself, then all MeshInstance3Ds that
|
||||
share that mesh will share that material. However, if you want to reuse the same
|
||||
mesh across multiple mesh instances, but have different materials for each
|
||||
instance then you should set the material on the Meshinstance.
|
||||
instance then you should set the material on the MeshInstance3D.
|
||||
|
||||
For this tutorial we will set our material on the mesh itself rather than taking
|
||||
advantage of the MeshInstance's ability to override materials.
|
||||
advantage of the MeshInstance3D's ability to override materials.
|
||||
|
||||
Setting up
|
||||
----------
|
||||
|
||||
Add a new :ref:`MeshInstance <class_meshinstance>` node to your scene.
|
||||
Add a new :ref:`MeshInstance3D <class_MeshInstance3D>` node to your scene.
|
||||
|
||||
In the inspector tab beside "Mesh" click "[empty]" and select "New PlaneMesh".
|
||||
Then click on the image of a plane that appears.
|
||||
@@ -81,7 +81,7 @@ Now set ``Subdivide Width`` and ``Subdivide Depth`` to ``32``.
|
||||
.. image:: img/plane-sub-set.png
|
||||
|
||||
You can see that there are now many more triangles in the
|
||||
:ref:`Mesh<class_MeshInstance>`. This will give us more vertices to work with
|
||||
:ref:`MeshInstance3D<class_MeshInstance3D>`. This will give us more vertices to work with
|
||||
and thus allow us to add more detail.
|
||||
|
||||
.. image:: img/plane-sub.png
|
||||
@@ -111,7 +111,7 @@ because this is a spatial shader.
|
||||
shader_type spatial;
|
||||
|
||||
Next we will define the ``vertex()`` function. The ``vertex()`` function
|
||||
determines where the vertices of your :ref:`Mesh<class_MeshInstance>` appear in
|
||||
determines where the vertices of your :ref:`MeshInstance3D<class_MeshInstance3D>` appear in
|
||||
the final scene. We will be using it to offset the height of each vertex and
|
||||
make our flat plane appear like a little terrain.
|
||||
|
||||
@@ -240,14 +240,14 @@ the shader.
|
||||
|
||||
::
|
||||
|
||||
# called from the MeshInstance
|
||||
# called from the MeshInstance3D
|
||||
mesh.material.set_shader_param("height_scale", 0.5)
|
||||
|
||||
.. note:: Changing uniforms in Spatial-based nodes is different from
|
||||
CanvasItem-based nodes. Here, we set the material inside the PlaneMesh
|
||||
resource. In other mesh resources you may need to first access the
|
||||
material by calling ``surface_get_material()``. While in the
|
||||
MeshInstance you would access the material using
|
||||
MeshInstance3D you would access the material using
|
||||
``get_surface_material()`` or ``material_override``.
|
||||
|
||||
Remember that the string passed into ``set_shader_param()`` must match the name
|
||||
|
||||
@@ -18,7 +18,7 @@ For a full list of these parameters see the :ref:`spatial shader
|
||||
A difference between the vertex function and a fragment function is that the
|
||||
vertex function runs per vertex and sets properties such as ``VERTEX``
|
||||
(position) and ``NORMAL``, while the fragment shader runs per pixel and, most
|
||||
importantly, sets the ``ALBEDO`` color of the :ref:`Mesh<class_MeshInstance>`.
|
||||
importantly, sets the ``ALBEDO`` color of the :ref:`MeshInstance3D<class_MeshInstance3D>`.
|
||||
|
||||
Your first spatial fragment function
|
||||
------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user