Proofing/review: Remove filler words, adhere to style guide

This commit is contained in:
mhilbrunner
2018-05-06 05:23:37 +02:00
parent c9be19229a
commit ec725ff8a0
88 changed files with 338 additions and 375 deletions

View File

@@ -20,7 +20,7 @@ usability and flexibility. Some practical examples of this are:
by material to reduce the costs, but at the same time sorting has a
cost.
- In 3D physics a similar situation happens. The best algorithms to
handle large amounts of physics objects (such as SAP) are very slow
handle large amounts of physics objects (such as SAP) are slow
at insertion/removal of objects and ray-casting. Algorithms that
allow faster insertion and removal, as well as ray-casting will not
be able to handle as many active objects.
@@ -63,7 +63,7 @@ Godot's priorities will be like this:
configuration).
If a scene has, for example, 20.000 objects with 20.000 different
materials each, rendering will be really slow. If the same scene has
materials each, rendering will be slow. If the same scene has
20.000 objects, but only uses 100 materials, rendering will be blazing
fast.
@@ -74,7 +74,7 @@ It is a common thought that the lower the number of polygons in a model, the
faster it will be rendered. This is *really* relative and depends on
many factors.
On a modern PC and console, vertex cost is low. Very low. GPUs
On a modern PC and console, vertex cost is low. GPUs
originally only rendered triangles, so all the vertices:
1. Had to be transformed by the CPU (including clipping).
@@ -96,7 +96,7 @@ to be a lot more power efficient.
To be more efficient, mobile GPUs attempt to avoid *overdraw*. This
means, the same pixel on the screen being rendered (as in, with lighting
calculation, etc.) more than once. Imagine a town with several buildings,
GPUs don't really know what is visible and what is hidden until they
GPUs don't know what is visible and what is hidden until they
draw it. A house might be drawn and then another house in front of it
(rendering happened twice for the same pixel!). PC GPUs normally don't
care much about this and just throw more pixel processors to the
@@ -162,7 +162,7 @@ Level of detail (LOD)
---------------------
As also mentioned before, using objects with less vertices can improve
performance in some cases. Godot has a very simple system to change level
performance in some cases. Godot has a simple system to change level
of detail,
:ref:`GeometryInstance <class_GeometryInstance>`
based objects have a visibility range that can be defined. Having

View File

@@ -7,7 +7,7 @@ Introduction
------------
Baked lightmaps are an alternative workflow for adding indirect (or baked) lighting to a scene. Unlike the :ref:`doc_gi_probes` approach,
baked lightmaps work fine on very low end PCs and mobile as they consume almost no resources in run-time.
baked lightmaps work fine on low end PCs and mobile devices as they consume almost no resources in run-time.
Unlike GIProbes, Baked Lightmaps are completely static, once baked they can't be modified at all. They also don't provide the scene with
reflections, so using :ref:`doc_reflection_probes` together with it on interiors (or using a Sky on exteriors) is a requirement to
@@ -40,7 +40,7 @@ Unwrap from your 3D DCC
~~~~~~~~~~~~~~~~~~~~~~~
One option is to do it from your favorite 3D app. This approach is generally not recommended but it's explained first so you know it exists.
The main advantage is that, on very complex objects that you may want to re-import a lot, the texture generation process can be quite costly within Godot,
The main advantage is that, on complex objects that you may want to re-import a lot, the texture generation process can be quite costly within Godot,
so having it unwrapped before import can be faster.
Simply do an unwrap on the second UV2 layer.
@@ -52,7 +52,7 @@ And import normally. Remember you will need to set the texture size on the mesh
.. image:: img/baked_light_lmsize.png
If you use external meshes on import, the size will be kept.
Be wary that most unwrappers in 3D DCCs are not very quality oriented, as they are meant to work quick. You will mostly need to use seams or other techniques to create better unwrapping.
Be wary that most unwrappers in 3D DCCs are not quality oriented, as they are meant to work quick. You will mostly need to use seams or other techniques to create better unwrapping.
Unwrap from within Godot
~~~~~~~~~~~~~~~~~~~~~~~~
@@ -77,7 +77,7 @@ final size of the lightmap texture (and, in consequence, the UV padding in the m
The effect of setting this option is that all meshes within the scene will have their UV2 maps properly generated.
As a word of warning: When reusing a mesh within a scene, keep in mind that UVs will be generated for the first instance found. If the mesh is re-used with different scales (and the scales
are wildly different, more than half or twice), this will result in inefficient lightmaps. Just don't reuse a source mesh at very different scales if you are planning to use lightmapping.
are wildly different, more than half or twice), this will result in inefficient lightmaps. Just don't reuse a source mesh at different scales if you are planning to use lightmapping.
Checking UV2
~~~~~~~~~~~~
@@ -144,7 +144,7 @@ Besides the capture size, quality can be modified by setting the **Bake Mode**.
.. image:: img/baked_light_mode.png
- **Voxel Cone**: Trace: Is the default one, it's less precise but very fast. Look similar (but slightly better) to GIProbe.
- **Voxel Cone**: Trace: Is the default one, it's less precise but fast. Look similar (but slightly better) to GIProbe.
- **Ray Tracing**: This method is more precise, but can take considerably longer to bake. If used in low or medium quality, some scenes may produce grain.
@@ -162,7 +162,7 @@ Configuring Bake
Several more options are present for baking:
- **Bake Subdiv**: Godot lightmapper uses a grid to transfer light information around. The default value is fine and should work for most cases. Increase it in case you want better lighting on very small details or your scene is very large.
- **Bake Subdiv**: Godot lightmapper uses a grid to transfer light information around. The default value is fine and should work for most cases. Increase it in case you want better lighting on small details or your scene is large.
- **Capture Subdiv**: This is the grid used for real-time capture information (lighting dynamic objects). Default value is generally OK, it's usually smaller than Bake Subdiv and can't be larger than it.
- **Bake Quality**: Three bake quality modes are provided, Low, Medium and High. Each takes less and more time.
- **Bake Mode**: The baker can use two different techniques: *Voxel Cone Tracing* (fast but approximate), or *RayTracing* (slow, but accurate).

View File

