MB-Lab icon indicating copy to clipboard operation
MB-Lab copied to clipboard

Morphs creation (Copy/Move/Delete/Rename/Backup morphs tool done)

Open TetoTheSquirrelFox opened this issue 4 years ago • 58 comments

So, I try to help by making tools to create like morphs (or muscle if I can figure how it works).

But I had to answer few questions first :

  • What is the scope ?
  • When can the user create morphs ?
  • Where are tools on the panel, are they available all the time ?
  • When can we lunch ?

So what I think about that:

  • To be able to create good morphs that can be used everywhere, user must starts with the basic shape of one of the 4 big types available in MB-Lab : male, female, anime male, anime female. So, to start with something, I created a “Base female f_NO01” (file characters_config.json) that has no phenotype, no race, and is the base model that used Manuel.
  • I also gave to this model a basic albedo.png that looks like clay. Not very good, but well...
  • Then I gave it no morphs, no phenotype, nothing. So it’s the most basic model we can have.
  • I also created dedicated directory for this type (\data\presets\none_female_base) with no file.
  • For me it’s the model user must use to make his own morphs for all female models (realistic female here)

You can see the content in characters_config here: "f_no01": { "description": "Generate a base female character for creating morphs", "template_model": "MBLab_human_female", "name": "f_no01", "label": "Base female (F_NO01) (AGPL3)", ... "texture_sclera_mask" : "sclera_mask.png", "morphs_extra_file": "", "shared_morphs_file": "", "shared_morphs_extra_file": "", "bounding_boxes_file": "human_female_bbox.json", ... "vertexgroup_base_file": "human_female_vgroups_base.json", "vertexgroup_muscle_file": "human_female_vgroups_muscles.json" }

Problem is that some morphs could be very specific to a race or a phenotype, and could not work properly in all models for a reason. So I decided that user could use the model he wants, and create his own morphs while other morphs are already used. To assure that, I put the “morphs editor” in the Pre-Finalized State session (gui_status == "ACTIVE_SESSION") and put it between “random generator” and “measures”. So, for the user who chooses “F_NO01” he can create, and for the others he can use other morphs as well.

So, as MB_Lab is not designed to create bodies from scratch, but more to use what it is available, I tried to be as simple as possible, while let the user to have the most useful tool to create new morphs.

So now here are the problems I’m facing :

  • Let’s take the model f_ca01 in characters_config.json. Few lines are dedicated to the morphs. "name": "f_ca01", "morphs_extra_file": "", "shared_morphs_file": "human_female_morphs.json", "shared_morphs_extra_file": "human_female_morphs_extra.json",
  • shared_morphs_file & shared_morphs_extra_file are basic morphs shared by all phenotype from female Caucasian. (extra_files is for fantasy, basically). Here it’s simple, all females share the same files. But it could be something else.
  • f_ca01 allows to use morphs that are dedicated to the type (female Caucasian) and the files need to be in the proper format for its name: “f_ca01_whatever_optionalWhatever.json”
  • More important: under those files, a same morph is split in two, for minimum values and maximum. Each morph end with _min or _max, so the engine can construct the final morph, from 0 to 1 (0,5 is the model before morphing).
  • morphs_extra_file: I think that the intent was to allow user morphs shared buy a whole type?
  • So under the directory \data\morphs you have 2 types of files, the ones who are dedicated to a whole range of human (male, female, anime male, anime female) and the others dedicated to types, and it seems that we can add all files we want if they are properly named.

At first, the tool would have looked like this (on the panel):

  • Create base model → copy all vertex from actual model shown, whatever it is.
  • Load base model → Load an old model.
  • Load work-in-progress → Load a model for a morph in progress.
  • Reset models → reload work-in-progress model.
  • Morph type → a list where we can choose if the morph will be for one type in particular or for a whole range.
  • Body type → Male or female.
  • Type name → (for example) an02
  • Type name extra → none or a name like the pseudo of the author.
  • Morph name → A name for the morph.
  • Min or Max → the target morph is for min values or max.
  • Save work-in-progress → Save all actual model as a work-in-progress.
  • Quick save → No dialog, take the name, add _min or _max, and _000 (or _001, _002, …) and save the morph, aka the vertices that are their location changed.
  • Save final morph: Same thing, but we have to choose min and max files, and the file is properly saved in the dedicated directory.

