Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates to normal and tangent import/export #446

Merged
merged 18 commits into from
Sep 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
cd3b0ef
Changed select_unassigned_polygons to actually select in the original…
Candoran2 May 7, 2021
bd6df57
Changed normal export to take sharp-marked normals into account. Copi…
Candoran2 May 13, 2021
f208d40
Added export of (bi)tangents directly from Blender, rather than gener…
Candoran2 May 23, 2021
afd108e
Fixed issue with edges being marked sharp on import (even though they…
Candoran2 May 24, 2021
9f6bd87
Refactored so that the to_tuple() conversion and normalization is don…
Candoran2 May 24, 2021
9a2872a
Updated code as per PR review. Pulled game out to local variable, ren…
Candoran2 May 26, 2021
c9a5e93
Implemented PR review comments from Hendrix: Renamed variables xxxlis…
Candoran2 May 27, 2021
c4d36d3
Updated documentation for export. Moved custom anchors to above title…
Candoran2 Jun 1, 2021
3303b74
Added Design Decisions document. Added section on why tangents are ex…
Candoran2 Jun 3, 2021
6a96a76
Fixed mistype leading to syntax error.
Candoran2 Jun 16, 2021
e3fa242
Implemented inversion of normal map Y channel to display normals as i…
Candoran2 Jun 16, 2021
8018ff6
Changed collision layer to be game dependent, rather than relying on …
Candoran2 Jul 7, 2021
0848906
Added default NONE game for in the scene tab, and a comprehensive err…
Candoran2 Jul 28, 2021
58c2054
Added game set check to kf export (previously only in nif export).
Candoran2 Aug 30, 2021
7abfce9
Changed texture import so that original nif texture path is preserved…
Candoran2 Aug 30, 2021
f53bc8f
Updated normal map Y-invert code so that the node group does not get …
Candoran2 Aug 30, 2021
16936f2
Removed obsolete part flag storage.
Candoran2 Sep 21, 2021
c7f6ff2
Converted body partitions from using Blender vertex groups to using f…
Candoran2 Sep 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/development/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Contents:
User Interface
--------------

* The user first activates the addon via **File** > **User Preferences** > **Addons**.
* The user first activates the addon via **Edit** > **Preferences** > **Addons**.

.. note::

Expand Down
52 changes: 52 additions & 0 deletions docs/development/design/decisions.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
.. _development-design-decisions:

################
Design Decisions
################

.. _development-design-decisions-geometrydata:

*************
Geometry Data
*************

.. _development-design-decisions-geometrydata-tangents:

Tangents
========

Tangents and bitangents are exported from Blender's tangents. This has two caveats:
* These are not the exact same as those of vanilla (Skyrim) assets.
* These tangents will only work completely correctly with normal maps that were generated with those tangents.
The first point is because we do not yet know by which method the vanilla tangents were generated. It is possible
that the generation method differs per model, and that there is no method which matches all vanilla models.

The second point is true for all tangent space normal maps. For more information on normal maps, see
`http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Tangent_Basis the polycount page`_. For information on how
the tangents get used in calculating surface direction, see
`http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-13-normal-mapping/ the OpenGL tutorial`_. The main
characteristics that need to be the same between the renderer (the game) and the normal map baking software are:
* The tangent direction
* Whether the bitangent is calculated per-vertex or per-pixel (see
`https://bgolus.medium.com/generating-perfect-normal-maps-for-unity-f929e673fc57#c473 this page`_).
Making sure that the tangent space is the same for the baker as it is in the nif is done by exporting a common
tangent space. The tangents from Blender are from `http://www.mikktspace.com/ MikkTSpace`_. This standard tangent space
is also an option in xNormal and Substance.

Because the bitangents are stored in the nif file, it can be assumed that they are not per-pixel in-game. Whether the
bitangent is calculated per-vertex or per-pixel is an option in xNormal and Substance. Blender calculates its bitangent
for baking per-pixel, which means that normal maps baked in Blender will not correctly display in-game, though the
difference may be minimal enough not to notice.

Blender tangent and bitangent to nif tangent and bitangent is not 1:1. In Blender, the tangent points in the positive U
direction and the bitangent points in positive V direction (Blender texture coordinates). In nifs, tangents point in
the positive V direction and bitangents point in the positive U direction (nif texture coordinates). Therefore, tangents
and bitangents are swapped between Blender and nif. However, because the nif V coordinate can be calculated from the
Blender V coordinate via::

nif_V = 1 - blender_V

This means that the direction for positive V coordinate is reversed. This results in the conversion as follows.::

nif_tangent = blender_bitangent
nif_bitangent = blender_tangent
3 changes: 2 additions & 1 deletion docs/user/features/armature/armature.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ Armatures
Armature Bones
==============

* The following section deals with Armatures
* The following section deals with Armatures. Note that, in order for any animations to display in Blender like they
would in-game, ``Preserve Volume`` must be turned off in the Armature modifier.

.. _armature-flags:

Expand Down
9 changes: 5 additions & 4 deletions docs/user/features/geometry/geometry.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Double Sided Mesh

- Adds a :class:`~pyffi.formats.nif.NifFormat.NiStencilProperty` or similiar, see :ref:`Properties - Stencil Property
<properties-stencil>` for more info.
- For Skyrim, tick the Shader Property flag "Double Sided" in the Niftools Shader Panel.

.. _geometry-uv:

Expand Down Expand Up @@ -82,14 +83,14 @@ Vertex Color & Alpha
**Example:**

#. :ref:`Create a mesh-object <geometry-mesh>`.
#. Switch to Vertex Paint mode, this automatically adds a base vertex colour layer. Make sure you name this layer 'RGBA'
#. Apply the desired vertex colours evenly to the vertex.
#. Switch to Vertex Paint mode, this automatically adds a base vertex color layer. Make sure you name this layer 'RGBA'
#. Apply the desired vertex colors evenly to the vertex.
#. You can alter the alpha channel using the 'Add Alpha' and 'Erase Alpha' brushes.

**Notes:**

* The Nif format only supports a single colour per vertex, whereas Blender vertex colour per face vertex.
* The Nif format only supports a single color per vertex, whereas Blender vertex color per face vertex.
* Blender treats the vertex as if the faces had been split apart, each face can have a different colour for that vertex.
* `This image should clarify per-face vertex colouring
<http://i211.photobucket.com/albums/bb189/NifTools/Blender/documentation/per_face_vertex_color.jpg>`_
* On export, the scripts will take an average of colours.
* On export, the scripts will create extra vertices for different vertex colors per face.
90 changes: 55 additions & 35 deletions docs/user/features/iosettings/export.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.. _user-features-iosettings-export:
Export Settings
===============
.. _user-features-iosettings-export:

This section explains the import and export settings.

Expand All @@ -9,26 +9,55 @@ This section explains the import and export settings.
This is due to the fact that they are ported directly from the old addon and as such, will functionally remain the
same.

.. _user-features-iosettings-export-scale:
Scale correction
----------------
.. _user-features-iosettings-export-scale:

This value is used to globally re-scale the Blender system of measurement units to the Nif Format units.

* The ratio of a Nif Units (NU) to Blender Units (BU) is 1Bu:0.1Nu. or each NU is about 10x larger than a BU.
* The Blender Niftools Addon applies a default correction of 10
* The default setting ensures the imported model fits into the view Blender viewport.

.. _user-features-iosettings-export-armature:
Armature
--------

.. _user-features-iosettings-export-flattenskin:
Flatten Skin
^^^^^^^^^^^^

This option should remove the hierarchy of the bones in the exported nif. However, it is currently not used in export.
In order to flatten the hierarchy before export with Blender: Select the bones in object mode, then go into edit mode
and use ``Alt+P`` to unparent the bones with the``Clear Parent`` option.

.. _iosettings-padnsort:
Pad & Sort Bones
^^^^^^^^^^^^^^^^

Adjusts the number of bones in a given partition to match the total number of bones used for the dismember instance.

.. _iosettings-maxpartitionbones:
Max Partition Bones
^^^^^^^^^^^^^^^^^^^

The maximum number of bones that a single dismember partition can use before starting a new partition.

.. _iosettings-maxvertexbones:
Max Vertex Bones
^^^^^^^^^^^^^^^^

The maximum number of bone weight values that can be applied to a single vertex.

.. _user-features-iosettings-export-game:
Game
----
.. _user-features-iosettings-export-game:

A list of supported games which the addon will export working nif files.

Process
.. _user-features-iosettings-export-animation:
Animation
-------
.. _user-features-iosettings-export-process:

Determines how to export the data in the blend file.

Expand All @@ -38,46 +67,37 @@ Export options include
* Geometry only (nif) - Only geometry to a single nif.
* Animation only (kf) - Only animation to a single kf.

Smooth Inter-Object Seams
-------------------------
.. _user-features-iosettings-export-smoothseams:

This option combines the normals data for all vertices containing the same XYZ location data along an edge and uses
the same normal tangent and bi-tangent values for all affected vertices.

Use NiBSAnimationNode
---------------------
.. _iosettings-bsanimationnode:
Use NiBSAnimationNode
^^^^^^^^^^^^^^^^^^^^^

NiBSAnimationNode is specific to "The Elder Scrolls - Morrowind" and should only be used when exporting animated
items for that game.

Flatten Skin
------------
.. _user-features-iosettings-export-flattenskin:

This option does something to the thing, no really it does, but I can't tell you because it's a sekret.

Pad & Sort Bones
----------------
.. _iosettings-padnsort:

Adjusts the number of bones in a given partition to match the total number of bones used for the dismember instance.
.. _user-features-io_settings-export-optimise:
Optimise
--------

Max Partition Bones
-------------------
.. _iosettings-maxpartitionbones:
.. _user-features-io_settings-export-stripifygeometries:
Stripify Geometries
^^^^^^^^^^^^^^^^^^^

The maximum number of bones that a single dismember partition can use before starting a new partition.
Export with NiTriStrips instead of NiTriShapes.

Max Vertex Bones
----------------
.. _iosettings-maxvertexbones:
.. _user-features-iosettings-export-stitchstrips:
Stitch Strips
^^^^^^^^^^^^^

The maximum number of bone weight values that can be applied to a single vertex.
Whether to stitch NiTriStrips (if they are used). Important for Civilization IV.

Force DDS
---------
.. _user-features-iosettings-export-forcedds:
Force DDS
^^^^^^^^^

Changes the suffix for the texture file path in the nif to use .dds

.. _user-features-io_settings-export-optimisematerials:
Optimise Materials
^^^^^^^^^^^^^^^^^^

Remove duplicate materials. Currently not used.
3 changes: 2 additions & 1 deletion docs/user/features/properties/shader/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,8 @@ BS Effect Shader Property

.. Describe this type

Skyrim non-PP shader model, used primarily for transparency effects, often as a decal.
Skyrim non-PP shader model, used primarily for transparency effects, often as a decal. Has the same shader flags as
BSLightingShaderProperty.

+-------------------------------+---------------------------------------------------------------+
| Property | Description |
Expand Down
3 changes: 3 additions & 0 deletions io_scene_niftools/kf_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ def execute(self):
directory = os.path.dirname(NifOp.props.filepath)
filebase, fileext = os.path.splitext(os.path.basename(NifOp.props.filepath))

if bpy.context.scene.niftools_scene.game == 'NONE':
raise NifError("You have not selected a game. Please select a game in the scene tab.")

prefix = "x" if bpy.context.scene.niftools_scene.game in ('MORROWIND',) else ""
self.version, data = scene.get_version_data()
# todo[anim] - change to KfData, but create_controller() [and maybe more] has to be updated first
Expand Down
10 changes: 5 additions & 5 deletions io_scene_niftools/modules/nif_export/collision/havok.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def export_collision_helper(self, b_obj, parent_block):

# linear_velocity = b_obj.rigid_body.deactivate_linear_velocity
# angular_velocity = b_obj.rigid_body.deactivate_angular_velocity
layer = b_obj.nifcollision.oblivion_layer
layer = int(b_obj.nifcollision.collision_layer)

# TODO [object][collision][flags] export bsxFlags
# self.export_bsx_upb_flags(b_obj, parent_block)
Expand All @@ -100,7 +100,7 @@ def export_collision_helper(self, b_obj, parent_block):
# bhkCollisionObject -> bhkRigidBody
if not parent_block.collision_object:
# note: collision settings are taken from lowerclasschair01.nif
if layer == "OL_BIPED":
if layer == NifFormat.OblivionLayer.OL_BIPED:
# special collision object for creatures
n_col_obj = self.export_bhk_blend_collision(b_obj)

Expand Down Expand Up @@ -135,7 +135,7 @@ def export_bhk_rigid_body(self, b_obj, n_col_obj):

n_r_body = block_store.create_block("bhkRigidBody", b_obj)
n_col_obj.body = n_r_body
n_r_body.layer = getattr(NifFormat.OblivionLayer, b_obj.nifcollision.oblivion_layer)
n_r_body.layer = int(b_obj.nifcollision.collision_layer)
n_r_body.col_filter = b_obj.nifcollision.col_filter
n_r_body.unknown_short = 0
n_r_body.unknown_int_1 = 0
Expand Down Expand Up @@ -185,11 +185,11 @@ def export_bhk_rigid_body(self, b_obj, n_col_obj):
return n_r_body

def export_bhk_collison_object(self, b_obj):
layer = b_obj.nifcollision.oblivion_layer
layer = int(b_obj.nifcollision.collision_layer)
col_filter = b_obj.nifcollision.col_filter

n_col_obj = block_store.create_block("bhkCollisionObject", b_obj)
if layer == "OL_ANIM_STATIC" and col_filter != 128:
if layer == NifFormat.OblivionLayer.OL_ANIM_STATIC and col_filter != 128:
# animated collision requires flags = 41
# unless it is a constrainted but not keyframed object
n_col_obj.flags = 41
Expand Down
Loading