@@ -67,7 +67,7 @@ Ambient Light
Ambient (as defined here) is a type of light that affects every piece of geometry with the same intensity. It is global and independent of lights that might be added to the scene.
There are two types of ambient light, the *Ambient Color* (which is just a constant color multiplied by the material albedo), and then one obtained from the *Sky* (as described before, but a sky needs to be set as background for this to be enabled).
There are two types of ambient light, the *Ambient Color* (which is a constant color multiplied by the material albedo), and then one obtained from the *Sky* (as described before, but a sky needs to be set as background for this to be enabled).
.. image:: img/environment_ambient.png
@@ -78,7 +78,7 @@ Here is a comparison of how different ambient light affects a scene:
.. image:: img/environment_ambient2.png
Finally there is a **Energy** setting, which is just a multiplier, useful when working with HDR.
Finally there is a **Energy** setting, which is a multiplier, useful when working with HDR.
In general, ambient light should only be used for simple scenes, large exteriors or for performance reasons (ambient light is cheap), as it does not provide the best lighting quality. It's better to generate
ambient light from ReflectionProbe or GIProbe, which will more faithfully simulate how indirect light propagates. Below is a comparison in quality between using a flat ambient color and a GIProbe:
@@ -90,7 +90,7 @@ Using one of the methods described above, objects get constant ambient lighting
Fog
^^^
Fog, just as in real life, makes distant objects fade away into an uniform color. The physical effect is actually pretty complex, but Godot provides a good approximation. There are two kinds of fog in Godot:
Fog, as in real life, makes distant objects fade away into an uniform color. The physical effect is actually pretty complex, but Godot provides a good approximation. There are two kinds of fog in Godot:
- **Depth Fog:** This one is applied based on the distance from the camera.
- **Height Fog:** This one is applied to any objects below (or above) a certain height, regardless of the distance from the camera.
@@ -179,7 +179,7 @@ This can be simulated with Screen Space Ambient Occlusion. As you can see in the
It is a common mistake to enable this effect, turn on a light and not be able to appreciate it. This is because SSAO only acts on *ambient* light, not direct light.
This is why, in the image above, the effect is less noticeable under the direct light (at the left). If you want to force SSAO to work with direct light too, just use the **Light Affect** parameter (even though this is not correct, some artists like how it looks).
This is why, in the image above, the effect is less noticeable under the direct light (at the left). If you want to force SSAO to work with direct light too, use the **Light Affect** parameter (even though this is not correct, some artists like how it looks).
SSAO looks best when combined with a real source of indirect light, like GIProbe:
@@ -218,7 +218,7 @@ It has an initial **Distance** with a **Transition** region (in world units):
The **Amount** parameter controls the amount of blur. For larger blurs, tweaking the **Quality** may be needed in order to avoid arctifacts.
It is very common to use both blurs together to focus the viewer's attention on a given object:
It is common to use both blurs together to focus the viewer's attention on a given object:
.. image:: img/environment_mixed_blur.png
@@ -231,7 +231,7 @@ the **Glow** effect.
.. image:: img/environment_glow1.png
By default, even if the effect is enabled, it will be very weak or invisible. One of two conditions need to happen for it to actually show:
By default, even if the effect is enabled, it will be weak or invisible. One of two conditions need to happen for it to actually show:
- 1) The light in a pixel surpasses the **HDR Threshold** (where 0 is all light surpasses it, and 1.0 is light over the tonemapper **White** value). Normally this value is expected to be at 1.0, but it can be lowered to allow more light to bleed. There is also an extra parameter, **HDR Scale** that allows scaling (making brighter or darker) the light surpasing the threshold.

View File

@@ -126,7 +126,7 @@ Now let's look at ``_process``.
First we check to see if the ``grenade_timer`` is less than ``GRENADE_TIMER``. If it is, we add ``delta`` and return. This is so we have to wait ``GRENADE_TIME`` seconds,
allowing our :ref:`RigidBody <class_RigidBody>` to move around.
If ``grenade_timer`` is at ``GRENADE_TIMER`` or higher, we then need to check if we just waited long enough and need to explode. We do this by checking to see
If ``grenade_timer`` is at ``GRENADE_TIMER`` or higher, we then need to check if we waited long enough and need to explode. We do this by checking to see
if ``explosion_wait_timer`` is equal to ``0`` or less. Since we will be adding ``delta`` to ``explosion_wait_timer`` right after, whatever code under the check
will only be called once, right when we've waited long enough and need to explode.
@@ -140,7 +140,7 @@ the grenade's position.
We then check to see if ``explosion_wait_timer`` is less than ``EXPLOSION_WAIT_TIME``. If it is, we add ``delta`` to ``explosion_wait_time``.
Next we check to see if ``explosion_wait_timer`` is more than or equal to ``EXPLOSTION_WAIT_TIME``. Because we just added ``delta``, this will only be called once.
Next we check to see if ``explosion_wait_timer`` is more than or equal to ``EXPLOSTION_WAIT_TIME``. Because we added ``delta``, this will only be called once.
If ``explosion_wait_timer`` is more or equal to ``EXPLOSION_WAIT_TIME``, we've waited long enough to let the :ref:`Particles <class_Particles>` play and can free/destroy ourselves.
______
@@ -241,7 +241,7 @@ Select ``Sticky_Grenade`` and make a new script called ``Sticky_Grenade.gd``. Ad
attach_point.queue_free()
queue_free()
The code above is almost identical to the code for ``Grenade.gd``, so let's just go over what's changed.
The code above is almost identical to the code for ``Grenade.gd``, so let's go over what's changed.
First, we have a few more global variables:
@@ -262,10 +262,10 @@ ______
Next let's take a look at ``collided_with_body``.
First we make sure we're not colliding with ourself. Because our :ref:`Area <class_Area>` does not know it's attached to the grenade's :ref:`RigidBody <class_RigidBody>`,
we need to make sure we're not going to stick to ourself. If we have collided with ourself, we just ignore it by returning.
we need to make sure we're not going to stick to ourself. If we have collided with ourself, we ignore it by returning.
We then check to see if we have something assigned to ``player_body``, and if the body we collided with is the player that threw this grenade.
If the body we've collided with is indeed ``player_body``, we just ignore it by returning.
If the body we've collided with is indeed ``player_body``, we ignore it by returning.
Next we check if we are attached already or not.
@@ -319,7 +319,7 @@ Okay, now lets start making the grenades work with our player. Add the following
* ``sticky_grenade_scene``: The sticky grenade scene we worked on earlier.
* ``GRENADE_THROW_FORCE``: The force at which we throw the grenade at.
Most of these variables are very similar to how we have out weapons set up.
Most of these variables are similar to how we have out weapons set up.
.. tip:: While it's possible to make a more modular grenade system, I found it was not worth the additional complexity for just two grenades.
If you were going to make a more complex FPS with more grenades, you'd likely want to make a system for grenades similar to how we have the weapons set up.
@@ -405,10 +405,10 @@ While we're still in ``Player.gd``, let's add a function to add grenades. Add th
Now we can add a grenade using ``add_grenade``, and it will automatically be clamped to a maximum of ``4`` grenades.
.. tip:: You can change the ``4`` to a constant if you want. You'd just need to make a new global constant, something like ``MAX_GRENADES``, and
.. tip:: You can change the ``4`` to a constant if you want. You'd need to make a new global constant, something like ``MAX_GRENADES``, and
then change the clamp from ``clamp(grenade_amounts[current_grenade], 0, 4)`` to ``clamp(grenade_amounts[current_grenade], 0, MAX_GRENADES)``
If you do not want to limit how many grenades you can carry, just remove the line that clamps the grenades altogether!
If you do not want to limit how many grenades you can carry, remove the line that clamps the grenades altogether!
Now we have a function to add grenades, let's open up ``AmmoPickup.gd`` and use it!
@@ -427,7 +427,7 @@ Open up ``AmmoPickup.gd`` and go to the ``trigger_body_entered`` function. Chang
respawn_timer = RESPAWN_TIME
kit_size_change_values(kit_size, false)
Now we're also checking to see if the body has the ``add_grenade`` function. If it does, we call it just like we call ``add_ammo``.
Now we're also checking to see if the body has the ``add_grenade`` function. If it does, we call it like we call ``add_ammo``.
You may have noticed we're using a new constant we haven't defined yet, ``GRENADE_AMOUNTS``. Let's add it! Add the following global variable
to ``AmmoPickup.gd`` with the other global variables:
@@ -506,7 +506,7 @@ With that done, all we need to do is add some code to ``process_input``:
Let's go over what's happening.
First we check to see if the action pressed is the ``fire`` action, and that we are using the ``UNARMED`` weapon.
This is because we only want to be able to pick up and throw objects when we're not using any weapons. This is just a design choice,
This is because we only want to be able to pick up and throw objects when we're not using any weapons. This is a design choice,
but I feel it gives ``UNARMED`` a use.
Next we check to see whether or not ``grabbed_object`` is ``null``.
@@ -565,7 +565,7 @@ If we are holding an object, we set its global position to the camera's position
______
Before we test this, we need to change something in ``_physics_process``. While we're holding an object, we really don't
Before we test this, we need to change something in ``_physics_process``. While we're holding an object, we don't
want to be able to change weapons or reload, so change ``_physics_process`` to the following:
::
@@ -595,7 +595,7 @@ Open up ``Turret.tscn``. Expand ``Turret`` if it's not already expanded.
Notice how our turret is broken up into several parts. We have a ``Base``, ``Head``, ``Vision_Area``, and a ``Smoke`` :ref:`Particles <class_Particles>`.
Open up ``Base`` and you'll find it's just a :ref:`StaticBody <class_StaticBody>` and a mesh. Open up ``Head`` and you'll find there's several meshes,
Open up ``Base`` and you'll find it's a :ref:`StaticBody <class_StaticBody>` and a mesh. Open up ``Head`` and you'll find there's several meshes,
a :ref:`StaticBody <class_StaticBody>` and a :ref:`Raycast <class_Raycast>` node.
One thing to note with the ``Head`` is that the raycast will be where our bullets will fire from if we are using raycasting. We also have two meshes called
@@ -842,7 +842,7 @@ we subtract ``delta`` from ``ammo_reload_timer``. If ``ammo_reload_timer`` is eq
we've waited long enough to refill the turret.
Next we check to see if the turret's health is less than or equal to ``0``, outside of whether we're active or not. If the turret's health is zero or less, we then
check to see if ``destroyed_timer`` is more than zero. If destroyed timer is more than zero, we just subtract ``delta`` from ``destroyed_timer``.
check to see if ``destroyed_timer`` is more than zero. If destroyed timer is more than zero, we subtract ``delta`` from ``destroyed_timer``.
If ``destyored_timer`` is less than or equal to zero, we set ``turret_health`` to ``MAX_TURRET_HEALTH`` and stop emitting smoke particles by setting ``smoke_particles.emitting`` to
``false``.
@@ -932,7 +932,7 @@ attached, assign the :ref:`NodePath <class_NodePath>` to the ``Turret`` node.
______
The last thing we need to do is add a way for the player to be hurt. Since all of our bullets use the ``bullet_hit`` function, we just need to add that to our player.
The last thing we need to do is add a way for the player to be hurt. Since all of our bullets use the ``bullet_hit`` function, we need to add that to our player.
Open ``Player.gd`` and add the following:

View File

@@ -169,7 +169,7 @@ it is mapped to the proper axes for the right joystick.
.. warning:: As stated above, I do not (currently) has access to a Mac computer, so the joystick axes may need changing. If they do,
please open a GitHub issue on the Godot documentation repository!
We then account for the joypad's dead zone, just like in ``process_input``.
We then account for the joypad's dead zone, exactly like in ``process_input``.
Then we rotate ``rotation_helper`` and our KinematicBody using ``joypad_vec``.
@@ -190,7 +190,7 @@ Once ``process_view_input`` is added to ``_physics_process``, you should be able
.. note:: I decided not to use the joypad triggers for firing because we'd then have to do some more axis managing, and because I prefer to use a shoulder button to fire.
If you want to use the triggers for firing, you will need to change how firing works in ``process_input``. You need to get the proper axis value for the trigger,
and check if it's over a certain value, say ``0.8`` for example. If it is, you just add the same code as when the ``fire`` action was pressed.
and check if it's over a certain value, say ``0.8`` for example. If it is, you add the same code as when the ``fire`` action was pressed.
Adding mouse scroll wheel input
-------------------------------
@@ -280,7 +280,7 @@ Open up ``Health_Pickup.tscn``.
Expand ``Holder`` if it's not already expanded. Notice how we have two Spatial nodes, one called ``Health_Kit`` and another called ``Health_Kit_Small``.
This is because we're actually going to be making two sizes of health pick ups, one small and one large/normal. ``Health_Kit`` and ``Health_Kit_Small`` just
This is because we're actually going to be making two sizes of health pick ups, one small and one large/normal. ``Health_Kit`` and ``Health_Kit_Small`` only
have a single :ref:`MeshInstance <class_MeshInstance>` as their children.
Next expand ``Health_Pickup_Trigger``. This is an :ref:`Area <class_Area>` node we're going to use to check if the player has walked close enough to pick up
@@ -452,10 +452,10 @@ when a ``Health_Pickup`` instanced scene is selected, from a convenient drop dow
Adding the ammo pick ups
------------------------
While adding health is good and all, we can't really reap the rewards from it since nothing can (currently) damage us.
While adding health is good and all, we can't reap the rewards from it since nothing can (currently) damage us.
Let's add some ammo pick ups next!
Open up ``Ammo_Pickup.tscn``. Notice how it's structured exactly the same as ``Health_Pickup.tscn``, just with the meshes and trigger collision shapes changed slightly to adjust
Open up ``Ammo_Pickup.tscn``. Notice how it's structured exactly the same as ``Health_Pickup.tscn``, but with the meshes and trigger collision shapes changed slightly to adjust
for the difference in mesh sizes.
Select ``Ammo_Pickup`` and add a new script called ``Ammo_Pickup.gd``. Add the following:
@@ -523,7 +523,7 @@ You may have noticed this code looks almost exactly the same as the health pick
have been changed, and that's what we're going to go over.
First, notice how we have ``AMMO_AMOUNTS`` instead of ``HEALTH_AMMOUNTS``. ``AMMO_AMOUNTS`` will be how many ammo clips/magazines we add to the current weapon.
(Unlike ``HEALTH_AMMOUNTS`` which was how many health points, we instead just add an entire clip for the current weapon, instead of the raw ammo amount)
(Unlike ``HEALTH_AMMOUNTS`` which was how many health points, we instead add an entire clip for the current weapon, instead of the raw ammo amount)
The only other thing to notice is in ``trigger_body_entered`` we're checking and calling a function called ``add_ammo``, not ``add_health``.
@@ -552,7 +552,7 @@ _______
With that done, you should now be able to get additional ammo! Go place some ammo pick ups in one/both/all of the scenes and give it a try!
.. note:: Notice how we're not limiting the amount of ammo you can carry. To limit the amount of ammo each weapon can carry, you just need to add a additional variable to
.. note:: Notice how we're not limiting the amount of ammo you can carry. To limit the amount of ammo each weapon can carry, you need to add a additional variable to
each weapon's script, and then clamp the weapon's ``spare_ammo`` variable after adding ammo in ``add_ammo``.
Adding breakable targets