But, first I wanted to have my own models, copies of the ones used by the engine, but after a while I started to think that it was not good. The engine is complex, and I should keep a coherence with it. The model the user is working on is linked to the engine, so let’s keep it that way. And the engine has already many useful tools like reset, loading, saving… So, if the user wants making morphs from base model, no problem, he can use the “reset character” button. If he wants to create while character already has morphs applied, he can use ‘import/export character”.

So now the tool looks like this :

  • Morph type → a list where we can choose if the morph will be for one type in particular or for a whole range.
  • Body type → Male or female.
  • Type name → (for example) an02
  • Type name extra → none or a name like the pseudo of the author.
  • Morph name → A name for the morph.
  • Min or Max → the target morph is for min values or max.
  • Load work-in-progress → Load a model for a morph in progress.
  • Save work in progress→ No dialog, take the name, add _min or _max, and _000 (or _001, _002, …) and save the morph, aka the vertices that are their location changed.
  • Save final morph: Same thing, but we have to choose min and max files, and the file is properly saved in the dedicated directory.

The workflow would look like this :

  • I choose for what type the morph is for. → Type name = as01
  • Morphs are already existing for the model, so I write my pseudo for save files → Type name extra = Teto
  • Morph is for this model → Morph type = dedicated
  • For female → Body type = female
  • I’m sculpting for min values → Min or Max = min.
  • I do my stuff → Save work-in-progress 4 or 5 times.
  • It’s done, same thing for Max values.
  • It’s done. Save the morph. The file name is automatic, I just have to choose the proper file for min and max values. The file is saved in the dedicated directory. If the file already exists, the morph is added in the file. If the name of the morph already exists, the new one replaces the old one.

I’m working on it now, and if you agree, I’d like to make a morph.py dedicated for this, so the changes in other .py files would be minimal. I’d like to talk about the work in progress here too.

TetoTheSquirrelFox avatar Jan 12 '20 14:01 TetoTheSquirrelFox

Quite impressive! I will have to read this over again as I only read through it once but so far what I see I like.

Of course making a new morph Python script would be ideal.

We can make this a project for the next version perhaps?

animate1978 avatar Jan 12 '20 14:01 animate1978

Thanks. ^^

About a new project, why not, but I'd like to be sure that what I'm doing goes somewhere. For now I'll change the existing python files to "prepare" the creation tools, and will post the changes here.

TetoTheSquirrelFox avatar Jan 12 '20 17:01 TetoTheSquirrelFox

image Now, first thing to do is to store a copy of the body (all vertices to be more specific) because after sculpting the morph, I need to compare with a base, and as the actual body has changed, I need an untouched body to compare with.

But I can't write body_as_a_base = actual_body, I suppose, and I must something like body_as_a_base = actual_body.duplicate() and make a real copy, not an instance. I'll on this tomorrow. And I think that will help me for comparing 2 body objects.

By the way, about the classes I'm modifying : the changed code is always between #Teto and #End Teto So when it will be done, I will be able to send the files to you and it will be easy (I guess) to change the files in master. Please tell me if I'm wrong.

TetoTheSquirrelFox avatar Jan 13 '20 20:01 TetoTheSquirrelFox

I'm not sure, but you might want to make a bmesh copy to sculpt, then bake it back to the original mesh. I do think that you can obtain the un_modified coordinates the same way you access the "current" coordinates, but I've never actually used those.

On Mon, Jan 13, 2020, 3:43 PM TetoTheSquirrelFox [email protected] wrote:

[image: image] https://user-images.githubusercontent.com/59537161/72289918-6cdc1b00-364c-11ea-80cd-6db8925675e0.png Now, first thing to do is to store a copy of the body (all vertices to be more specific) because after sculpting the morph, I need to compare with a base, and as the actual body has changed, I need an untouched body to compare with.

But I can't write body_as_a_base = actual_body, I suppose, and I must something like body_as_a_base = actual_body.duplicate() and make a real copy, not an instance. I'll on this tomorrow. And I think that will help me for comparing 2 body objects.

By the way, about the classes I'm modifying : the changed code is always between #Teto and #End Teto So when it will be done, I will be able to send the files to you and it will be easy (I guess) to change the files in master. Please tell me if I'm wrong.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/animate1978/MB-Lab/issues/226?email_source=notifications&email_token=AKYHC3XRPNKH7TUN4GVU4MTQ5TG63A5CNFSM4KFX5YB2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEI2G24Q#issuecomment-573861234, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKYHC3UFGXVKB2TBDEANNQLQ5TG63ANCNFSM4KFX5YBQ .