View File

@@ -351,7 +351,7 @@ If you want to move using the world space directional vectors, you'd do somethin
node.translate(Vector3(-1, 0, 0))
.. note:: Notice how we do not need to do any calculations to get world space directional vectors.
We can just define a few :ref:`Vector3 <class_Vector3>` variables and input the values pointing in each direction.
We can define a few :ref:`Vector3 <class_Vector3>` variables and input the values pointing in each direction.
Here is what world space looks like in 2D:
@@ -553,7 +553,7 @@ similar names.
``is_sprinting`` is a boolean to track whether the player is currently sprinting, and ``flashlight`` is a variable
we will be using to hold our flash light node.
Now we just need to add a few lines of code, starting in ``_ready``. Add the following to ``_ready``:
Now we need to add a few lines of code, starting in ``_ready``. Add the following to ``_ready``:
::
@@ -588,14 +588,14 @@ Let's go over the additions:
We set ``is_sprinting`` to true when we are holding down the ``movement_sprint`` action, and false
when the ``movement_sprint`` action is released. In ``process_movement`` we'll add the code that makes the player faster when
they sprint. Here in ``process_input`` we're just going to change the ``is_sprinting`` variable.
they sprint. Here in ``process_input`` we're going to change the ``is_sprinting`` variable.
We do something similar freeing/capturing the cursor for handling the flash light. We first check to see if the ``flashlight`` action
was just pressed. If it was, we then check to see if ``flashlight`` is visible in the scene tree. If it is, then we hide it, and if it's not we show it.
_________
Now we just need to change a couple things in ``process_movement``. First, replace ``target *= MAX_SPEED`` with the following:
Now we need to change a couple things in ``process_movement``. First, replace ``target *= MAX_SPEED`` with the following:
::

View File

@@ -28,9 +28,9 @@ The main menu is broken up into three different panels, each representing a diff
'screen' of our main menu.
.. note:: The ``Background_Animation`` node is just so the background of the menu is a bit more interesting than a solid color.
It's just a camera looking around the skybox, nothing fancy.
It's a camera looking around the skybox, nothing fancy.
Feel free to expand all of the nodes and see how their set up. Just remember to keep only ``Start_Menu`` visible
Feel free to expand all of the nodes and see how their set up. Remember to keep only ``Start_Menu`` visible
when you're done, as that's the screen we want to show first when we enter the main menu.
Select ``Main_Menu`` (the root node) and create a new script called ``Main_Menu.gd``. Add the following:
@@ -120,7 +120,7 @@ Select ``Main_Menu`` (the root node) and create a new script called ``Main_Menu.
globals.joypad_sensitivity = $Options_Menu/HSlider_Joypad_Sensitivity.value
Most of the code here relates to making UIs, which is really outside of the purpose of this tutorial series.
Most of the code here relates to making UIs, which is outside of the purpose of this tutorial series.
**We're only going to look at the UI related code briefly.**
.. tip:: See :ref:`doc_ui_main_menu` and the tutorials following for better ways to make GUIs and UIs!
@@ -189,7 +189,7 @@ We then set the ``mouse_sensitivity`` and ``joypad_sensitvity`` variables to the
Making the ``Globals`` singleton
--------------------------------
Now, for this all to work we really need to make the ``Globals`` singleton. Make a new script in the ``Script`` tab and call it ``Globals.gd``.
Now, for this all to work we need to create the ``Globals`` singleton. Make a new script in the ``Script`` tab and call it ``Globals.gd``.
Add the following to ``Globals.gd``.
@@ -206,8 +206,8 @@ Add the following to ``Globals.gd``.
func load_new_scene(new_scene_path):
get_tree().change_scene(new_scene_path)
As you can see, it's really quite small and simple. As this part progresses we will
keeping adding complexities to ``Global.gd``, but for now all it really is doing is holding two variables for us, and abstracting how we change scenes.
As you can see, it's quite small and simple. As this part progresses we will
keeping adding complexities to ``Global.gd``, but for now all it is doing is holding two variables for us, and abstracting how we change scenes.
* ``mouse_sensitivity``: The current sensitivity for our mouse, so we can load it in ``Player.gd``.
* ``joypad_sensitivity``: The current sensitivity for our joypad, so we can load it in ``Player.gd``.
@@ -333,7 +333,7 @@ instancing/spawning lots of nodes and are not freeing them.
______
Now we just need to add ``set_debug_display`` to ``Globals.gd``:
Now we need to add ``set_debug_display`` to ``Globals.gd``:
::
@@ -456,7 +456,7 @@ Add the following to ``Globals.gd``:
``popup_closed`` will resume the game and destroy the pop up if there is one.
``popup_quit`` is very similar, but we're also making sure the mouse is visible and changing scenes to the title screen.
``popup_quit`` is similar, but we're also making sure the mouse is visible and changing scenes to the title screen.
Add the following to ``Globals.gd``:
@@ -886,7 +886,7 @@ Lets go over these global variables.
* ``SIMPLE_AUDIO_PLAYER_SCENE``: The simple audio player scene.
* ``created_audio``: A list to hold all of the simple audio players we create
.. note:: If you want to add additional audio, you just need to add it to ``audio_clips``. No audio files are provided in this tutorial,
.. note:: If you want to add additional audio, you need to add it to ``audio_clips``. No audio files are provided in this tutorial,
so you will have to provide your own.
One site I'd recommend is **GameSounds.xyz**.

View File

@@ -188,7 +188,7 @@ Now we can see how much ammo we have through the HUD.
Adding reloading to the weapons
-------------------------------
Now that we can run our weapons out of ammo, we really need a way to fill them back up. Let's add reloading next!
Now that we can run our weapons out of ammo, we need a way to fill them back up. Let's add reloading next!
For reloading we need to add a few more variables and a function to every weapon.
@@ -267,7 +267,7 @@ Now we need to add reloading to the rifle. Open up ``Weapon_Rifle.gd`` and add t
These variables are exactly the same as the pistol, just with ``RELOADING_ANIM_NAME`` changed to the rifle's reloading animation.
Now we just need to add ``reload_weapon`` to ``Weapon_Rifle.gd``:
Now we need to add ``reload_weapon`` to ``Weapon_Rifle.gd``:
::
@@ -312,19 +312,19 @@ The last bit we need to do for the weapons is add 'reloading' to the knife. Add
Since we both cannot reload or refill a knife, we set both constants to ``false``. We also define ``RELOADING_ANIM_NAME`` as an empty string, since the knife
has no reloading animation.
Now we just need to add ``reloading_weapon``, and thankfully it's really simple:
Now we need to add ``reloading_weapon``:
::
func reload_weapon():
return false
Since we cannot reload a knife, we just always return ``false``.
Since we cannot reload a knife, we always return ``false``.
Adding reloading to the player
------------------------------
Now we just need to add a few things to ``Player.gd``. First we need to define a new global variable:
Now we need to add a few things to ``Player.gd``. First we need to define a new global variable:
::
@@ -584,7 +584,7 @@ First we need to load the ``SimpleAudioPlayer.tscn``. Place the following code i
var simple_audio_player = preload("res://Simple_Audio_Player.tscn")
Now we just need to instance the simple audio player when we need it, and then call its
Now we need to instance the simple audio player when we need it, and then call its
``play_sound`` function and pass the name of the sound we want to play. To make the process simpler,
let's create a ``create_sound`` function:
@@ -611,7 +611,7 @@ is the root node that our player is under, which could not always be the case.
If this doesn't make sense to you, don't worry too much about it. The second line of code only doesn't work
reliably if you have multiple scenes loaded as children to the root node at a time, which will rarely happen for most projects.
This is really only potentially a issue depending on how you handle scene loading.
This is only potentially a issue depending on how you handle scene loading.
The third line adds our newly created ``SimpleAudioPlayer`` scene to be a child of the scene root. This
works exactly the same as when we are spawning bullets.
@@ -633,7 +633,7 @@ Now, we want to make a noise when we fire the pistol, so add the following to th
Now when we fire our pistol, we'll play the ``pistol_shot`` sound.
To make a sound when we reload, we just need to add the following right under ``player_node.animation_manager.set_animation(RELOADING_ANIM_NAME)`` in the
To make a sound when we reload, we need to add the following right under ``player_node.animation_manager.set_animation(RELOADING_ANIM_NAME)`` in the
``reload_weapon`` function:
::
@@ -655,7 +655,7 @@ To play sounds when the rifle is fired, add the following to the end of the ``fi
Now when we fire our rifle, we'll play the ``rifle_shot`` sound.
To make a sound when we reload, we just need to add the following right under ``player_node.animation_manager.set_animation(RELOADING_ANIM_NAME)`` in the
To make a sound when we reload, we need to add the following right under ``player_node.animation_manager.set_animation(RELOADING_ANIM_NAME)`` in the
``reload_weapon`` function:
::
@@ -674,7 +674,7 @@ Now you have weapons with limited ammo that play sounds when you fire them!
At this point we have all of the basics of a FPS working.
There's still a few things that would be nice to add, and we're going to add them in the next three parts!
For example, right now we have no way to add ammo to our spares, so we'll eventually run out. Also, we don't really
For example, right now we have no way to add ammo to our spares, so we'll eventually run out. Also, we don't
have anything to shoot at outside of the :ref:`RigidBody <class_RigidBody>` nodes.
In In :ref:`doc_fps_tutorial_part_four` we'll add some targets to shoot at, along with some health and ammo pick ups!

View File