Noizirom avatar Jan 15 '20 11:01 Noizirom

No no, it's waaaaay simpler than that. ^^ Actually I want to make a copy of the vertices of the shown model. And a python program already exists for this (it writes in a file, I just want to make a special object that stores the vertices). After that, user does his thing with Blender sculpt tools (without touching the number/name/id of vertices of course). And at the end the tool checks just the differences between the base and the sculpted, then write them in a json file in order to be a regular morph.

So no, I don't "touch" anything in the model, I just check the differences between 2 states of a same model that is entirely handled by the engine (which is complex, like, really complex).

TetoTheSquirrelFox avatar Jan 15 '20 19:01 TetoTheSquirrelFox

A file called co_to_js.py will put vertices of a selected object into a .json file. https://github.com/Noizirom/Blender-Python-Tool

On Wed, Jan 15, 2020, 2:26 PM TetoTheSquirrelFox [email protected] wrote:

No no, it's waaaaay simpler than that. ^^ Actually I want to make a copy of the vertices of the shown model. And a python program already exists for this (it writes in a file, I just want to make a special object that stores the vertices). After that, user does his thing with Blender sculpt tools (without touching the number/name/id of vertices of course). And at the end the tool checks just the differences between the base and the sculpted, then write them in a json file in order to be a regular morph.

So no, I don't "touch" anything in the model, I just check the differences between 2 states of a same model that is entirely handled by the engine (which is complex, like, really complex).

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/animate1978/MB-Lab/issues/226?email_source=notifications&email_token=AKYHC3UUCKPIWAQQWLWM64TQ55PNDA5CNFSM4KFX5YB2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEJBQEBA#issuecomment-574816772, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKYHC3RET2UVD2APDZ6UUITQ55PNDANCNFSM4KFX5YBQ .

Noizirom avatar Jan 15 '20 23:01 Noizirom

I'm not quite sure what your asking , being that you've already found an addon for this.

On Wed, Jan 15, 2020, 6:37 PM Zion Hill Hill [email protected] wrote:

A file called co_to_js.py will put vertices of a selected object into a .json file. https://github.com/Noizirom/Blender-Python-Tool

On Wed, Jan 15, 2020, 2:26 PM TetoTheSquirrelFox [email protected] wrote:

No no, it's waaaaay simpler than that. ^^ Actually I want to make a copy of the vertices of the shown model. And a python program already exists for this (it writes in a file, I just want to make a special object that stores the vertices). After that, user does his thing with Blender sculpt tools (without touching the number/name/id of vertices of course). And at the end the tool checks just the differences between the base and the sculpted, then write them in a json file in order to be a regular morph.

So no, I don't "touch" anything in the model, I just check the differences between 2 states of a same model that is entirely handled by the engine (which is complex, like, really complex).

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/animate1978/MB-Lab/issues/226?email_source=notifications&email_token=AKYHC3UUCKPIWAQQWLWM64TQ55PNDA5CNFSM4KFX5YB2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEJBQEBA#issuecomment-574816772, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKYHC3RET2UVD2APDZ6UUITQ55PNDANCNFSM4KFX5YBQ .

Noizirom avatar Jan 15 '20 23:01 Noizirom

Nope, it's this file.

TetoTheSquirrelFox avatar Jan 16 '20 16:01 TetoTheSquirrelFox

Quick update : image Now the UI is done. I think that if the thing is finished, I will have to change things here and there, but for now I need something working for users.

TetoTheSquirrelFox avatar Jan 19 '20 14:01 TetoTheSquirrelFox

Great great news today ! ^^

I copied the great co_to_js.py int the class that is executed when user clicks on button "Store actual body vertices". I had to change things because python is handled differently when used in console and inside the plugin. So after changed every line because of this ^^, I did this :

  • I stored in a file the body shown on screen, after have created it.
  • on "Edit mode", I changed 1 vertex (somewhere on the arm) with mirror enabled, so the other arm changed accordingly.
  • Store the body again.
  • So now I have 2 .json files, that I open with Notepad++
  • I compare them (it's easy, Notepad++ has a module made for) And voilà ! Only 2 vertices changed in the file : image image The colors are ugly but that's not the point. On left, base body.

I was worried before the try, because I feared that the data stored by MB-Lab were not the data used by Blender. So if I changed something in the body (by using sculpt tools for example), the changes would not be "seen" in MB-Lab objects. I don't know if I'm clear. Anyway, it's not the case, that is good for me.

So, now I know that it works, animate1978, the thing can be a project now ? Anyway, I have a lot of work to do.

  • First, be able to do the comparison in the engine, not very difficult I think, I know how to do this, I just have to collect the index of each changed vertex, and do a subtraction "new - old" and store the result in a json file.
  • This way, the tool would be barely usable for users.
  • And then I'd work to make the tool really useful, like allow to write many morphs in one file, manage directories for users morphs, and to the stuff written above.

Stay tuned ! Teto.

TetoTheSquirrelFox avatar Jan 20 '20 19:01 TetoTheSquirrelFox

It's working ! So what I did today : having a full comparison between 2 lists of vertices, with index, in order to be saved. I took one character, stored its vertices. Disabled smoothing. image Went to Edit mode, changed 1 vertex (2, because symmetric edition) image Asked for the result and voilà ! image Not sure yet, but I think that the indexes are good. Now it's not over. What I have to do

  • Seems that when I reset the character, and try again, Blender doesn't like at all. But doing things, store, doing other things, store, and so on, then finalize the differences works well.
  • I have to save it in a file, with proper name. Manuel didn't reinvent the wheel, and uses strictly json library for that purpose, so it seems I just have to make a dictionary with keys (the name of the morph) and values (the changes) to write a file in the good format. I'm on it.

TetoTheSquirrelFox avatar Jan 28 '20 20:01 TetoTheSquirrelFox

Now I'm almost there. image As you can see, the UI changed a lot, and many parts of the name or the morphs can't be changed because they are dependent of the model.

The only thing that I have to do is to put data in an opened json, add or replace morphs, and save it. For the moment, if a morph already exists, it is replaced. Everything else seems to work.

TetoTheSquirrelFox avatar Feb 02 '20 20:02 TetoTheSquirrelFox

So V0.95 is done, is working (I hope) and was sent to Animate1978 for approval.

So what is it now ? It's a tool that allows the user to make his own morphs, based on the model he chose .

  • The modifications can be made for the whole gender he's working on (human female, realistic anime male, ...) of for a particular type (male Asian, female Caucasian, and so on)
  • the tool is able to do autosaves, and file names have rules in order to be understood by engine when they are loaded. The tools provides mechanisms to avoid wrong naming.
  • The tool has unfortunately limitations.
  • The author is not fully fluent in english. Feel free to comment/correct the words used for the UI. ^^

The tool : It changed a lot since I started to code. From something with many things to write before to be able to save the work, it's something now very straightforward, as the name (for the morph, for the file) must follow strict rules. However, now the engine can load many files for morphs as you want. Before this tool it was just 5 : shared morphs (for a gender), shared morphs extra, and a third one (not used by the engine), plus 2 other files for morphs specific to body types. Now with the tool you can add any files you want, the ones you made and the ones made by others.

So, what have we get ? Once the base character is made, you can choose the Morphs Creator tool and you have this: image Here is a rapid view of functions:

  1. Store base body vertices : The base model you're working on. Button to press before any change in vertices.
  2. Morph wording - Body parts -> Label for the content below.
  3. Body part : image Fun fact, it seem that we can have any body parts we want. But for the sake of sanity, I just used the standard.
  4. Name : Name of the morph. the tip shows the format. MyOwnMorph01 for example.
  5. min/max : If it's for min values of the morph, or max values. There are other values available (seen in some files) but I don't know what it's about. By the way, a morph can have just a min (or just a max), the engine doesn't mind and works well.
  6. Morph wording - File -> Label for the content below.
  7. Spectrum. whole gender or specific to a body type. Important : labels below show the name of the file, depending of your choice. And yes, you can save for both types (see below).
  8. Ethnic group : If empty, the one used by base model is used as name. If not, it overrides the base name. image
  9. Extra name : Basically the name of the author, but can be something else to separate morphs files.
  10. Autosave : If enabled, each time you save the file, a new file like m_zz99_morphs_pseudo_001.json (002, ... 999) is created with the morph. The count is reset for each session. And take care to move the files somewhere else after closing Blender to avoid overload.
  11. Quick-save work-in-progress. A little explanation here. You can change the shape of the model in edit mode or sculpt mode, but don't forget to disable 2 things : image DON'T change the index/name/number of vertices. NEVER. You just can change their location. When it's done, you can press the button. After that you can change things (or save with autosave), and press the button again, no problem.
  12. Finalize the morph. At last you save the morph :
  • If the file name is an existing file -> the file is opened, and if the morph already exists, it is replaced. So caution with standards files. Otherwise, the new morph is added.
  • If the file doesn't exist, it's created, and the morph added.
  • So, by changing gender, ethnic group or extra name, you can quickly add the same morph to many files.
  • For a morph with min and max, you have to do the work twice.
  • Important note : if the base model is not saved, or the changed model, nothing happens and a warning is shown. The morph is not saved either if the changes are too small. The engine doesn't count changes under 0.0001. So don't be alarmed if you sculpted a subtle detail but is not taken in account : it's just too small for the engine (and I didn't want to change that. Short story, the display of the number becomes scientific, like 1e-5 and Manuel didn't want to have this written in file, I guess).

Limitations :

  • There are no tools for files management. Well, not for the moment, because it's a lot of work for something not very useful (in my opinion). json files are human readable. When you know the structure, you can do many things manually. Maybe later. ^^
  • The model should be always selected. I saw weird things when I lost selection because I selected the lamp or something. Basically, use the tool with just one model displayed : the MB_lab body.

Typical workflow :

  • Create a base model.
  • Save it by "Store base body vertices" button.
  • Create a morph for min values. (and maybe save steps)
  • Press save work-in-progress button.
  • Save the file.
  • Reset the model. image
  • Create the morph for max values.
  • Press save work-in-progress button.
  • Save it in the same file.
  • Exit Blender
  • Open Blender, re-create the same model if morph was made for a specific body, of same gender otherwise.
  • Check Body measures, and the part where the morphs is stored.
  • Profit.

I wrote the main things to know I think. Don't hesitate to comment. Teto.

Edit : And by the way, many many many thanks to the guy(s) who wrote the program "co_to_js.py". Without it, I think that none of this would have existed.

TetoTheSquirrelFox avatar Feb 04 '20 20:02 TetoTheSquirrelFox

I just read the email, I have downloaded the sources and after work tonight I will go through and test this.

This is a pretty big deal, I was kind of waiting for this to come into being before I did any other work (aside from my own personal life being very busy atm)

I will also go through this issue and read through it so I can start developing some documentation.

animate1978 avatar Feb 05 '20 16:02 animate1978

OK, So I had an idea this morning and was able to make it this evening. image So you can see 3 tools under "finalize the morph" :

  1. The first save all vertices of the actual body shown on screen.
  2. You can load a model and use it as a base model (you don't see the result, there's no update, sorry).
  3. The same for sculpted body.

What is the interest?

  • If you have to leave but you are finished your new sculpt, you can save all data to build the morph.
  • I put a "proof of concept" here. Put this unzipped morph under your C:\Users\YourName\AppData\Roaming\Blender Foundation\Blender\2.81\scripts\addons\MB-Lab-dev\data\morphs. Create a female african (f_af01), under image Try the Morph "try". Enjoy.

Animate1978, I've just sent to you the modified files by mail.

f_af01_morphs_teto.zip

TetoTheSquirrelFox avatar Feb 05 '20 21:02 TetoTheSquirrelFox

I have added the code to my local copy, right now just checking it out, I still have to fully read through and test it but so far no outstanding bugs.

animate1978 avatar Feb 06 '20 14:02 animate1978

It has been committed now

animate1978 avatar Feb 06 '20 16:02 animate1978

https://github.com/animate1978/MB-Lab/blob/73072b27f07c68c474dec4a60c5030a2b09fdc0a/morphcreator.py#L225

This is causing the tester on GitHub to fail.

Lint with flake8
5s
##[error]Process completed with exit code 1.
Run pip install flake8
  pip install flake8
  # stop the build if there are Python syntax errors or undefined names
  flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
  # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
  flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
  shell: /bin/bash -e {0}
  env:
    pythonLocation: /opt/hostedtoolcache/Python/3.6.10/x64
Collecting flake8
  Downloading flake8-3.7.9-py2.py3-none-any.whl (69 kB)
Collecting entrypoints<0.4.0,>=0.3.0
  Downloading entrypoints-0.3-py2.py3-none-any.whl (11 kB)
Collecting pycodestyle<2.6.0,>=2.5.0
  Downloading pycodestyle-2.5.0-py2.py3-none-any.whl (51 kB)
Collecting pyflakes<2.2.0,>=2.1.0
  Downloading pyflakes-2.1.1-py2.py3-none-any.whl (59 kB)
Collecting mccabe<0.7.0,>=0.6.0
  Downloading mccabe-0.6.1-py2.py3-none-any.whl (8.6 kB)
Installing collected packages: entrypoints, pycodestyle, pyflakes, mccabe, flake8
Successfully installed entrypoints-0.3 flake8-3.7.9 mccabe-0.6.1 pycodestyle-2.5.0 pyflakes-2.1.1
./morphcreator.py:225:70: F821 undefined name 'simple_path'
    logger.info("Looking for the retarget data in the folder %s...", simple_path(data_dir))
                                                                     ^
1     F821 undefined name 'simple_path'
1
##[error]Process completed with exit code 1.

I will look into it when I can

animate1978 avatar Feb 06 '20 16:02 animate1978

OK, I did a copy/paste and forgot to erase simple_path. So the line becomes :

logger.info("Looking for the retarget data in the folder %s...", data_dir)

And I remember : the method is not used , you can delete it. ^^

TetoTheSquirrelFox avatar Feb 06 '20 21:02 TetoTheSquirrelFox

OK. I am working on some documentation for this, we should also do some tutorials as well because I think this opens up a lot for people. This also opens up the door to a new model which I would like to start with this one as a prototype...

https://github.com/animate1978/MB-Lab/issues/161

I was successful to a point....

https://vimeo.com/359182294

I think if a workflow could be established, this model exported correctly (I think it was a weight paint issue) and then work on some morphs as a proof of concept before we go jumping in to making "production" models.

I have yet to fully test because I have not had time yet I plan on doing some this weekend.

animate1978 avatar Feb 07 '20 17:02 animate1978

OK. I've watched your video and it reminded me something. So I may be wrong, but I don't think that weight painting is the source of the problem. Groups of vertices just don't move. And the step between full move / no move is too small, and too binary. The vertex move or not. So what I'm guessing :

  1. It's a problem of vertices groups. It seems that muscles are attached to vertices by vertices groups. Your vertices could be attached to wrong group, like the fingers are attached to muscles for face ? But more I think about it, the more I think I'm wrong.
  2. But I think more about a problem of the deforming cage used to deform correctly the model when we deform it for poses. If a vertex or a group of vertices are outside this cage, they just don't move :

image here an example shown with Blenrig. Maybe I'm wrong, I don't know if MB-Lab uses a deform cage, but it really looks like it has this problem.

TetoTheSquirrelFox avatar Feb 07 '20 19:02 TetoTheSquirrelFox

I've just figured out that one method in morphcreator is really dirty. So, in method get_all_files (line 254) instead of :

    dir = data_path + "\\" + data_type_path
    list_dir = os.listdir(dir)
    found_files = []
    split_one = ""
    split_two = ""
    for i in range(len(list_dir)):
        if list_dir[i] != body_type and list_dir[i].count("extra") < 1:
            split_one = list_dir[i].split('_')
            split_two = body_type.split('_')
            if split_one[0] == split_two[0] and split_one[1] == split_two[1]:
                found_files += [dir + "\\" + list_dir[i]]    
    return found_files

that is just ugly, we should have :

    dir = os.path.join(data_path, data_type_path)
    list_dir = os.listdir(dir)
    found_files = []
    split_one = ""
    split_two = ""
    for i in range(len(list_dir)):
        if list_dir[i] != body_type and list_dir[i].count("extra") < 1:
            split_one = list_dir[i].split('_')
            split_two = body_type.split('_')
            if split_one[0] == split_two[0] and split_one[1] == split_two[1]:
                found_files += [os.path.join(dir, list_dir[i])]   
    return found_files

Much better.

And same thing in init.py, line 1052 :

file_path_name = file_ops.get_data_path() + "\\morphs\\" + file_name + ".json"

must become:

file_path_name = os.path.join(file_ops.get_data_path(), "morphs", file_name + ".json")

TetoTheSquirrelFox avatar Feb 08 '20 20:02 TetoTheSquirrelFox

How about this:

    dir = os.path.join(data_path, data_type_path)
    found_files = []
    body_type_split = body_type.split('_')[:2]
    for item in os.listdir(dir):
        if item != body_type and item.count("extra") < 1:
            if item.split('_')[:2] == body_type_split:
                found_files.append(os.path.join(dir, item))
    return found_files

ldo avatar Feb 08 '20 23:02 ldo

Equality can work between indexes of a list like this way ? I take it! ^^ Thanks for the tip.

Edit : And I understood the rest when copying it. Not fluent in Python....

TetoTheSquirrelFox avatar Feb 09 '20 07:02 TetoTheSquirrelFox

On a side note, I discovered that the method load_json_data in files_ops.py is equal to my load_morphs_file now. I did my own method because the one from Manuel opens a file in read-only. But at the time I didn't want that because I wanted to create the file if it didn't exist. It seems that it is created anyway, so my method is useless now. Delete it.

Also, my method save_morphs_file is "perfect" for any kind of data we want to be saved in a file. So I renamed it, and put it in file_ops.py, as it's a method that will be used for many other things soon... ^^

TetoTheSquirrelFox avatar Feb 09 '20 07:02 TetoTheSquirrelFox

Animate1978, in my fork, I've just committed few changes in morphengine.py, and they are needed to allow the engine to read and load morphs created by users. I didn't see the changes in your dev branch (that I forked).

TetoTheSquirrelFox avatar Feb 09 '20 16:02 TetoTheSquirrelFox

Damn. Good news and bad news.

Bad news : The morph editor is not finished yet. Like, at all. Good news : I know now why there are methods that I didn't understand the purpose, why they exist, and how Manuel handled overlapping morphs in order to have nice deformations any time.

Short story : As I tried things tonight to separate base expressions morphs to regular morphs (for body), I was shocked about morph names that had a bizarre name like "Torso_BreastMass-BreastTone-Mass-Tone_max-max-min-min" What ?!? The first part (Torso) is OK, it's about the torso, no problem. But "BreastMass-BreastTone-Mass-Tone". I quickly understood that in fact it's about 4 morphs in 1, aka a combined morph. So "max-max-min-min" is about the min/max of each part. So I checked this (in human_female_morphs.json). And I found this : "Torso_BreastMass-BreastTone-Mass-Tone_min-min-min-min": "Torso_BreastMass-BreastTone-Mass-Tone_min-min-min-max": ... "Torso_BreastMass-BreastTone-Mass-Tone_max-max-max-min": "Torso_BreastMass-BreastTone-Mass-Tone_max-max-max-max": 16 combined morphs that are a combination of 4 "simple" morphs (and they displayed separately in Blender, like regular morphs, it's not an "all in one") and min/max values, so 16 morphs in total.

Useful to know, for later : Manuel uses 2 subclasses in humanoid:

  1. HumanCategory : Keeps all parts of a body, as a category. Arm, body, leg, and so on.
  2. HumanModifier : A modifier is a body part that belongs to a Category, with all properties needed to keep the morphs and apply them to a model.

So, some Modifiers keep properties for 1, 2 or 4 parts (the biggest I found), some parts can even be in multiple modifiers (for example, BreastMass is in a Torso_"BreastMass-BreastTone-Mass-Tone", as already said, but also "Torso_BreastMass-BreastScaleY", "Torso_BreastMass-BreastPosX" and so on. One thing that can't be mixed, is the category. all BreastMass combinations are in Torso, no other category.

So, after few research about the methods/object that use those 2 sub-classes, I think this : The combined morphs is to assure that all body parts involved are morphing nicely, and combination of a huge part, for example, and a tiny one, in the extremes, gives something believable, not ugly or weird.

But for me, and I don't like that, ^^ that also means that I have to add a new editor : "combined morphs creator" and rename the actual "simple morph creator"

I'll do the new tool when the new model will be done, or if I code it before, it will be useful only with new models that have no morph. The tool will be easy to do (I 'm thinking about it while writing), because basically what I have to do is to dispatch all simple morphs of a category, the user sculpt all combinations, save them (like the existing tool), and when it's done, he deletes the base morphs used to create combinations. The name will be automatic, as usual, and I imagine that the engine will do the rest. Note : The method where we can see how a morph name is split and put in category and modifier is "init_character_data(self, morph_name)" in humanoid.

Good night ! ^^ Teto.

TetoTheSquirrelFox avatar Feb 27 '20 20:02 TetoTheSquirrelFox

OK, the work is not finished yet, but I'm getting something. So my work this week-end was about the Combined Morph Creation, as explained above. What's going on for now ?

  1. I reorganized the whole tab a little, and has 3 parts. 1st the 2 main categories, editing model and create model. 2nd is about tools available while editing/creating model. 3rd is the content of the selected tool. image

  2. If a compatible model is not selected, you can't do anything, you're stuck. image

  3. About the Combined Morph Creation, it's a complete (well, for the moment, buttons for saving are missing) tool that allow you to create combined morphs from simple morphs : image The image here shows the max combination we can do.

  4. Something important : you can't create a combined morph if simple morphs are already combined morphs (in file). For example here; all morphs I want to use are actually used in combined morphs somewhere. So you can't use them to create a new one. I'll explain the workflow in next post.

  5. Since morphs are compatible, you can create your combined morph : image It works exactly like Simple Morph Creator. The name is automatic (and long), you choose if it's for a whole gender or specific to an ethnic body. You add an extra name (important here, see next post about that), and when your sculpt is done you can save.

  6. Note : I'll add a button to update the character. When clicked, all values of selected morphs will be put in min/max values according the choice made. Then you sculpt the model, store the modification, and save them if you're satisfied with your work. No difficulty here.

So in the next post I talk about the workflow, guidelines (I think) for creating the morphs of a model. (it's for future documentation, that's why it's a separated post). I'll edit it sometimes, with images and stuff.

TetoTheSquirrelFox avatar Mar 08 '20 21:03 TetoTheSquirrelFox

What is the workflow to create morphs to a model ?

First, what is a morph ? A morph is a group of vectors that move vertices they are attached on. Each morph corresponds to a specific body part, and the name explains what it does. For example Torso-SizeX is a morph that change the size of the torso along the X axis. The first part of the name is the category where the morph is. A same morph can't be in 2 different categories. And each morph has a minimum value(0) and a maximum (1). For the moment we can't exceed theses values.

Different types of morphs ? For the user, no. They don't exist after finalization, except for the morphs involved in face expressions, they are changed in shapekeys, and used to create expressions like angry, or happy.

For the creator, it's different, you have 2 types.

  1. Simple Morphs : They change the size/position/shape of a body part, and they don't overlap other morphs too much (or it doesn't matter, the result fits well in any case).
  2. Combined morphs : You see them as simple morphs when you morph a model as an user, but in reality they overlap each over so much that the result would be weird or ugly if they would stay simple morphs. For example, a torso can be fat, athletic, normal, and so on. The tone of the torso has consequences on the mass, etc. So the morphs can't be separated, they must be combined to always work nicely. More about this below.

So, what is the general workflow when creating morphs ?

  1. After the creation of the model, and when all vertices are frozen, you will use mainly 2 editors to create morphs, "Simple Morph Creation" and "Combined Morph Creation".
  2. First thing to do is to choose wisely all the morphs you want to create and try to have a complete list before starting to sculpt.
  3. In this list try to separate the morphs that will stay simple and the ones that will be combined. After a while, changing will be difficult and source of problems.
  4. Read the documentation to know about the use of the tools. But, basically, you'll create 2 files for your morphs. 4.1. The main file where you put your simple morphs, and your combined morphs. 4.2. and intermediary file where you store the simple morphs that are used to create the combined morphs.

The workflow for creating combined morphs :

  1. You create a dedicated file where you store every simple morphs that you want to use to create combined morphs.
  2. You create/sculpt them and store the results with "Simple Morph Creator" tool.
  3. Quit Blender and reopen it.
  4. Use the "Combined Morph Creator" to choose those morphs (for mix of 2, 3 or 4 simple morphs). Play with min/max values. For each combination you have to sculpt the result and store it. So for combination of 2 simple morphs, you have to create 4 sculpts. For 3 it's 8 and for 4 it's 16. You save the result as a simple morph, it's the same workflow. Important, save the morphs in another file, not the one where the simple morphs are.
  5. When all these combinations are made and saved in the dedicated file, you can either create new combined morphs (and they can re-use simple morphs already used), or delete/move the file where the simple morphs are. Quit Blender, reopen it, and the combined morphs are shown as simple morphs, but their behavior depend of other morphs used for the mix.

TetoTheSquirrelFox avatar Mar 08 '20 21:03 TetoTheSquirrelFox

A quick update. I'm finishing tonight the "Combined Morph Tool", and I was thinking that the "Simple Morph Tool" should have a refreshing, so I improved few things like displayed texts and tips. I also reworked how it looks, I think it's more obvious : image Another example, where all is completed before finalizing : image

TetoTheSquirrelFox avatar Mar 10 '20 19:03 TetoTheSquirrelFox