@@ -239,7 +239,7 @@ check for every possible animation state. If we need to, we transition into anot
the end of the animation and are about to loop again.
.. note:: the transitions in ``animation_ended`` ideally would be part of the data in ``states``, but in
an effort to make the tutorial easier to understand, we'll just hard code each state transition
an effort to make the tutorial easier to understand, we'll hard code each state transition
in ``animation_ended``.
_________
@@ -248,7 +248,7 @@ Finally we have ``animation_callback``. This function will be called by a functi
If we have a :ref:`FuncRef <class_FuncRef>` assigned to ``callback_function``, then we call that passed in function. If we do not
have a :ref:`FuncRef <class_FuncRef>` assigned to ``callback_function``, we print out a warning to the console.
.. tip:: Try running ``Testing_Area.tscn`` just to make sure there is no runtime issues. If the game runs but nothing
.. tip:: Try running ``Testing_Area.tscn`` to make sure there is no runtime issues. If the game runs but nothing
seems to have changed, then everything is working correctly.
Getting the animations ready
@@ -263,7 +263,7 @@ Open up ``Player.tscn`` if you don't have it open and navigate to the :ref:`Anim
We need to attach a function track to three of our animations: The firing animation for the pistol, rifle, and knife.
Let's start with the pistol. Click the animation drop down list and select "Pistol_fire".
Now scroll down to the very bottom of the list of animation tracks. The final item in the list should read
Now scroll down to the bottom of the list of animation tracks. The final item in the list should read
``Armature/Skeleton:Left_UpperPointer``. Now at the bottom of the list, click the plus icon on the bottom
bar of animation window, right next to the loop button and the up arrow.
@@ -277,7 +277,7 @@ option that reads "Add Call Func Track". This will open a window showing the ent
Now at the bottom of list of animation tracks you will have a green track that reads "AnimationPlayer".
Now we need to add the point where we want to call our callback function. Scrub the timeline until you
reach the point where the muzzle just starts to flash.
reach the point where the muzzle starts to flash.
.. note:: The timeline is the window where all of the points in our animation are stored. Each of the little
points represents a point of animation data.
@@ -323,7 +323,7 @@ Let's repeat the process for the rifle and knife firing animations!
Follow the steps in the above if you get lost! It is exactly the same, just on a different animation.
Go to the "Rifle_fire" animation from the animation drop down. Add the function callback track once you reach the bottom of the
animation track list by clicking the little plus icon at the bottom of the screen. Find the point where the muzzle just starts
animation track list by clicking the little plus icon at the bottom of the screen. Find the point where the muzzle starts
to flash and click the little green plus symbol to add a function callback point at that position on the track.
Next, click the "enable editing of individual keys" button.
@@ -331,12 +331,12 @@ Select the newly created function callback point, put "animation_callback" into
Click the "enable editing of individual keys" button again to turn off individual key editing.
so we cannot change one of the transform tracks by accident.
Now we just need to apply the callback function track to the knife animation. Select the "Knife_fire" animation and scroll to the bottom of the
Now we need to apply the callback function track to the knife animation. Select the "Knife_fire" animation and scroll to the bottom of the
animation tracks. Click the plus symbol at the bottom of the animation window and add a function callback track.
Next find a point around the first third of the animation to place the animation callback function point at.
.. note:: We will not actually be firing the knife, and the animation really is a stabbing animation rather than a firing one.
For this tutorial we are just reusing the gun firing logic for our knife, so the animation has been named in a style that
.. note:: We will not actually be firing the knife, and the animation is a stabbing animation rather than a firing one.
For this tutorial we are reusing the gun firing logic for our knife, so the animation has been named in a style that
is consistent with the other animations.
From there click the little green plus to add a function callback point at the current position. Then click the "enable editing of individual keys"
@@ -347,7 +347,7 @@ so we cannot change one of the transform tracks by accident.
.. tip:: Be sure to save your work!
With that done, we are almost ready to start adding the ability to fire to our player script! We just need to setup one last scene:
With that done, we are almost ready to start adding the ability to fire to our player script! We need to setup one last scene:
The scene for our bullet object.
Creating the bullet scene
@@ -366,15 +366,15 @@ There are several advantages to this method. The first being we do not have to s
and then move on, and the bullet itself with handle checking for collisions, sending the proper signal(s) to the object it collides with, and destroying itself.
Another advantage is we can have more complex bullet movement. If we want to make the bullet fall ever so slightly as time goes on, we can make the bullet
controlling script slowly push the bullet towards the ground. Using a object also makes the bullet take time to reach its target, it doesn't just instantly
hit whatever its pointed at. This feels more realistic because nothing in real life really moves instantly from one point to another.
controlling script slowly push the bullet towards the ground. Using a object also makes the bullet take time to reach its target, it doesn't instantly
hit whatever its pointed at. This feels more realistic because nothing in real life moves instantly from one point to another.
One of the huge disadvantages performance. While having each bullet calculate their own paths and handle their own collision allows for a lot of flexibility,
it comes at the cost of performance. With this method we are calculating every bullet's movement every step, and while this may not be a problem for a few dozen
bullets, it can become a huge problem when you potentially have several hundred bullets.
Despite the performance hit, many first person shooters include some form of object bullets. Rocket launchers are a prime example because in many
first person shooters, Rockets do not just instantly explode at their target position. You can also find bullets as object many times with grenades
first person shooters, rockets do not just instantly explode at their target position. You can also find bullets as object many times with grenades
because they generally bounce around the world before exploding.
.. note:: While I cannot say for sure this is the case, these games *probably* use bullet objects in some form or another:
@@ -408,19 +408,19 @@ We set the raycast's origin to the starting position of the bullet, and based on
- Call of Duty (Assault rifles, light machine guns, sub machine guns, pistols, and more)
- Battlefield (Assault rifles, SMGs, carbines, pistols, and more)
One huge advantage for this method is it's really light on performance.
One huge advantage for this method is it's light on performance.
Sending a couple hundred rays through space is *way* easier for the computer to calculate than sending a couple hundred
bullet objects.
Another advantage is we can instantly know if we've hit something or not exactly when we call for it. For networking this is important because we do not need
to sync the bullet movements over the Internet, we just need to send whether or not the raycast hit.
to sync the bullet movements over the Internet, we only need to send whether or not the raycast hit.
Raycasting does have some disadvantages though. One major disadvantage is we cannot easily cast a ray in anything but a linear line.
This means we can only fire in a straight line for however long our ray length is. You can create the illusion of bullet movement by casting
multiple rays at different positions, but not only is this hard to implement in code, it is also is heavier on performance.
Another disadvantage is we cannot see the bullet. With bullet objects we can actually see the bullet travel through space if we attach a mesh
to it, but because raycasts happen instantly, we do not really have a decent way of showing the bullets. You could draw a line from the origin of the
to it, but because raycasts happen instantly, we do not have a decent way of showing the bullets. You could draw a line from the origin of the
raycast to the point where the raycast collided, and that is one popular way of showing raycasts. Another way is simply not drawing the raycast
at all, because theoretically the bullets move so fast our eyes could not see it anyway.
@@ -494,7 +494,7 @@ change how the bullet interacts with the world.
.. note:: The reason we are using a kill timer is so we do not have a case where we
get a bullet travelling forever. By using a kill timer, we can assure that
no bullets will just travel forever and consume resources.
no bullets will travel forever and consume resources.
.. tip:: As in :ref:`doc_fps_tutorial_part_one`, we have a couple all uppercase global variables. The reason behind this is the same
as the reason given in :ref:`doc_fps_tutorial_part_one`: We want to treat these variables like constants, but we want to be
@@ -674,14 +674,14 @@ By using a modular design with a consistent interface, we can keep ``Player.gd``
_________
In ``_ready`` we simply just pass over it.
In ``_ready`` we simply pass over it.
There is one thing of note though, an assumption we're assuming we'll fill in ``Player.gd``.
We are going to assume that ``Player.gd`` will pass themselves in before calling any of the functions in ``Weapon_Pistol.gd``.
While this can lead to situations where the player does not pass themselves in (because we forget), we would have to have a long string
of ``get_parent`` calls to traverse up the scene tree to retrieve the player. This does not look very pretty (``get_parent().get_parent().get_parent()`` and so on)
of ``get_parent`` calls to traverse up the scene tree to retrieve the player. This does not look pretty (``get_parent().get_parent().get_parent()`` and so on)
and it is relatively safe to assume we will remember to pass ourselves to each weapon in ``Player.gd``.
_________
@@ -732,7 +732,7 @@ _________
Finally, let's look at ``unequip_weapon``:
``unequip_weapon`` is very similar to ``equip_weapon``, but instead we're checking things in reverse.
``unequip_weapon`` is similar to ``equip_weapon``, but instead we're checking things in reverse.
First we check to see if we are in our idle animation. Then check to make sure we are not in the ``Pistol_unequip`` animation.
If we are not in the ``Pistol_unequip`` animation, we want to play ``pistol_unequip``.
@@ -893,7 +893,7 @@ we call it, passing in the amount of damage a single knife swipe does (``DAMAGE`
.. note:: While we could attempt to calculate a rough location for where the knife hit, we
do not bother because using the area's position works well enough and the extra time
needed to calculate a rough position for each body is not really worth the effort.
needed to calculate a rough position for each body is not worth the effort.
Making the weapons work
-----------------------
@@ -927,7 +927,7 @@ Lets go over what these new variables will do:
- ``WEAPON_NAME_TO_NUMBER``: A dictionary allowing us to convert from a weapon's name to its number. We'll use this for changing weapons.
- ``changing_weapon``: A boolean to track whether or not we are changing guns/weapons.
- ``changing_weapon_name``: The name of the weapon we want to change to.
- ``health``: How much health our player has. In this part of the tutorial we will not really be using it.
- ``health``: How much health our player has. In this part of the tutorial we will not be using it.
- ``UI_status_label``: A label to show how much health we have, and how much ammo we have both in our gun and in reserves.
_________
@@ -1138,9 +1138,9 @@ We also set ``current_weapon_name`` to ``changing_weapon_name``, since the curre
_________
Now, we just need to add one more function to the player, and then the player is ready to start the weapons!
Now, we need to add one more function to the player, and then the player is ready to start the weapons!
We just need to add ``fire_bullet``, which will be called when by the :ref:`AnimationPlayer <class_AnimationPlayer>` at those
We need to add ``fire_bullet``, which will be called when by the :ref:`AnimationPlayer <class_AnimationPlayer>` at those
points we set earlier in the :ref:`AnimationPlayer <class_AnimationPlayer>` function track:
::
@@ -1154,13 +1154,13 @@ points we set earlier in the :ref:`AnimationPlayer <class_AnimationPlayer>` func
Lets go over what this function is doing:
First we check if we are changing weapons or not. If we are changing weapons, we do not want shoot so we just ``return``.
First we check if we are changing weapons or not. If we are changing weapons, we do not want shoot so we ``return``.
.. tip:: Calling ``return`` stops the rest of the function from being called. In this case, we are not returning a variable
because we are only interested in not running the rest of the code, and because we are not looking for a returned
variable either when we call this function.
Then we just tell the current weapon we are using to fire by calling its ``fire_weapon`` function.
Then we tell the current weapon we are using to fire by calling its ``fire_weapon`` function.
.. tip:: Remember how we mentioned the speed of the animations for firing was faster than
the other animations? By changing the firing animation speeds, you can change how
@@ -1168,7 +1168,7 @@ Then we just tell the current weapon we are using to fire by calling its ``fire_
_______
Before we are ready to test our new weapons, we still have just a little bit of work to do.
Before we are ready to test our new weapons, we still have a little bit of work to do.
Creating some test subjects
---------------------------
@@ -1176,7 +1176,7 @@ Creating some test subjects
Create a new script by going to the scripting window, clicking "file", and selecting new.
Name this script ``RigidBody_hit_test`` and make sure it extends :ref:`RigidBody <class_RigidBody>`.
Now we just need to add this code:
Now we need to add this code:
::
@@ -1210,7 +1210,7 @@ the :ref:`RigidBody <class_RigidBody>` seem to move in response to the bullet co
_______
Now we just need to attach this script to all of the :ref:`RigidBody <class_RigidBody>` nodes we want to effect.
Now we need to attach this script to all of the :ref:`RigidBody <class_RigidBody>` nodes we want to effect.
Open up ``Testing_Area.tscn`` and select all of the cubes parented to the ``Cubes`` node.

View File

@@ -20,7 +20,7 @@ The main downside of GIProbes are:
- A small amount of light leaking can occur if the level is not carefully designed. this must be artist-tweaked.
- Performance requirements are higher than for lightmaps, so it may not run properly in low end integrated GPUs (may need to reduce resolution).
- Reflections are voxelized, so they don't look as sharp as with ReflectionProbe, but in exchange they are volumetric so any room size or shape works for them. Mixing them with Screen Space Reflection also works very well.
- Reflections are voxelized, so they don't look as sharp as with ReflectionProbe, but in exchange they are volumetric so any room size or shape works for them. Mixing them with Screen Space Reflection also works well.
- They consume considerably more video memory than Reflection Probes, so they must be used by care in the right subdivision sizes.
Setting Up
@@ -79,7 +79,7 @@ The difference becomes clear in the image below, where light from the sky goes f
.. image:: img/giprobe_interior.png
As complex buildings may mix interiors with exteriors, combining GIProbes for both parts works very well.
As complex buildings may mix interiors with exteriors, combining GIProbes for both parts works well.
Tweaking

View File

@@ -6,7 +6,7 @@ Introduction to 3D
Creating a 3D game can be challenging. That extra Z coordinate makes
many of the common techniques that helped to make 2D games simple no
longer work. To aid in this transition, it is worth mentioning that
Godot uses very similar APIs for 2D and 3D. Most nodes are the same and
Godot uses similar APIs for 2D and 3D. Most nodes are the same and
are present in both 2D and 3D versions. In fact, it is worth checking
the 3D platformer tutorial, or the 3D kinematic character tutorials,
which are almost identical to their 2D counterparts.

View File

@@ -16,7 +16,7 @@ Initial problem
Talking in Godot terminology, the task we want to solve here is to position
our 2 angles we talked about above so, that the tip of the lowerarm bone is
as close to the target point (which is set by the target Vector3()) as possible
using only rotations. This task is very calculation-intensive and never
using only rotations. This task is calculation-intensive and never
resolved by analytical equation solving. So, it is an underconstrained
problem, which means there is an unlimited number of solutions to the
equation.
@@ -63,7 +63,7 @@ IK bone and calculate using that.
Implementation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We will just use an exported variable for the bone length to make it easy.
We will use an exported variable for the bone length to make it easy.
::
@@ -110,7 +110,7 @@ And for the ``_process()`` function:
func _process(delta):
pass_chain(delta)
Executing this script will just pass through the bone chain, printing bone
Executing this script will pass through the bone chain, printing bone
transforms.
::

View File

@@ -137,8 +137,8 @@ radius .
.. image:: img/light_omni.png
In real life, light attenuation is an inverse function, which means omni lights don't really have a radius.
This is a problem, because it means computing several omni lights would become really demanding.
In real life, light attenuation is an inverse function, which means omni lights don't have a radius.
This is a problem, because it means computing several omni lights would become demanding.
To solve this, a *Range* is introduced, together with an attenuation function.
@@ -152,10 +152,10 @@ These two parameters allow tweaking how this works visually, in order to find ae
Omni Shadow Mapping
^^^^^^^^^^^^^^^^^^^
Omni light shadow mapping is relatively straightforward, as it just works. The main issue that needs to be
Omni light shadow mapping is relatively straightforward. The main issue that needs to be
considered is the algorithm used to render it.
Omni Shadows can be rendered as either **"Dual Paraboloid" or "Cube Mapped"**. The former renders very quickly but can cause deformations,
Omni Shadows can be rendered as either **"Dual Paraboloid" or "Cube Mapped"**. The former renders quickly but can cause deformations,
while the later is more correct but more costly.
.. image:: img/shadow_omni_dp_cm.png
@@ -183,7 +183,7 @@ Spot lights share the same **Range** and **Attenuation** as **OmniLight**, and a
Spot Shadow Mapping
^^^^^^^^^^^^^^^^^^^
Spots don't need any parameters for shadow mapping, they should just work. Keep in mind that, at more than 89 degrees of aperture, shadows
Spots don't need any parameters for shadow mapping. Keep in mind that, at more than 89 degrees of aperture, shadows
stop functioning for spots, and you should consider using an Omni light.
Shadow Atlas

View File

@@ -12,7 +12,7 @@ Reflection Probes are used as a source of reflected and ambient light for object
A probe of this type captures the surroundings (as a sort of 360 degrees image), and stores versions
of it with increasing levels of *blur*. This is used to simulate roughness in materials, as well as ambient lighting.
While these probes are a very efficient way of storing reflections, they have a few shortcomings:
While these probes are a efficient way of storing reflections, they have a few shortcomings:
* They are efficient to render, but expensive to compute. This leads to a default behavior where they only capture on scene load.
* They work best for rectangular shaped rooms or places, otherwise the reflections shown are not as faithful (specially when roughness is 0).
@@ -20,7 +20,7 @@ While these probes are a very efficient way of storing reflections, they have a
Setting Up
----------
Setting up reflection probes is really easy! Just create a ReflectionProbe node, and wrap it around the area where you want to have reflections:
Create a ReflectionProbe node, and wrap it around the area where you want to have reflections:
.. image:: img/refprobe_setup.png
@@ -43,7 +43,7 @@ can be displaced to an empty place by moving the handles in the center:
.. image:: img/refprobe_center_gizmo.png
By default, shadow mapping is disabled when rendering probes (only in the rendered image inside the probe, not the actual scene). This is
a simple way to save on performance and memory. If you really want shadows in the probe, they can be toggled on/of with the *Enable Shadow* setting:
a simple way to save on performance and memory. If you want shadows in the probe, they can be toggled on/off with the *Enable Shadow* setting:
.. image:: img/refprobe_shadows.png
@@ -76,8 +76,8 @@ As you can see, this blending is never perfect (after all, these are box reflect
are only visible when using perfectly mirrored reflections. Normally, scenes have normal mapping and varying levels of roughness which
can hide this.
Alternatively, Reflection Probes work very well blended together with Screen Space Reflections to solve these problems. Combining them makes local reflections appear
more faithful, while probes only used as fallback when no screen-sace information is found:
Alternatively, Reflection Probes work well blended together with Screen Space Reflections to solve these problems. Combining them makes local reflections appear
more faithful, while probes only used as fallback when no screen-space information is found:
.. image:: img/refprobe_ssr.png

View File

@@ -60,7 +60,7 @@ by running the lighting shader on every pixel.
As these calculations are costly, performance can be brought down considerably in some corner cases such as drawing
several layers of transparency (common in particle systems). Switching to per vertex lighting may help these cases.
Additionally, on very low end devices such as mobile, switching to vertex lighting can considerably increase rendering performance.
Additionally, on low end or mobile devices, switching to vertex lighting can considerably increase rendering performance.
.. image:: img/spatial_material2.png
@@ -131,7 +131,7 @@ default one is Burley. Other modes are also available:
* **Burley:** Default mode, the original Disney Principled PBS diffuse algorithm.
* **Lambert:** Is not affected by roughness.
* **Lambert Wrap:** Extends Lambert to cover more than 90 degrees when roughness increases. Works great for hair and simulating cheap subsurface scattering. This implementation is energy conserving.
* **Oren Nayar:** This implementation aims to take microsurfacing into account (via roughness). Works really well for clay-like materials and some types of cloth.
* **Oren Nayar:** This implementation aims to take microsurfacing into account (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.
.. image:: img/spatial_material6.png
@@ -233,8 +233,8 @@ This renders the object via the opaque pipeline, which is faster and allows it t
Material colors, maps and channels
----------------------------------
Besides the parameters, what defines materials themselves are the colors, textures and channels. Godot supports a very extensive list
of them (arguably far more than any of the other prominent game engines). They will be described in detail below:
Besides the parameters, what defines materials themselves are the colors, textures and channels. Godot supports a extensive list
of them. They will be described in detail below:
Albedo
~~~~~~
@@ -300,7 +300,7 @@ then the albedo of the material is used. Using intermediate values generally wor
Clearcoat
~~~~~~~~~
The *clearcoat* parameter is used mostly to add a *secondary* pass of transparent coat to the material. This is very common in car paint and toys.
The *clearcoat* parameter is used mostly to add a *secondary* pass of transparent coat to the material. This is common in car paint and toys.
In practice, it's a smaller specular blob added on top of the existing material.
Anisotropy
@@ -331,7 +331,7 @@ It may not work for complex objets, but it produces a realistic depth effect for
Subsurface Scattering
~~~~~~~~~~~~~~~~~~~~~
This effect emulates light that goes beneath an object's surface, is scattered, and then comes out. It's very useful to make realistic skin, marble, colored liquids, etc.
This effect emulates light that goes beneath an object's surface, is scattered, and then comes out. It's useful to make realistic skin, marble, colored liquids, etc.
.. image:: img/spatial_material21.png
@@ -339,7 +339,7 @@ This effect emulates light that goes beneath an object's surface, is scattered,
Transmission
~~~~~~~~~~~~
Controls how much light from the lit side (visible to light) is transferred to the dark side (opposite side to light). This works very well for thin objects such as tree/plant leaves,
Controls how much light from the lit side (visible to light) is transferred to the dark side (opposite side to light). This works well for thin objects such as tree/plant leaves,
grass, human ears, etc.
.. image:: img/spatial_material22.png
@@ -348,7 +348,7 @@ Refraction
~~~~~~~~~~~
When refraction is enabled, it supersedes alpha blending and Godot attempts to fetch information from behind the object being rendered instead. This allows distorting the transparency
in a way very similar to refraction.
in a way similar to refraction.
.. image:: img/spatial_material23.png
@@ -378,7 +378,7 @@ Proximity and Distance Fade
----------------------------
Godot allows materials to fade by proximity to another, as well as depending on the distance to the viewer.
Proximity fade is very useful for effects such as soft particles, or a mass of water with a smooth blending to the shores.
Proximity fade is useful for effects such as soft particles, or a mass of water with a smooth blending to the shores.
Distance fade is useful for light shafts or indicators that are only present after a given distance.
Keep in mind enabling these enables alpha blending, so abusing them for a whole scene is not generally a good idea.

View File

@@ -6,10 +6,10 @@ Using 3D transforms in Godot
Introduction
------------
If you have never made 3D games before, working with rotations in three dimensions can be very confusing at first.
If you have never made 3D games before, working with rotations in three dimensions can be confusing at first.
Coming from 2D, the natural way of thinking is along the lines of *"Oh, it's just like rotating in 2D, except now rotations happen in X, Y and Z"*.
At first this seems easy and for simple games, this way of thinking may even be enough. Unfortunately, it's very often incorrect.
At first this seems easy and for simple games, this way of thinking may even be enough. Unfortunately, it's often incorrect.
Angles in three dimensions are most commonly referred to as "Euler Angles".
@@ -27,7 +27,7 @@ The idea of this document is to explain why, as well as outlining best practices
Problems of Euler Angles
------------------------
While it may seem very intuitive that each axis has a rotation, the truth is that it's just not practical.
While it may seem intuitive that each axis has a rotation, the truth is that it's just not practical.
Axis Order
==========
@@ -36,7 +36,7 @@ The main reason for this is that there isn't a *unique* way to construct an orie
takes all the angles togehter and produces an actual 3D rotation. The only way an orientation can be produced from angles is to rotate the object angle
by angle, in an *arbitrary order*.
This could be done by first rotating in *X*, then *Y* and then in *Z*. Alternatively, you could first rotate in *Y*, then in *Z* and finally in *X*. Anything really works,
This could be done by first rotating in *X*, then *Y* and then in *Z*. Alternatively, you could first rotate in *Y*, then in *Z* and finally in *X*. Anything works,
but depending on the order, the final orientation of the object will *not necessarily be the same*. Indeed, this means that there are several ways to construct an orientation
from 3 different angles, depending on *the order of the rotations*.
@@ -80,7 +80,7 @@ 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 very 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_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.
Instead, there is a better way to solve your rotation problems.
@@ -385,7 +385,7 @@ Converting a rotation to quaternion is straightforward.
The :ref:`class_Quat` 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 or they also may suffer from numerical precision errors.
Quaternions are very useful when doing camera/path/etc. interpolations, as the result will be always correct and smooth.
Quaternions are useful when doing camera/path/etc. interpolations, as the result will be always correct and smooth.
Transforms are your friend
--------------------------

View File

@@ -20,7 +20,6 @@ structures called "bones". Each "bone" is represented as a Transform, which is
applied to a group of vertices within a mesh. You can directly control a group
of vertices from Godot. For that please reference the :ref:`class_MeshDataTool`
class and its method :ref:`set_vertex_bones <class_MeshDataTool_set_vertex_bones>`.
This class is very powerful.
The "bones" are organized hierarchically, every bone, except for root
bone(s) have a parent. Every bone has an associated name you can use to