Updated
This commit is contained in:
674
Scripts/Modeling/Edit/LDMT/faceTransfer/LICENSE
Normal file
674
Scripts/Modeling/Edit/LDMT/faceTransfer/LICENSE
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
{one line to give the program's name and a brief idea of what it does.}
|
||||
Copyright (C) {year} {name of author}
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
{project} Copyright (C) {year} {fullname}
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
412
Scripts/Modeling/Edit/LDMT/faceTransfer/__init__.py
Normal file
412
Scripts/Modeling/Edit/LDMT/faceTransfer/__init__.py
Normal file
@ -0,0 +1,412 @@
|
||||
"""
|
||||
Retarget your blendshapes between meshes with the same topology.
|
||||
|
||||
.. figure:: https://github.com/robertjoosten/rjRetargetBlendshape/raw/master/README.png
|
||||
:align: center
|
||||
|
||||
`Link to Video <https://vimeo.com/170360738>`_
|
||||
|
||||
Installation
|
||||
============
|
||||
Copy the **rjRetargetBlendshape** folder to your Maya scripts directory
|
||||
::
|
||||
C:/Users/<USER>/Documents/maya/scripts
|
||||
|
||||
Usage
|
||||
=====
|
||||
Command line
|
||||
::
|
||||
import rjRetargetBlendshape
|
||||
rjRetargetBlendshape.convert(
|
||||
source,
|
||||
blendshape,
|
||||
target,
|
||||
scale=True,
|
||||
rotate=True,
|
||||
smooth=0,
|
||||
smoothIterations=0,
|
||||
space=OpenMaya.MSpace.kObject,
|
||||
)
|
||||
|
||||
Display UI
|
||||
::
|
||||
import rjRetargetBlendshape.ui
|
||||
rjRetargetBlendshape.ui.show()
|
||||
|
||||
Note
|
||||
====
|
||||
Retarget your blendshapes between meshes with the same topology. There are a
|
||||
few options that can be helpful to achieve the desired results.
|
||||
|
||||
* Scaling your delta depending on the size difference between the source and the target vertex.
|
||||
* Rotating the delta depending on the normal difference between the source and the target vertex.
|
||||
* Smoothing based on the vertex size between the retarget mesh and the blendshape mesh.
|
||||
|
||||
Code
|
||||
====
|
||||
"""
|
||||
|
||||
import math
|
||||
from maya import OpenMaya, cmds
|
||||
|
||||
__author__ = "Robert Joosten"
|
||||
__version__ = "0.8.2"
|
||||
__email__ = "rwm.joosten@gmail.com"
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def convert(
|
||||
source,
|
||||
blendshape,
|
||||
target,
|
||||
scale=True,
|
||||
rotate=True,
|
||||
smooth=0,
|
||||
smoothIterations=2,
|
||||
space=OpenMaya.MSpace.kObject
|
||||
):
|
||||
"""
|
||||
Create a new target based on the difference between the source and
|
||||
blendshape. The target mesh is duplicated and the difference between
|
||||
source and target is transfered onto the duplicated mesh. When
|
||||
transfering both scale and rotation of the delta vectors can be taken
|
||||
into account. Once the data is transfered an Laplacian smoothing algorithm
|
||||
can be applied onto the newly created target to create a more desired
|
||||
result.
|
||||
|
||||
:param str source:
|
||||
:param str blendshape:
|
||||
:param str target:
|
||||
:param bool scale: Take scale between delta vectors into account
|
||||
:param bool rotate: Take rotation between normal vectors into account
|
||||
:param float smooth: Smoothing strength
|
||||
:param int smoothIterations: Times the smooth algorithm repeats
|
||||
:param OpenMaya.MSpace space:
|
||||
:raises RuntimeError: If the vertex count doesn't match
|
||||
:return: Name of transfered blendshape mesh
|
||||
:rtype: str
|
||||
"""
|
||||
# convert objects to dag
|
||||
dags = []
|
||||
meshes = []
|
||||
|
||||
for i, name in enumerate([source, target, blendshape]):
|
||||
dags.append(asMDagPath(asMObject(name)))
|
||||
meshes.append(asMFnMesh(dags[i]))
|
||||
|
||||
sourceD, targetD, blendshapeD = dags
|
||||
sourceM, targetM, blendshapeM = meshes
|
||||
|
||||
# compare vertex count
|
||||
count = set([m.numVertices() for m in meshes])
|
||||
|
||||
if len(count) != 1:
|
||||
raise RuntimeError(
|
||||
"Input geometry doesn't have matching vertex counts!"
|
||||
)
|
||||
|
||||
# duplicate target to manipulate mesh
|
||||
targetB = getBasename(target)
|
||||
blendshapeB = getBasename(blendshape)
|
||||
|
||||
target = cmds.duplicate(
|
||||
target,
|
||||
rr=True,
|
||||
n="{0}_{1}".format(targetB, blendshapeB)
|
||||
)[0]
|
||||
|
||||
# parent duplicated target
|
||||
if cmds.listRelatives(target, p=True):
|
||||
target = cmds.parent(target, world=True)[0]
|
||||
|
||||
targetD = asMDagPath(asMObject(target))
|
||||
targetM = asMFnMesh(targetD)
|
||||
|
||||
# iterate vertices
|
||||
count = next(iter(count))
|
||||
positions = OpenMaya.MPointArray()
|
||||
|
||||
# variables
|
||||
dags = [sourceD, targetD, blendshapeD]
|
||||
|
||||
points = [OpenMaya.MPoint(), OpenMaya.MPoint(), OpenMaya.MPoint()]
|
||||
normals = [OpenMaya.MVector(), OpenMaya.MVector()]
|
||||
|
||||
length = [0,0,0]
|
||||
lengths = [[],[],[]]
|
||||
|
||||
# get new positions
|
||||
for i in range(count):
|
||||
# initialize component
|
||||
component = asComponent(i)
|
||||
|
||||
# loop meshes
|
||||
for j, dag in enumerate(dags):
|
||||
# get points
|
||||
meshes[j].getPoint(i, points[j], space)
|
||||
|
||||
# get length
|
||||
l = getAverageLength(dag, component, space)
|
||||
|
||||
length[j] = l
|
||||
lengths[j].append(l)
|
||||
|
||||
# variables
|
||||
sourceP, targetP, blendshapeP = points
|
||||
sourceL, targetL, blendshapeL = length
|
||||
|
||||
# difference vector
|
||||
vector = blendshapeP - sourceP
|
||||
|
||||
# handle scale
|
||||
if scale:
|
||||
scaleFactor = targetL/sourceL if sourceL and targetL else 1
|
||||
|
||||
# scale vector
|
||||
vector = vector * scaleFactor
|
||||
|
||||
# handle normal rotation
|
||||
if rotate:
|
||||
# get normals
|
||||
for j, mesh in enumerate(meshes[:-1]):
|
||||
mesh.getVertexNormal(i, True, normals[j], space)
|
||||
|
||||
# get quaternion between normals
|
||||
sourceN, targetN = normals
|
||||
quaternion = sourceN.rotateTo(targetN)
|
||||
|
||||
# rotate vector
|
||||
vector = vector.rotateBy(quaternion)
|
||||
|
||||
positions.append(targetP + vector)
|
||||
|
||||
# set all points
|
||||
targetM.setPoints(positions, space)
|
||||
|
||||
# loop over smooth iterations
|
||||
for _ in range(smoothIterations):
|
||||
|
||||
# loop over vertices
|
||||
for i, sourceL, targetL, blendshapeL in zip(range(count), *lengths):
|
||||
|
||||
# smooth vertex
|
||||
setLaplacianSmooth(
|
||||
targetD,
|
||||
i,
|
||||
space,
|
||||
sourceL,
|
||||
targetL,
|
||||
blendshapeL,
|
||||
smooth
|
||||
)
|
||||
|
||||
return target
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def setLaplacianSmooth(
|
||||
dag,
|
||||
index,
|
||||
space,
|
||||
sourceL,
|
||||
targetL,
|
||||
blendshapeL,
|
||||
smooth
|
||||
):
|
||||
"""
|
||||
Laplacian smoothing algorithm, where the average of the neighbouring points
|
||||
are used to smooth the target vertices, based on the factor between the
|
||||
average length of both the source and the target mesh.
|
||||
|
||||
:param OpenMaya.MDagPath dag:
|
||||
:param int index: Component index
|
||||
:param OpenMaya.MSpace space:
|
||||
:param float sourceL:
|
||||
:param float targetL:
|
||||
:param float blendshapeL:
|
||||
:param float smooth:
|
||||
"""
|
||||
# calculate factor
|
||||
component = asComponent(index)
|
||||
avgL = getAverageLength(dag, component, space)
|
||||
|
||||
targetF = blendshapeL/sourceL if sourceL and targetL else 1
|
||||
blendshapeF = avgL/targetL if sourceL and blendshapeL else 1
|
||||
|
||||
factor = abs((1-targetF/blendshapeF)*smooth)
|
||||
factor = max(min(factor, 1), 0)
|
||||
|
||||
# ignore if there is not smooth factor
|
||||
if not factor:
|
||||
return
|
||||
|
||||
# get average position
|
||||
component = asComponent(index)
|
||||
vtx = OpenMaya.MItMeshVertex(dag, component)
|
||||
|
||||
origP, avgP = getAveragePosition(dag, component, space)
|
||||
|
||||
# get new position
|
||||
avgP = avgP * factor
|
||||
origP = origP * (1-factor)
|
||||
newP = avgP + OpenMaya.MVector(origP)
|
||||
|
||||
# set new position
|
||||
vtx.setPosition(newP, space)
|
||||
|
||||
def getAveragePosition(dag, component, space):
|
||||
"""
|
||||
Get average position of connected vertices.
|
||||
|
||||
:param OpenMaya.MDagPath dag:
|
||||
:param OpenMaya.MFnSingleIndexedComponent component:
|
||||
:param OpenMaya.MSpace space:
|
||||
:return: Average length of the connected edges
|
||||
:rtype: OpenMaya.MPoint
|
||||
"""
|
||||
averagePos = OpenMaya.MPoint()
|
||||
|
||||
# get connected vertices
|
||||
connected = OpenMaya.MIntArray()
|
||||
|
||||
iterate = OpenMaya.MItMeshVertex(dag, component)
|
||||
iterate.getConnectedVertices(connected)
|
||||
|
||||
# get original position
|
||||
originalPos = iterate.position(space)
|
||||
|
||||
# ignore if no vertices are connected
|
||||
if not connected.length():
|
||||
return averagePos
|
||||
|
||||
# get average
|
||||
component = asComponent(connected)
|
||||
iterate = OpenMaya.MItMeshVertex(dag, component)
|
||||
while not iterate.isDone():
|
||||
averagePos += OpenMaya.MVector(iterate.position(space))
|
||||
iterate.next()
|
||||
|
||||
averagePos = averagePos/connected.length()
|
||||
return originalPos, averagePos
|
||||
|
||||
def getAverageLength(dag, component, space):
|
||||
"""
|
||||
Get average length of connected edges.
|
||||
|
||||
:param OpenMaya.MDagPath dag:
|
||||
:param OpenMaya.MFnSingleIndexedComponent component:
|
||||
:param OpenMaya.MSpace space:
|
||||
:return: Average length of the connected edges
|
||||
:rtype: float
|
||||
"""
|
||||
total = 0
|
||||
|
||||
lengthUtil = OpenMaya.MScriptUtil()
|
||||
lengthPtr = lengthUtil.asDoublePtr()
|
||||
|
||||
# get connected edges
|
||||
connected = OpenMaya.MIntArray()
|
||||
|
||||
iterate = OpenMaya.MItMeshVertex(dag, component)
|
||||
iterate.getConnectedEdges(connected)
|
||||
|
||||
# ignore if no edges are connected
|
||||
if not connected.length():
|
||||
return 0
|
||||
|
||||
# get average
|
||||
component = asComponent(connected, OpenMaya.MFn.kMeshEdgeComponent)
|
||||
iterate = OpenMaya.MItMeshEdge(dag, component)
|
||||
while not iterate.isDone():
|
||||
iterate.getLength(lengthPtr, space)
|
||||
total += lengthUtil.getDouble(lengthPtr)
|
||||
|
||||
iterate.next()
|
||||
|
||||
return total/connected.length()
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def getBasename(name):
|
||||
"""
|
||||
Strip the parent and namespace data of the provided string.
|
||||
|
||||
:param str name:
|
||||
:return: Base name of parsed object
|
||||
:rtype: str
|
||||
"""
|
||||
return name.split("|")[-1].split(":")[-1]
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def asMIntArray(index):
|
||||
"""
|
||||
index -> OpenMaya.MIntArray
|
||||
|
||||
:param int/OpenMaya.MIntArray index: indices
|
||||
:return: Array of indices
|
||||
:rtype: OpenMaya.MIntArray
|
||||
"""
|
||||
if type(index) != OpenMaya.MIntArray:
|
||||
array = OpenMaya.MIntArray()
|
||||
array.append(index)
|
||||
return array
|
||||
|
||||
return index
|
||||
|
||||
def asComponent(index, t=OpenMaya.MFn.kMeshVertComponent):
|
||||
"""
|
||||
index -> OpenMaya.MFn.kComponent
|
||||
Based on the input type it will create a component type for this tool
|
||||
the following components are being used.
|
||||
|
||||
* OpenMaya.MFn.kMeshVertComponent
|
||||
* OpenMaya.MFn.kMeshEdgeComponent
|
||||
|
||||
:param int/OpenMaya.MIntArray index: indices to create component for
|
||||
:param OpenMaya.MFn.kComponent t: can be all of OpenMaya component types.
|
||||
:return: Initialized components
|
||||
:rtype: OpenMaya.MFnSingleIndexedComponent
|
||||
"""
|
||||
# convert input to an MIntArray if it not already is one
|
||||
array = asMIntArray(index)
|
||||
|
||||
# initialize component
|
||||
component = OpenMaya.MFnSingleIndexedComponent().create(t)
|
||||
OpenMaya.MFnSingleIndexedComponent(component).addElements(array)
|
||||
return component
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def asMObject(path):
|
||||
"""
|
||||
str -> OpenMaya.MObject
|
||||
|
||||
:param str path: Path to Maya object
|
||||
:rtype: OpenMaya.MObject
|
||||
"""
|
||||
selectionList = OpenMaya.MSelectionList()
|
||||
selectionList.add(path)
|
||||
|
||||
obj = OpenMaya.MObject()
|
||||
selectionList.getDependNode(0, obj)
|
||||
return obj
|
||||
|
||||
def asMDagPath(obj):
|
||||
"""
|
||||
OpenMaya.MObject -> OpenMaya.MDagPath
|
||||
|
||||
:param OpenMaya.MObject obj:
|
||||
:rtype: OpenMaya.MDagPath
|
||||
"""
|
||||
return OpenMaya.MDagPath.getAPathTo(obj)
|
||||
|
||||
def asMFnMesh(dag):
|
||||
"""
|
||||
OpenMaya.MDagPath -> OpenMaya.MfnMesh
|
||||
|
||||
:param OpenMaya.MDagPath dag:
|
||||
:rtype: OpenMaya.MfnMesh
|
||||
"""
|
||||
|
||||
return OpenMaya.MFnMesh(dag)
|
430
Scripts/Modeling/Edit/LDMT/faceTransfer/ui.py
Normal file
430
Scripts/Modeling/Edit/LDMT/faceTransfer/ui.py
Normal file
@ -0,0 +1,430 @@
|
||||
from functools import partial
|
||||
from maya import cmds, OpenMaya, OpenMayaUI
|
||||
|
||||
# import pyside, do qt version check for maya 2017 >
|
||||
qtVersion = cmds.about(qtVersion=True)
|
||||
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtWidgets import *
|
||||
from Qt.QtCompat import wrapInstance, getCppPointer
|
||||
|
||||
# import command line convert
|
||||
from . import convert
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
SPACE = []
|
||||
SPACE.append(OpenMaya.MSpace.kObject)
|
||||
SPACE.append(OpenMaya.MSpace.kWorld)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
FONT = QFont()
|
||||
FONT.setFamily("Consolas")
|
||||
|
||||
BOLT_FONT = QFont()
|
||||
BOLT_FONT.setFamily("Consolas")
|
||||
BOLT_FONT.setWeight(QFont.Weight.Light)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def mayaWindow():
|
||||
"""
|
||||
Get Maya's main window.
|
||||
|
||||
:rtype: QMainWindow
|
||||
"""
|
||||
window = OpenMayaUI.MQtUtil.mainWindow()
|
||||
window = wrapInstance(int(window), QMainWindow)
|
||||
|
||||
return window
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def title(parent, name):
|
||||
"""
|
||||
Create title ui widget.
|
||||
|
||||
:param QWidget parent:
|
||||
:param str name:
|
||||
:rtype: QLabel
|
||||
"""
|
||||
title = QLabel(parent)
|
||||
title.setText(name)
|
||||
title.setFont(BOLT_FONT)
|
||||
return title
|
||||
|
||||
def divider(parent):
|
||||
"""
|
||||
Create divider ui widget.
|
||||
|
||||
:param QWidget parent:
|
||||
:rtype: QFrame
|
||||
"""
|
||||
line = QFrame(parent)
|
||||
line.setFrameShape(QFrame.HLine)
|
||||
line.setFrameShadow(QFrame.Sunken)
|
||||
return line
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def getSelectedMeshes():
|
||||
"""
|
||||
Get all selected meshes, the current selection will be looped and checked
|
||||
if any of the selected transforms contain a mesh node. If this is the case
|
||||
the transform will be added to the selection list.
|
||||
|
||||
:return: Parents nodes of all selected meshes
|
||||
:rtype: list
|
||||
"""
|
||||
# get selection
|
||||
selection = cmds.ls(sl=True, l=True)
|
||||
extendedSelection = []
|
||||
|
||||
# extend selection
|
||||
for sel in selection:
|
||||
extendedSelection.extend(
|
||||
cmds.listRelatives(sel, s=True, ni=True, f=True)
|
||||
)
|
||||
|
||||
# return parent of meshes
|
||||
return list(set([
|
||||
cmds.listRelatives(m, p=True, f=True)[0]
|
||||
for m in extendedSelection
|
||||
if cmds.nodeType(m) == "mesh"
|
||||
]))
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
class SelectionWidget(QWidget):
|
||||
signal = Signal()
|
||||
def __init__(self, parent, label, selectionMode="single"):
|
||||
QWidget.__init__(self, parent)
|
||||
|
||||
# selection
|
||||
self._selectionMode = selectionMode
|
||||
self._selection = []
|
||||
|
||||
# create layout
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(3, 0, 3, 0)
|
||||
layout.setSpacing(0)
|
||||
|
||||
# create label
|
||||
self.label = QLabel(self)
|
||||
self.label.setText("( 0 ) Mesh(es)")
|
||||
self.label.setFont(FONT)
|
||||
layout.addWidget(self.label)
|
||||
|
||||
# create button
|
||||
button = QPushButton(self)
|
||||
button.setText(label)
|
||||
button.setFont(FONT)
|
||||
button.released.connect(self.setSelection)
|
||||
|
||||
layout.addWidget(button)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
@property
|
||||
def selection(self):
|
||||
return self._selection
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def setSelection(self):
|
||||
"""
|
||||
Update the UI with the current selection, a signal is emit so the
|
||||
parent widget can validate the current selection.
|
||||
"""
|
||||
# get selection
|
||||
meshes = getSelectedMeshes()
|
||||
|
||||
# update ui
|
||||
self.label.setText("( {0} ) Mesh(es)".format(len(meshes)))
|
||||
self.label.setToolTip("\n".join(meshes))
|
||||
|
||||
# process selection mode
|
||||
if self._selectionMode == "single" and meshes:
|
||||
meshes = meshes[0]
|
||||
|
||||
self._selection = meshes
|
||||
self.signal.emit()
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
class CheckBoxWidget(QWidget):
|
||||
def __init__(self, parent, label, toolTip):
|
||||
QWidget.__init__(self, parent)
|
||||
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(3, 0, 3, 0)
|
||||
layout.setSpacing(0)
|
||||
|
||||
# create checkbox
|
||||
self.checkBox = QCheckBox(self)
|
||||
self.checkBox.setText(label)
|
||||
self.checkBox.setFont(FONT)
|
||||
self.checkBox.setChecked(True)
|
||||
self.checkBox.setToolTip(toolTip)
|
||||
layout.addWidget(self.checkBox)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def isChecked(self):
|
||||
return self.checkBox.isChecked()
|
||||
|
||||
class SpinBoxWidget(QWidget):
|
||||
def __init__(
|
||||
self,
|
||||
parent,
|
||||
widget,
|
||||
label,
|
||||
toolTip,
|
||||
value,
|
||||
minimum,
|
||||
maximum,
|
||||
step
|
||||
):
|
||||
QWidget.__init__(self, parent)
|
||||
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(3, 0, 3, 0)
|
||||
layout.setSpacing(0)
|
||||
|
||||
# create label
|
||||
l = QLabel(self)
|
||||
l.setText(label)
|
||||
l.setFont(FONT)
|
||||
layout.addWidget(l)
|
||||
|
||||
# create spinbox
|
||||
self.spinBox = widget(self)
|
||||
self.spinBox.setFont(FONT)
|
||||
self.spinBox.setToolTip(toolTip)
|
||||
self.spinBox.setValue(value)
|
||||
self.spinBox.setSingleStep(step)
|
||||
self.spinBox.setMinimum(minimum)
|
||||
self.spinBox.setMaximum(maximum)
|
||||
layout.addWidget(self.spinBox)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def value(self):
|
||||
return self.spinBox.value()
|
||||
|
||||
class RetargetBlendshapeWidget(QWidget):
|
||||
def __init__(self, parent):
|
||||
QWidget.__init__(self, parent)
|
||||
|
||||
# set ui
|
||||
self.setParent(parent)
|
||||
self.setWindowFlags(Qt.Window)
|
||||
self.setWindowIcon(QIcon(":/blendShape.png"))
|
||||
|
||||
self.setWindowTitle("Retarget Blendshapes")
|
||||
self.setObjectName("RetargetUI")
|
||||
self.resize(300, 200)
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(5, 5, 5, 5)
|
||||
layout.setSpacing(5)
|
||||
|
||||
# create title
|
||||
t = title(self, "Retarget Blendshapes")
|
||||
layout.addWidget(t)
|
||||
|
||||
# create selection widget
|
||||
self.sourceW = SelectionWidget(self, "Set Source")
|
||||
self.blendshapeW = SelectionWidget(self, "Set Blendshape(s)", "multi")
|
||||
self.targetW = SelectionWidget(self, "Set Target")
|
||||
|
||||
for widget in [self.sourceW, self.targetW, self.blendshapeW]:
|
||||
widget.signal.connect(self.validate)
|
||||
layout.addWidget(widget)
|
||||
|
||||
# create divider
|
||||
d = divider(self)
|
||||
layout.addWidget(d)
|
||||
|
||||
# create options
|
||||
t = title(self, "Options")
|
||||
layout.addWidget(t)
|
||||
|
||||
# scale settings
|
||||
self.scaleW = CheckBoxWidget(
|
||||
self,
|
||||
"Scale Delta",
|
||||
(
|
||||
"If checked, the vertex delta will be scaled based on the \n"
|
||||
"difference of the averaged connected edge length between \n"
|
||||
"the source and the target."
|
||||
)
|
||||
)
|
||||
layout.addWidget(self.scaleW)
|
||||
|
||||
# rotate settings
|
||||
self.rotateW = CheckBoxWidget(
|
||||
self,
|
||||
"Rotate Delta",
|
||||
(
|
||||
"If checked, the vertex delta will be rotated based on the \n"
|
||||
"difference of the vertex normal between the source and \n"
|
||||
"the target."
|
||||
)
|
||||
)
|
||||
layout.addWidget(self.rotateW)
|
||||
|
||||
# create divider
|
||||
d = divider(self)
|
||||
layout.addWidget(d)
|
||||
|
||||
# create smoothing
|
||||
t = title(self, "Smoothing")
|
||||
layout.addWidget(t)
|
||||
|
||||
# smooth settings
|
||||
self.smoothW = SpinBoxWidget(
|
||||
self,
|
||||
QDoubleSpinBox,
|
||||
"Factor",
|
||||
(
|
||||
"The targets will be smoothed based on the difference \n"
|
||||
"between source and blendshape and original target and \n"
|
||||
"output"
|
||||
),
|
||||
value=10,
|
||||
minimum=0,
|
||||
maximum=1000,
|
||||
step=0.5
|
||||
)
|
||||
layout.addWidget(self.smoothW)
|
||||
|
||||
# smooth iter settings
|
||||
self.smoothIterW = SpinBoxWidget(
|
||||
self,
|
||||
QSpinBox,
|
||||
"Iterations",
|
||||
(
|
||||
"The amount of time the smoothing algorithm is applied to \n"
|
||||
"the output."
|
||||
),
|
||||
value=2,
|
||||
minimum=0,
|
||||
maximum=10,
|
||||
step=1
|
||||
)
|
||||
layout.addWidget(self.smoothIterW)
|
||||
|
||||
# create divider
|
||||
d = divider(self)
|
||||
layout.addWidget(d)
|
||||
|
||||
# create space
|
||||
t = title(self, "Space")
|
||||
layout.addWidget(t)
|
||||
|
||||
self.spaceW = QComboBox(self)
|
||||
self.spaceW.setFont(FONT)
|
||||
self.spaceW.addItems(["kObject", "kWorld"])
|
||||
self.spaceW.setToolTip(
|
||||
"Determine space in which all the calculations take place."
|
||||
)
|
||||
|
||||
layout.addWidget(self.spaceW)
|
||||
|
||||
# create divider
|
||||
d = divider(self)
|
||||
layout.addWidget(d)
|
||||
|
||||
# create retarget button
|
||||
self.retargetB = QPushButton(self)
|
||||
self.retargetB.setText("Retarget")
|
||||
self.retargetB.setFont(FONT)
|
||||
self.retargetB.setEnabled(False)
|
||||
self.retargetB.released.connect(self.retarget)
|
||||
layout.addWidget(self.retargetB)
|
||||
|
||||
# create spacer
|
||||
spacer = QSpacerItem(1, 1, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
layout.addItem(spacer)
|
||||
|
||||
# create progress bar
|
||||
self.progressBar = QProgressBar(self)
|
||||
layout.addWidget(self.progressBar)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def validate(self):
|
||||
"""
|
||||
Validate the current selection, if the selection is valid the retarget
|
||||
button will be enabled. If not the button will stay disabled.
|
||||
"""
|
||||
# variables
|
||||
source = self.sourceW.selection
|
||||
target = self.targetW.selection
|
||||
blendshapes = self.blendshapeW.selection
|
||||
|
||||
# set button invisible
|
||||
self.retargetB.setEnabled(False)
|
||||
|
||||
if source and target and blendshapes:
|
||||
self.retargetB.setEnabled(True)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def retarget(self):
|
||||
"""
|
||||
Read the values from the UI and call the command line convert function
|
||||
to retarget the blendshapes. Once the blendshapes are converted the
|
||||
new geometry will be selected.
|
||||
"""
|
||||
# get selection
|
||||
source = self.sourceW.selection
|
||||
target = self.targetW.selection
|
||||
blendshapes = self.blendshapeW.selection
|
||||
|
||||
# get settings
|
||||
scale = self.scaleW.isChecked()
|
||||
rotate = self.rotateW.isChecked()
|
||||
|
||||
# get smoothing
|
||||
smooth = self.smoothW.value()
|
||||
smoothIterations = self.smoothIterW.value()
|
||||
|
||||
# get space
|
||||
space = SPACE[self.spaceW.currentIndex()]
|
||||
|
||||
# set progress bar
|
||||
self.progressBar.setMinimum(0)
|
||||
self.progressBar.setMaximum(len(blendshapes))
|
||||
self.progressBar.setValue(0)
|
||||
|
||||
# convert
|
||||
converted = []
|
||||
for i, blendshape in enumerate(blendshapes):
|
||||
converted.append(
|
||||
convert(
|
||||
source,
|
||||
blendshape,
|
||||
target,
|
||||
scale,
|
||||
rotate,
|
||||
smooth,
|
||||
smoothIterations,
|
||||
space
|
||||
)
|
||||
)
|
||||
|
||||
# update spacebar
|
||||
self.progressBar.setValue(i+1)
|
||||
|
||||
# select output
|
||||
cmds.select(converted)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
def show():
|
||||
retargetBlendshape = RetargetBlendshapeWidget(mayaWindow())
|
||||
retargetBlendshape.show()
|
536
Scripts/Modeling/Edit/LDMT/ldmt_checkUVBleed.py
Normal file
536
Scripts/Modeling/Edit/LDMT/ldmt_checkUVBleed.py
Normal file
@ -0,0 +1,536 @@
|
||||
import os
|
||||
import math
|
||||
from ldmt_function.ldmt_loadUIFile import get_maya_window, load_ui_file
|
||||
import maya.OpenMayaUI as omui
|
||||
from ldmt_core import ldmt_cmds as ld
|
||||
from functools import partial
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
|
||||
try:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtWidgets import *
|
||||
# from Qt.QtUiTools import *
|
||||
from Qt import __version__
|
||||
from Qt.QtCompat import loadUi, wrapInstance
|
||||
except ImportError:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
# from Qt.QtUiTools import *
|
||||
from Qt import __version__
|
||||
from Qt.QtCompat import wrapInstance
|
||||
|
||||
import maya.OpenMaya as om
|
||||
import maya.api.OpenMaya as om2
|
||||
import random
|
||||
import ast
|
||||
|
||||
LDMTPATH = ld.getPath('LDMT')
|
||||
ldmt_uifile = LDMTPATH + '/ldmt_ui/ldmt_checkUVBleed.ui'
|
||||
ldmt_window_name = 'ldmt_checkUVBleed'
|
||||
ldmt_button_name = 'btn_'+ldmt_window_name.split('_')[1]
|
||||
|
||||
'''
|
||||
Function
|
||||
'''
|
||||
def changeSelectionType(sel,selType): #selType vertex face edge puv
|
||||
mel.eval('if( !`exists doMenuComponentSelection` ) eval( "source dagMenuProc" );')
|
||||
mel.eval('doMenuComponentSelection("'+sel+'","'+selType+'")' )
|
||||
|
||||
def getUVEdgeDic(sel):
|
||||
selList = om2.MSelectionList()
|
||||
selList.add(sel)
|
||||
selPath = selList.getDagPath(0)
|
||||
selMesh = om2.MFnMesh(selPath)
|
||||
selVtxIter = om2.MItMeshVertex(selPath)
|
||||
selEdgeIter = om2.MItMeshEdge(selPath)
|
||||
selFaceIter = om2.MItMeshPolygon(selPath)
|
||||
|
||||
uvid_uv = [] # generate {uvid:[u,v],} from MFnMesh.getUVs()
|
||||
vtxid_uvid = []
|
||||
edgeid_vtxid = []
|
||||
edgeid_uvid = [] #edgeid_vtxid + vtxid_uvid
|
||||
faceid_edgeid = []
|
||||
faceid_uvid = []
|
||||
edgeid_faceid = [] #faceid_edgeid reverse
|
||||
uvedgeid_uvid = [] # get { uvedgeid: [uvid1, uvid2]} On border
|
||||
|
||||
uvid_usi = selMesh.getUvShellsIds() # [usi1,usi2,...]
|
||||
uvid_usi = uvid_usi[1]
|
||||
uvArray = selMesh.getUVs()
|
||||
for i in range(len(uvArray[0])):
|
||||
uvid_uv.append([uvArray[0][i],uvArray[1][i]])
|
||||
|
||||
while not selVtxIter.isDone(): #get {[[uvid1,uvid2],...]}
|
||||
vtxid_uvid.append(list(set(selVtxIter.getUVIndices())))
|
||||
selVtxIter.next()
|
||||
|
||||
while not selEdgeIter.isDone(): #get edge to vtx
|
||||
edgeid_vtxid.append([selEdgeIter.vertexId(0),selEdgeIter.vertexId(1)])
|
||||
edgeid_faceid.append(selEdgeIter.getConnectedFaces())
|
||||
selEdgeIter.next()
|
||||
|
||||
for edgeid in range(len(edgeid_vtxid)): # get {[[uvid1,uvid2,uvid3],...]}
|
||||
vtx0 = edgeid_vtxid[edgeid][0]
|
||||
vtx1 = edgeid_vtxid[edgeid][1]
|
||||
edgeid_uvid.append(vtxid_uvid[vtx0] + vtxid_uvid[vtx1])
|
||||
|
||||
while not selFaceIter.isDone(): # get {[[uvid1,uvid2,uvid3,uvid4], ...] }
|
||||
verts = selFaceIter.getVertices()
|
||||
faceid_edgeid.append(selFaceIter.getEdges())
|
||||
uvids=[]
|
||||
for index in range(len(verts)):
|
||||
uvids.append(selFaceIter.getUVIndex(index)) #necessary for uvedgeid
|
||||
faceid_uvid.append(uvids)
|
||||
selFaceIter.next()
|
||||
|
||||
for edgeid in range(len(edgeid_faceid)):
|
||||
faceids = edgeid_faceid[edgeid]
|
||||
edgeuvids = set(edgeid_uvid[edgeid])
|
||||
numface = len(faceids)
|
||||
if numface == 1: #OnBorder
|
||||
uvids = faceid_uvid[faceids[0]]
|
||||
uvedgeid_uvid.append(list(edgeuvids.intersection(uvids)))
|
||||
continue
|
||||
elif numface == 2:
|
||||
uvidsA = faceid_uvid[faceids[0]]
|
||||
uvidsB = faceid_uvid[faceids[1]]
|
||||
intersectUV = list(set(uvidsA).intersection(uvidsB))
|
||||
intersectUV_len = len(intersectUV)
|
||||
if intersectUV_len<2:
|
||||
if intersectUV_len == 1:
|
||||
for uv in edgeuvids:
|
||||
if uv == intersectUV[0]:
|
||||
continue
|
||||
elif uv in uvidsA or uv in uvidsB:
|
||||
uvedgeid_uvid.append([intersectUV[0],uv])
|
||||
else:
|
||||
uvedgeid_uvid.append(list(edgeuvids.intersection(uvidsA)))
|
||||
uvedgeid_uvid.append(list(edgeuvids.intersection(uvidsB)))
|
||||
else:
|
||||
print("Cleanup mesh first!!!!")
|
||||
|
||||
usi_uvid = {}
|
||||
usi_uvidOnBord = {}
|
||||
usi_uvedgeidOnBord = {}
|
||||
usi_bb = {}
|
||||
|
||||
for uvid in range(len(uvid_usi)):
|
||||
usi = uvid_usi[uvid]
|
||||
if usi in usi_uvid:
|
||||
usi_uvid[usi].append(uvid)
|
||||
else:
|
||||
usi_uvid[usi] = [uvid]
|
||||
|
||||
for uvedgeid in range(len(uvedgeid_uvid)):
|
||||
usi = uvid_usi[uvedgeid_uvid[uvedgeid][0]]
|
||||
if usi in usi_uvedgeidOnBord:
|
||||
usi_uvedgeidOnBord[usi].append(uvedgeid)
|
||||
else:
|
||||
usi_uvedgeidOnBord[usi] = [uvedgeid]
|
||||
|
||||
for usi in usi_uvedgeidOnBord:
|
||||
edgeids = usi_uvedgeidOnBord[usi]
|
||||
uvsOnBord = []
|
||||
for edgeid in edgeids:
|
||||
uvsOnBord = uvsOnBord + uvedgeid_uvid[edgeid]
|
||||
usi_uvidOnBord[usi] = list(set(uvsOnBord))
|
||||
|
||||
for usi in usi_uvidOnBord:
|
||||
umin = 1
|
||||
umax = 0
|
||||
vmin = 1
|
||||
vmax = 0
|
||||
for uvid in usi_uvidOnBord[usi]:
|
||||
u = uvid_uv[uvid][0]
|
||||
v = uvid_uv[uvid][1]
|
||||
if u < umin:
|
||||
umin = u
|
||||
if u > umax:
|
||||
umax = u
|
||||
if v < vmin:
|
||||
vmin = v
|
||||
if v > vmax:
|
||||
vmax = v
|
||||
usi_bb[usi] = [[umin,umax],[vmin,vmax]]
|
||||
|
||||
usi_bbarea = {}
|
||||
for i in range(len(usi_uvid)): #get {usi:area,} from usi_bb
|
||||
usi_bbarea[i] = abs(usi_bb[i][0][1]-usi_bb[i][0][0])*abs(usi_bb[i][1][1]-usi_bb[i][1][0])
|
||||
bbarea_usi = sorted(zip(usi_bbarea.values(), usi_bbarea.keys())) # get [(minarea, usi0),...,( maxarea, usi99)]
|
||||
bbarea_usi.reverse()
|
||||
|
||||
uvedgeid_uv = []
|
||||
for uvedgeid in range(len(uvedgeid_uvid)):
|
||||
uvidA = uvedgeid_uvid[uvedgeid][0]
|
||||
uvidB = uvedgeid_uvid[uvedgeid][1]
|
||||
uA = uvid_uv[uvidA][0]
|
||||
vA = uvid_uv[uvidA][1]
|
||||
uB = uvid_uv[uvidB][0]
|
||||
vB = uvid_uv[uvidB][1]
|
||||
if vB >= vA:
|
||||
uvedgeid_uv.append([[uA,vA],[uB,vB]])
|
||||
else:
|
||||
uvedgeid_uv.append([[uB,vB],[uA,vA]])
|
||||
|
||||
return usi_uvid, uvid_uv, uvedgeid_uvid, usi_uvidOnBord, usi_uvedgeidOnBord, usi_bb, bbarea_usi, uvedgeid_uv
|
||||
|
||||
def LD_CheckUVBleed(uvScale,pixelDistance,borderDistance):
|
||||
uvDistance = float(pixelDistance)/uvScale
|
||||
borderDistance = float(borderDistance)/uvScale
|
||||
TOLERANCE = 4
|
||||
p = 10**TOLERANCE
|
||||
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
sel = sel[0]
|
||||
faceWithNoUV = getFacesHaveNoUV(sel)
|
||||
if faceWithNoUV !=[]:
|
||||
cmds.select(faceWithNoUV,r=1)
|
||||
cmds.warning("Some Faces Have no UVs!")
|
||||
return
|
||||
uvDic = getUVEdgeDic(sel) #uvDic[6]
|
||||
usi_uvid = uvDic[0]
|
||||
uvid_uv = uvDic[1]
|
||||
uvedgeid_uvid = uvDic[2]
|
||||
usi_uvidOnBord = uvDic[3]
|
||||
usi_uvedgeidOnBord = uvDic[4]
|
||||
usi_bb = uvDic[5]
|
||||
bbarea_usi = uvDic[6]
|
||||
uvedgeid_uv = uvDic[7]
|
||||
|
||||
uvNotPass = set() # len(uvNotPass) Filter out stacking uvs
|
||||
skipList = set()
|
||||
skipListTemp = set()
|
||||
intersectList = {}
|
||||
usi_uvidOnBord_final = {}
|
||||
usi_uvedgeidOnBord_final = {}
|
||||
|
||||
# prepare
|
||||
for tupleA in range(len(bbarea_usi)):
|
||||
usiA = bbarea_usi[tupleA][1]
|
||||
skipListTemp.add(usiA)
|
||||
|
||||
# fast detect
|
||||
bb_uminA = usi_bb[usiA][0][0]
|
||||
bb_umaxA = usi_bb[usiA][0][1]
|
||||
bb_vminA = usi_bb[usiA][1][0]
|
||||
bb_vmaxA = usi_bb[usiA][1][1]
|
||||
|
||||
for tupleB in range(len(bbarea_usi)):
|
||||
usiB = bbarea_usi[tupleB][1]
|
||||
|
||||
#faset detect
|
||||
bb_uminB = usi_bb[usiB][0][0]
|
||||
bb_umaxB = usi_bb[usiB][0][1]
|
||||
bb_vminB = usi_bb[usiB][1][0]
|
||||
bb_vmaxB = usi_bb[usiB][1][1]
|
||||
if bb_uminA - uvDistance > bb_umaxB or\
|
||||
bb_umaxA + uvDistance < bb_uminB or\
|
||||
bb_vminA - uvDistance > bb_vmaxB or\
|
||||
bb_vmaxA + uvDistance < bb_vminB :
|
||||
continue
|
||||
|
||||
if usiB in skipListTemp:
|
||||
continue
|
||||
if ifUVShellStack(usiA,usiB,usi_bb, p):
|
||||
skipList.add(usiB)
|
||||
skipListTemp.add(usiB)
|
||||
elif ifUVShellIntersect(usiA,usiB,usi_uvedgeidOnBord, uvedgeid_uv, usi_bb):
|
||||
if usiA in intersectList:
|
||||
intersectList[usiA].append(usiB)
|
||||
else:
|
||||
intersectList[usiA]=[usiB]
|
||||
skipListTemp.add(usiB)
|
||||
skipList.add(usiB)
|
||||
|
||||
elif ifUVShellContain(usiA,usiB,usi_uvedgeidOnBord,usi_uvidOnBord,uvedgeid_uv,uvid_uv):
|
||||
skipList.add(usiB)
|
||||
skipListTemp.add(usiB)
|
||||
|
||||
# calculate final list
|
||||
for usiA in usi_uvidOnBord:
|
||||
if usiA in skipList:
|
||||
continue
|
||||
if usiA in intersectList:
|
||||
tempUVidList = []
|
||||
tempUVedgeidList = []
|
||||
for usiB in intersectList[usiA]:
|
||||
tempUVidList += usi_uvidOnBord[usiB]
|
||||
tempUVedgeidList += usi_uvedgeidOnBord[usiB]
|
||||
usi_uvidOnBord_final[usiA] = tempUVidList + usi_uvidOnBord[usiA]
|
||||
usi_uvedgeidOnBord_final[usiA] = tempUVedgeidList + usi_uvedgeidOnBord[usiA]
|
||||
else:
|
||||
usi_uvidOnBord_final[usiA] = usi_uvidOnBord[usiA]
|
||||
usi_uvedgeidOnBord_final[usiA] = usi_uvedgeidOnBord[usiA]
|
||||
|
||||
usi_bb_final = {}
|
||||
for usi in usi_uvidOnBord_final:
|
||||
umin = 1
|
||||
umax = 0
|
||||
vmin = 1
|
||||
vmax = 0
|
||||
for uvid in usi_uvidOnBord_final[usi]:
|
||||
u = uvid_uv[uvid][0]
|
||||
v = uvid_uv[uvid][1]
|
||||
if u < umin:
|
||||
umin = u
|
||||
if u > umax:
|
||||
umax = u
|
||||
if v < vmin:
|
||||
vmin = v
|
||||
if v > vmax:
|
||||
vmax = v
|
||||
usi_bb_final[usi] = [[umin,umax],[vmin,vmax]]
|
||||
|
||||
# calculate final result
|
||||
for usiA in usi_uvidOnBord_final:
|
||||
if usi_bb_final[usiA][0][0] - borderDistance < 0 or\
|
||||
usi_bb_final[usiA][0][1] + borderDistance > 1 or\
|
||||
usi_bb_final[usiA][1][0] - borderDistance < 0 or\
|
||||
usi_bb_final[usiA][1][1] + borderDistance > 1:
|
||||
for uvid in usi_uvidOnBord_final[usiA]:
|
||||
x = uvid_uv[uvid][0]
|
||||
y = uvid_uv[uvid][1]
|
||||
if x - borderDistance < 0 or\
|
||||
x + borderDistance > 1 or\
|
||||
y - borderDistance < 0 or\
|
||||
y + borderDistance > 1:
|
||||
uvNotPass.add(uvid)
|
||||
|
||||
for usiB in usi_uvidOnBord_final:
|
||||
if usiB == usiA or\
|
||||
usi_bb_final[usiA][0][0] - uvDistance > usi_bb_final[usiB][0][1] or\
|
||||
usi_bb_final[usiA][0][1] + uvDistance < usi_bb_final[usiB][0][0] or\
|
||||
usi_bb_final[usiA][1][0] - uvDistance > usi_bb_final[usiB][1][1] or\
|
||||
usi_bb_final[usiA][1][1] + uvDistance < usi_bb_final[usiB][1][0]:
|
||||
continue
|
||||
for uvid in usi_uvidOnBord_final[usiA]:
|
||||
if uvid in uvNotPass:
|
||||
continue
|
||||
x = uvid_uv[uvid][0]
|
||||
y = uvid_uv[uvid][1]
|
||||
if x - uvDistance > usi_bb_final[usiB][0][1] or\
|
||||
x + uvDistance < usi_bb_final[usiB][0][0] or\
|
||||
y - uvDistance > usi_bb_final[usiB][1][1] or\
|
||||
y + uvDistance < usi_bb_final[usiB][1][0]:
|
||||
continue
|
||||
for edge in usi_uvedgeidOnBord_final[usiB]:
|
||||
uvedgeid = uvedgeid_uvid[edge]
|
||||
x1 = uvid_uv[uvedgeid[0]][0]
|
||||
y1 = uvid_uv[uvedgeid[0]][1]
|
||||
x2 = uvid_uv[uvedgeid[1]][0]
|
||||
y2 = uvid_uv[uvedgeid[1]][1]
|
||||
cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1)
|
||||
if cross <= 0:
|
||||
closest = ((x - x1)**2 + (y - y1)**2)**(0.5)
|
||||
if closest < uvDistance:
|
||||
uvNotPass.add(uvid)
|
||||
continue
|
||||
d2 = (x2 - x1)**2 + (y2 - y1)**2
|
||||
if cross >= d2:
|
||||
closest = ((x - x2)**2 + (y - y2)**2)**(0.5)
|
||||
if closest < uvDistance:
|
||||
uvNotPass.add(uvid)
|
||||
continue
|
||||
r = cross / d2
|
||||
px = x1 + (x2 - x1) * r
|
||||
py = y1 + (y2 - y1) * r
|
||||
closest = ((x - px)**2 + (py - y)**2)**(0.5)
|
||||
if closest < uvDistance:
|
||||
uvNotPass.add(uvid)
|
||||
uvNamesNotPass = []
|
||||
for uv in uvNotPass:
|
||||
uvNamesNotPass.append(sel+'.map['+str(uv)+']')
|
||||
cmds.select(uvNamesNotPass,r=1)
|
||||
changeSelectionType(sel,"puv")
|
||||
|
||||
def ifUVShellStack(usiA, usiB, usi_bb, p):
|
||||
# fast filter
|
||||
usiA_umin = float(int(usi_bb[usiA][0][0] * p))/p
|
||||
usiB_umin = float(int(usi_bb[usiB][0][0] * p))/p
|
||||
if not usiA_umin == usiB_umin:
|
||||
return 0
|
||||
|
||||
usiA_umax = float(int(usi_bb[usiA][0][1] * p))/p
|
||||
usiA_vmin = float(int(usi_bb[usiA][1][0] * p))/p
|
||||
usiA_vmax = float(int(usi_bb[usiA][1][1] * p))/p
|
||||
usiB_umax = float(int(usi_bb[usiB][0][1] * p))/p
|
||||
usiB_vmin = float(int(usi_bb[usiB][1][0] * p))/p
|
||||
usiB_vmax = float(int(usi_bb[usiB][1][1] * p))/p
|
||||
if usiA_umax == usiB_umax and usiA_vmin == usiB_vmin and usiA_vmax == usiB_vmax:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def ifUVShellIntersect(usiA, usiB, usi_uvedgeidOnBord, uvedgeid_uv, usi_bb):
|
||||
for edgeA in usi_uvedgeidOnBord[usiA]:
|
||||
ax = uvedgeid_uv[edgeA][0][0]
|
||||
ay = uvedgeid_uv[edgeA][0][1]
|
||||
bx = uvedgeid_uv[edgeA][1][0]
|
||||
by = uvedgeid_uv[edgeA][1][1]
|
||||
|
||||
# fast filter
|
||||
abx = [ax,bx]
|
||||
aby = [ay,by]
|
||||
if bx<ax:
|
||||
abx = [bx,ax]
|
||||
if by<ay:
|
||||
aby = [by,ay]
|
||||
|
||||
# bound filter
|
||||
bb_usiB = usi_bb[usiB]
|
||||
bb_uminB = bb_usiB[0][0]
|
||||
bb_umaxB = bb_usiB[0][1]
|
||||
bb_vminB = bb_usiB[1][0]
|
||||
bb_vmaxB = bb_usiB[1][1]
|
||||
|
||||
if abx[0] > bb_umaxB or\
|
||||
abx[1] < bb_uminB or\
|
||||
aby[0] > bb_vmaxB or\
|
||||
aby[1] < bb_vminB:
|
||||
continue
|
||||
|
||||
for edgeB in usi_uvedgeidOnBord[usiB]:
|
||||
cx = uvedgeid_uv[edgeB][0][0]
|
||||
cy = uvedgeid_uv[edgeB][0][1]
|
||||
dx = uvedgeid_uv[edgeB][1][0]
|
||||
dy = uvedgeid_uv[edgeB][1][1]
|
||||
|
||||
# fast filter
|
||||
cdx = [cx,dx]
|
||||
cdy = [cy,dy]
|
||||
if dx<cx:
|
||||
cdx = [dx,cx]
|
||||
if dy<cy:
|
||||
cdy = [dy,cy]
|
||||
if abx[0] > cdx[1] or\
|
||||
abx[1] < cdx[0] or\
|
||||
aby[0] > cdy[1] or\
|
||||
aby[1] < cdy[0]:
|
||||
continue
|
||||
|
||||
x1 = bx - ax
|
||||
y1 = by - ay
|
||||
x2 = cx - ax
|
||||
y2 = cy - ay
|
||||
cross1 = x1*y2-x2*y1
|
||||
x2 = dx - ax
|
||||
y2 = dy - ay
|
||||
cross2 = x1*y2-x2*y1
|
||||
x1 = dx - cx
|
||||
y1 = dy - cy
|
||||
x2 = ax - cx
|
||||
y2 = ay - cy
|
||||
cross3 = x1*y2-x2*y1
|
||||
x2 = bx - cx
|
||||
y2 = by - cy
|
||||
cross4 = x1*y2-x2*y1
|
||||
if (cross1*cross2 <= 0 and cross3*cross4<=0):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def ifUVShellContain(usiA,usiB,usi_uvedgeidOnBord,usi_uvidOnBord,uvedgeid_uv,uvid_uv):
|
||||
uvid = usi_uvidOnBord[usiB][0]
|
||||
intersects = 0
|
||||
ray_u = uvid_uv[uvid][0]
|
||||
ray_v = uvid_uv[uvid][1]
|
||||
|
||||
for edge in usi_uvedgeidOnBord[usiA]:
|
||||
u0 = uvedgeid_uv[edge][0][0]
|
||||
v0 = uvedgeid_uv[edge][0][1]
|
||||
u1 = uvedgeid_uv[edge][1][0]
|
||||
v1 = uvedgeid_uv[edge][1][1]
|
||||
if (v1 >= ray_v and v0 < ray_v):
|
||||
if ((u0-ray_u)*(v1-ray_v)-(v0-ray_v)*(u1-ray_u)) < 0:
|
||||
intersects += 1
|
||||
if intersects%2 == 1:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def getFacesHaveNoUV(sel):
|
||||
selList = om2.MSelectionList()
|
||||
selList.add(sel)
|
||||
selPath = selList.getDagPath(0)
|
||||
selVtxIter= om2.MItMeshVertex(selPath)
|
||||
faceidWithNoUV = []
|
||||
faceWithNoUV = []
|
||||
while not selVtxIter.isDone():
|
||||
if selVtxIter.numUVs()==0:
|
||||
faceidWithNoUV += selVtxIter.getConnectedFaces()
|
||||
selVtxIter.next()
|
||||
faceidWithNoUV = list(set(faceidWithNoUV))
|
||||
for faceid in faceidWithNoUV:
|
||||
faceWithNoUV+=[sel+'.f['+str(faceid)+']']
|
||||
return faceWithNoUV
|
||||
# checkUVBleed_0()
|
||||
# cProfile.run('checkUVBleed_0()')
|
||||
|
||||
'''
|
||||
#UI
|
||||
'''
|
||||
class ldmt_cls(QDialog):
|
||||
def __init__(self, parent = get_maya_window()):
|
||||
super(ldmt_cls, self).__init__(parent)
|
||||
self.window_name = ldmt_window_name
|
||||
self.setWindowTitle(ldmt_window_name)
|
||||
self.setWindowFlags(Qt.Window)
|
||||
self.move(QCursor.pos() + QPoint(20,20))
|
||||
# update status bar so it's not only show in help line window.
|
||||
self.set_ui()
|
||||
self.setupBtn()
|
||||
# self.statusbar.showMessage(ld.tag())
|
||||
# self.installStartBar()
|
||||
|
||||
def set_ui(self):
|
||||
main_layout = QVBoxLayout(self)
|
||||
self.ui = load_ui_file(ldmt_uifile)
|
||||
if self.ui is None:
|
||||
cmds.warning("UI file not found: {}".format(ldmt_uifile))
|
||||
return
|
||||
main_layout.addWidget(self.ui)
|
||||
|
||||
def setupBtn(self):
|
||||
self.ui.btn_check.clicked.connect(self.checkUVBleed)
|
||||
|
||||
def checkUVBleed(self):
|
||||
cmds.undoInfo(ock = 1)
|
||||
try:
|
||||
minShellBleed = int(self.ui.text_borderBleed.text())
|
||||
minBorderBleed = int(self.ui.text_borderBleed.text())
|
||||
uvSize = int(self.ui.box_textureSize.currentText())
|
||||
except:
|
||||
ld.msg("Input value is not valid!")
|
||||
LD_CheckUVBleed(uvSize,minShellBleed,minBorderBleed)
|
||||
cmds.undoInfo(cck = 1)
|
||||
|
||||
def installStartBar(self):
|
||||
allQWidgets = self.findChildren(QWidget)
|
||||
for i in allQWidgets:
|
||||
i.installEventFilter(self)
|
||||
|
||||
def eventFilter(self, obj, event ):
|
||||
'''Connect signals on mouse over'''
|
||||
if event.type() == QEvent.Enter:
|
||||
self.oldMessage = ld.tag()
|
||||
self.statusbar.showMessage(' '+obj.statusTip(),0)
|
||||
elif event.type() == QEvent.Leave:
|
||||
self.statusbar.showMessage(' '+self.oldMessage, 0)
|
||||
pass
|
||||
event.accept()
|
||||
return False
|
||||
|
||||
# def closeEvent(self,event):
|
||||
# ld.turnToolBtnOff(self,ldmt_button_name)
|
||||
# cmds.deleteUI(ldmt_window_name)
|
||||
|
||||
def ldmt_show():
|
||||
if cmds.window(ldmt_window_name, exists=True):
|
||||
cmds.deleteUI(ldmt_window_name)
|
||||
|
||||
app = QApplication.instance()
|
||||
dialog = ldmt_cls(parent=app.activeWindow())
|
||||
dialog.show()
|
||||
app.exec_()
|
||||
|
||||
if __name__ == '__main__':
|
||||
ldmt_show()
|
94
Scripts/Modeling/Edit/LDMT/ldmt_cleanMesh.py
Normal file
94
Scripts/Modeling/Edit/LDMT/ldmt_cleanMesh.py
Normal file
@ -0,0 +1,94 @@
|
||||
import os
|
||||
import math
|
||||
from ldmt_function.ldmt_loadUIFile import get_maya_window, load_ui_file
|
||||
import maya.OpenMayaUI as omui
|
||||
from ldmt_core import ldmt_cmds as ld
|
||||
from functools import partial
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
|
||||
try:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtWidgets import *
|
||||
from Qt import __version__
|
||||
from Qt.QtCompat import loadUi, wrapInstance
|
||||
except ImportError:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtUiTools import *
|
||||
from Qt import __version__
|
||||
from Qt.QtCompat import loadUi, wrapInstance
|
||||
|
||||
import maya.OpenMaya as om
|
||||
import maya.api.OpenMaya as om2
|
||||
import random
|
||||
import ast
|
||||
|
||||
LDMTPATH = ld.getPath('LDMT')
|
||||
ldmt_uifile = LDMTPATH + '/ldmt_ui/ldmt_cleanMesh.ui'
|
||||
ldmt_window_name = 'ldmt_cleanMesh'
|
||||
ldmt_button_name = 'btn_'+ldmt_window_name.split('_')[1]
|
||||
|
||||
'''
|
||||
#UI
|
||||
'''
|
||||
class ldmt_cls(QDialog):
|
||||
def __init__(self, parent = get_maya_window()):
|
||||
super(ldmt_cls, self).__init__(parent)
|
||||
self.window_name = ldmt_window_name
|
||||
self.setWindowTitle(ldmt_window_name)
|
||||
self.setWindowFlags(Qt.Window)
|
||||
self.move(QCursor.pos() + QPoint(20,20))
|
||||
# update status bar so it's not only show in help line window.
|
||||
self.set_ui()
|
||||
self.setupBtn()
|
||||
# self.statusbar.showMessage(ld.tag())
|
||||
# self.installStartBar()
|
||||
|
||||
def set_ui(self):
|
||||
main_layout = QVBoxLayout(self)
|
||||
self.ui = load_ui_file(ldmt_uifile)
|
||||
if self.ui is None:
|
||||
cmds.warning("UI file not found: {}".format(ldmt_uifile))
|
||||
return
|
||||
main_layout.addWidget(self.ui)
|
||||
|
||||
def setupBtn(self):
|
||||
self.ui.btn_select.clicked.connect(self.select)
|
||||
self.ui.btn_cleanup.clicked.connect(self.cleanup)
|
||||
def select(self):
|
||||
mel.eval('polyCleanupArgList 4 { "0","2","1","0","1","1","1","0","1","1e-005","1","1e-005","1","1e-005","0","1","1","0" };')
|
||||
def cleanup(self):
|
||||
mel.eval('polyCleanupArgList 4 { "0","1","1","0","1","1","1","0","1","1e-005","1","1e-005","1","1e-005","0","1","1","0" };')
|
||||
def installStartBar(self):
|
||||
allQWidgets = self.findChildren(QWidget)
|
||||
for i in allQWidgets:
|
||||
i.installEventFilter(self)
|
||||
|
||||
def eventFilter(self, obj, event ):
|
||||
'''Connect signals on mouse over'''
|
||||
if event.type() == QEvent.Enter:
|
||||
self.oldMessage = ld.tag()
|
||||
self.statusbar.showMessage(' '+obj.statusTip(),0)
|
||||
elif event.type() == QEvent.Leave:
|
||||
self.statusbar.showMessage(' '+self.oldMessage, 0)
|
||||
pass
|
||||
event.accept()
|
||||
return False
|
||||
|
||||
# def closeEvent(self,event):
|
||||
# ld.turnToolBtnOff(self,ldmt_button_name)
|
||||
# cmds.deleteUI(ldmt_window_name)
|
||||
|
||||
def ldmt_show():
|
||||
if cmds.window(ldmt_window_name, exists=True):
|
||||
cmds.deleteUI(ldmt_window_name)
|
||||
|
||||
app = QApplication.instance()
|
||||
dialog = ldmt_cls(parent=app.activeWindow())
|
||||
dialog.show()
|
||||
app.exec_()
|
||||
|
||||
if __name__ == '__main__':
|
||||
ldmt_show()
|
154
Scripts/Modeling/Edit/LDMT/ldmt_clothTransfer.py
Normal file
154
Scripts/Modeling/Edit/LDMT/ldmt_clothTransfer.py
Normal file
@ -0,0 +1,154 @@
|
||||
import os
|
||||
import math
|
||||
import ldmt_function.ldmt_loadUIFile
|
||||
import importlib
|
||||
#importlib.reload(ldmt_function.ldmt_loadUIFile)
|
||||
from ldmt_function.ldmt_loadUIFile import get_maya_window, load_ui_file
|
||||
import maya.OpenMayaUI as omui
|
||||
from ldmt_core import ldmt_cmds as ld
|
||||
from functools import partial
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
|
||||
try:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtWidgets import *
|
||||
# from Qt.QtUiTools import *
|
||||
from Qt import __version__
|
||||
from Qt.QtCompat import wrapInstance
|
||||
except ImportError:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
# from Qt.QtUiTools import *
|
||||
from Qt import __version__
|
||||
from Qt.QtCompat import wrapInstance
|
||||
|
||||
import maya.OpenMaya as om
|
||||
import maya.api.OpenMaya as om2
|
||||
import random
|
||||
import ast
|
||||
|
||||
LDMTPATH = ld.getPath('LDMT')
|
||||
ldmt_uifile = LDMTPATH + '/ldmt_ui/ldmt_clothTransfer.ui'
|
||||
# ldmt_list_form, ldmt_list_base = load_ui_type(ldmt_uifile)
|
||||
ldmt_window_name = 'ldmt_clothTransfer'
|
||||
ldmt_button_name = 'btn_'+ldmt_window_name.split('_')[1]
|
||||
|
||||
'''
|
||||
#Functions
|
||||
'''
|
||||
|
||||
'''
|
||||
#UI
|
||||
'''
|
||||
class ldmt_cls(QDialog):
|
||||
def __init__(self, parent = get_maya_window()):
|
||||
super(ldmt_cls, self).__init__(parent)
|
||||
self.window_name = ldmt_window_name
|
||||
self.setWindowTitle(ldmt_window_name)
|
||||
self.setWindowFlags(Qt.Window)
|
||||
# self.setupUi(self)
|
||||
# self.move(QCursor.pos() + QPoint(20,20))
|
||||
self.set_ui()
|
||||
# update status bar so it's not only show in help line window.
|
||||
self.setupBtn()
|
||||
# self.statusbar.showMessage(ld.tag())
|
||||
# self.installStartBar()
|
||||
|
||||
def set_ui(self):
|
||||
main_layout = QVBoxLayout(self)
|
||||
|
||||
self.ui = load_ui_file(ldmt_uifile)
|
||||
|
||||
main_layout.addWidget(self.ui)
|
||||
|
||||
def setupBtn(self):
|
||||
self.ui.btn_setCloth.clicked.connect(self.setCloth)
|
||||
self.ui.btn_setOrigin.clicked.connect(self.setOrigin)
|
||||
self.ui.btn_setTarget.clicked.connect(self.setTarget)
|
||||
self.ui.btn_selectCloth.clicked.connect(self.selectCloth)
|
||||
self.ui.btn_selectOrigin.clicked.connect(self.selectOrigin)
|
||||
self.ui.btn_selectTarget.clicked.connect(self.selectTarget)
|
||||
|
||||
self.ui.btn_transfer.clicked.connect(self.transfer)
|
||||
|
||||
def setCloth(self):
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
sel = sel[0]
|
||||
if sel != []:
|
||||
self.ui.btn_selectCloth.setText(str(sel))
|
||||
else:
|
||||
self.ui.btn_selectCloth.setText('...')
|
||||
def setOrigin(self):
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
sel = sel[0]
|
||||
if sel != []:
|
||||
self.ui.btn_selectOrigin.setText(str(sel))
|
||||
else:
|
||||
self.ui.btn_selectOrigin.setText('...')
|
||||
def setTarget(self):
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
sel = sel[0]
|
||||
if sel != []:
|
||||
self.ui.btn_selectTarget.setText(str(sel))
|
||||
else:
|
||||
self.ui.btn_selectTarget.setText('...')
|
||||
def selectSetObjects(self,sel):
|
||||
if sel != '...':
|
||||
cmds.select(sel,r=1)
|
||||
else:
|
||||
ld.msg('Nothing selected')
|
||||
def selectCloth(self):
|
||||
sel = self.ui.btn_selectCloth.text()
|
||||
self.selectSetObjects(sel)
|
||||
def selectOrigin(self):
|
||||
sel = self.ui.btn_selectOrigin.text()
|
||||
self.selectSetObjects(sel)
|
||||
def selectTarget(self):
|
||||
sel = self.ui.btn_selectTarget.text()
|
||||
self.selectSetObjects(sel)
|
||||
def transfer(self):
|
||||
cloth = self.ui.btn_selectCloth.text()
|
||||
origin = self.ui.btn_selectOrigin.text()
|
||||
target = self.ui.btn_selectTarget.text()
|
||||
cmds.makeIdentity(target,apply=True, t=1, r=1, s=1, n=0)
|
||||
cmds.select(cloth,r=1)
|
||||
cmds.select(origin,add=1)
|
||||
mel.eval('DeleteHistory;')
|
||||
mel.eval('CreateWrap;')
|
||||
blendObjs = [target,origin]
|
||||
blendName = cmds.blendShape(blendObjs,o='world',n='clothTransfer#')
|
||||
cmds.blendShape(blendName,e=1,w=(0,1))
|
||||
|
||||
def installStartBar(self):
|
||||
allQWidgets = self.findChildren(QWidget)
|
||||
for i in allQWidgets:
|
||||
i.installEventFilter(self)
|
||||
|
||||
def eventFilter(self, obj, event ):
|
||||
'''Connect signals on mouse over'''
|
||||
if event.type() == QEvent.Enter:
|
||||
self.oldMessage = ld.tag()
|
||||
self.statusbar.showMessage(' '+obj.statusTip(),0)
|
||||
elif event.type() == QEvent.Leave:
|
||||
self.statusbar.showMessage(' '+self.oldMessage, 0)
|
||||
pass
|
||||
event.accept()
|
||||
return False
|
||||
# def closeEvent(self,event):
|
||||
# ld.turnToolBtnOff(self,ldmt_button_name)
|
||||
# cmds.deleteUI(ldmt_window_name)
|
||||
|
||||
def ldmt_show():
|
||||
|
||||
if cmds.window(ldmt_window_name, exists=True):
|
||||
cmds.deleteUI(ldmt_window_name)
|
||||
|
||||
app = QApplication.instance()
|
||||
dialog = ldmt_cls(parent=app.activeWindow())
|
||||
dialog.show()
|
||||
app.exec_()
|
||||
|
||||
if __name__ == '__main__':
|
||||
ldmt_show()
|
2155
Scripts/Modeling/Edit/LDMT/ldmt_core/Qt.py
Normal file
2155
Scripts/Modeling/Edit/LDMT/ldmt_core/Qt.py
Normal file
File diff suppressed because it is too large
Load Diff
0
Scripts/Modeling/Edit/LDMT/ldmt_core/__init__.py
Normal file
0
Scripts/Modeling/Edit/LDMT/ldmt_core/__init__.py
Normal file
246
Scripts/Modeling/Edit/LDMT/ldmt_core/ldmt_cmds.py
Normal file
246
Scripts/Modeling/Edit/LDMT/ldmt_core/ldmt_cmds.py
Normal file
@ -0,0 +1,246 @@
|
||||
'''
|
||||
Don't edit the line above, it should be set by ldmt_setup.py automatically according to
|
||||
your installation path.
|
||||
'''
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
import maya.api.OpenMaya as om2
|
||||
try:
|
||||
import configparser as ConfigParser
|
||||
except ImportError:
|
||||
import ConfigParser
|
||||
import os
|
||||
try:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtWidgets import *
|
||||
# from Qt.QtUiTools import *
|
||||
# from Qt.QtCompat import loadUi
|
||||
from Qt import __version__
|
||||
from Qt.QtCompat import wrapInstance
|
||||
except ImportError:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
# from Qt.QtUiTools import *
|
||||
# from Qt.QtCompat import loadUi
|
||||
from Qt import __version__
|
||||
from Qt.QtCompat import wrapInstance
|
||||
|
||||
PM_startTime = cmds.timerX()
|
||||
PM_timeAdder = 0
|
||||
MAYA_version = cmds.about(v=1)
|
||||
MAYA_version_float = float(MAYA_version.split(' ')[0])
|
||||
|
||||
'''
|
||||
GLobal Environment
|
||||
'''
|
||||
def tag():
|
||||
return "Liu Dian xgits@outlook.com"
|
||||
def getPath(whatPath):
|
||||
if whatPath == 'MAYA_SCRIPT_PATH':
|
||||
MAYA_SCRIPT_PATH = os.environ['MAYA_SCRIPT_PATH']
|
||||
MAYA_SCRIPT_PATH = MAYA_SCRIPT_PATH.split(';')
|
||||
for eachPath in MAYA_SCRIPT_PATH:
|
||||
if eachPath.endswith('maya/scripts'):
|
||||
return eachPath
|
||||
elif whatPath == 'LDMT':
|
||||
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
# MAYA_SCRIPT_PATH = os.environ['MAYA_SCRIPT_PATH']
|
||||
# MAYA_SCRIPT_PATH = MAYA_SCRIPT_PATH.split(';')
|
||||
# for eachPath in MAYA_SCRIPT_PATH:
|
||||
# if eachPath.endswith('maya/scripts'):
|
||||
# MAYA_SCRIPT_PATH = eachPath
|
||||
# return MAYA_SCRIPT_PATH + '/' + 'LDMT'
|
||||
|
||||
'''
|
||||
Config
|
||||
'''
|
||||
|
||||
def getLdmtConfig(section,option):
|
||||
cf = ConfigParser.ConfigParser()
|
||||
FOLDERNAME = getPath('LDMT').split('/')[-1]
|
||||
cfPath = getPath("MAYA_SCRIPT_PATH") + "/" + FOLDERNAME + "/ldmt_config.ini"
|
||||
cf.read(cfPath)
|
||||
return cf.get(section,option)
|
||||
## math ##
|
||||
|
||||
def round(number,pre):
|
||||
if number > 0:
|
||||
return float(int(number*10**pre+0.5))/10**pre
|
||||
else:
|
||||
return float(int(number*10**pre-0.5))/10**pre
|
||||
def distance(pointA,pointB):
|
||||
return ((pointB[0]-pointA[0])**2+(pointB[1]-pointA[1])**2+(pointB[2]-pointA[2])**2)**(0.5)
|
||||
## Plugins ##
|
||||
def existsCmd(command):
|
||||
if not mel.eval('exists "'+command+'"'):
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
## Hotkeys ##
|
||||
def getOrCreateCustomHotkeySet():
|
||||
allHotkey= cmds.hotkeySet( q=1, hsa=1 )
|
||||
currentHotkey = cmds.hotkeySet( q=1, current=1 )
|
||||
if currentHotkey == 'Maya_Default' and len(allHotkey)==1:
|
||||
cmds.hotkeySet( "MyHotkeySet", current=1 )
|
||||
elif currentHotkey == 'Maya_Default':
|
||||
for i in allHotkey:
|
||||
if i != "Maya_Default":
|
||||
cmds.hotkeySet(i,e=1,current=1)
|
||||
currentHotkey = cmds.hotkeySet( q=1, current=1 )
|
||||
return currentHotkey
|
||||
## Tranforms ##
|
||||
def freeze(sel):
|
||||
cmds.makeIdentity(sel,apply=True, t=1, r=1, s=1, n=0)
|
||||
def movePivotToCenter(sel):
|
||||
selBB = cmds.polyEvaluate(sel,b=1)
|
||||
selBB_diff_x = selBB[0][1]-selBB[0][0]
|
||||
selBB_diff_y = selBB[1][1]-selBB[1][0]
|
||||
selBB_diff_z = selBB[2][1]-selBB[2][0]
|
||||
selBB_center_x = (selBB[0][1]+selBB[0][0])/2
|
||||
selBB_center_y = (selBB[1][1]+selBB[1][0])/2
|
||||
selBB_center_z = (selBB[2][1]+selBB[2][0])/2
|
||||
cmds.move(selBB_center_x, selBB_center_y, selBB_center_z, sel+".scalePivot", sel+".rotatePivot", absolute=True)
|
||||
def moveObjToZero(sel):
|
||||
cmds.move(0,0,0,sel,rpr=1)
|
||||
## Select ##
|
||||
def ls( index="all", type = "transform" ):
|
||||
# if index is str and not indicating index, then we think this is a type and return all index
|
||||
if index != "all" and index != 0:
|
||||
type = index
|
||||
# specify each type
|
||||
if type == "transform":
|
||||
sel = cmds.ls( sl=1, type = type )
|
||||
elif type in ["poly","polygon","polymesh","mesh","obj"]:
|
||||
sel = cmds.ls (sl=1, type ="transform")
|
||||
sel = cmds.filterExpand(sel,sm=12)
|
||||
elif type in ["c","cr","curve","nurbsCurve"]:
|
||||
sel = cmds.ls (sl=1, type ="transform")
|
||||
sel = cmds.filterExpand(sel,sm=9)
|
||||
# specify index
|
||||
if index == "all" or isinstance(index,(str)):
|
||||
if sel == None:
|
||||
msg("Nothing Selected")
|
||||
return None
|
||||
return sel
|
||||
elif isinstance(index,(int)):
|
||||
if sel == None:
|
||||
msg("Nothing Selected")
|
||||
return None
|
||||
return sel[index]
|
||||
## Warning ##
|
||||
def msg(msg="Heads Up!"):
|
||||
global PM_startTime
|
||||
global PM_timeAdder
|
||||
PM_offset = 0
|
||||
PM_time = cmds.timerX(startTime = PM_startTime)
|
||||
PM_startTime = cmds.timerX()
|
||||
if PM_time<1.5:
|
||||
PM_offset = 10+20*(PM_timeAdder)
|
||||
PM_timeAdder = PM_timeAdder+1
|
||||
else:
|
||||
PM_offset = 10
|
||||
PM_timeAdder = 0
|
||||
if MAYA_version_float >= 2014:
|
||||
cmds.inViewMessage(
|
||||
amg = "<span style=\"color:#ffffff\">"+ msg +"</span>",
|
||||
fade = 1, fit = 150, fst = 800, fot = 150, fof = PM_offset, bkc = 0x2288ff,
|
||||
pos = "topCenter", fontSize = 10, a = 0, ta = 0.68)
|
||||
print(msg)
|
||||
# Get Mesh Info
|
||||
def get(sel,what):
|
||||
if what == "uvid_uv":
|
||||
selMesh = MFnMesh(sel)
|
||||
uvid_uv = []
|
||||
uvArray = selMesh.getUVs()
|
||||
for i in xrange(len(uvArray[0])):
|
||||
uvid_uv.append([uvArray[0][i],uvArray[1][i]])
|
||||
return uvid_uv
|
||||
elif what == "vtxid_uvid":
|
||||
vtxid_uvid = []
|
||||
selVtxIter = MItMeshVertex(sel)
|
||||
while not selVtxIter.isDone():
|
||||
vtxid_uvid.append(list(set(selVtxIter.getUVIndices()))[0])
|
||||
selVtxIter.next()
|
||||
return vtxid_uvid
|
||||
elif what == "bb":
|
||||
return cmds.polyEvaluate(sel,b=1)
|
||||
#API
|
||||
def getDagPath(sel):
|
||||
selList = om2.MSelectionList()
|
||||
selList.add(sel)
|
||||
selPath = selList.getDagPath(0)
|
||||
return selPath
|
||||
def MFnMesh(sel):
|
||||
selPath = getDagPath(sel)
|
||||
selMesh = om2.MFnMesh(selPath)
|
||||
return selMesh
|
||||
def MItMeshVertex(sel):
|
||||
selPath = getDagPath(sel)
|
||||
selVtxIter = om2.MItMeshVertex(selPath)
|
||||
return selVtxIter
|
||||
def MItMeshEdge(sel):
|
||||
selPath = getDagPath(sel)
|
||||
selEdgeIter = om2.MItMeshEdge(selPath)
|
||||
return selEdgeIter
|
||||
def MItMeshPolygon(sel):
|
||||
selPath = getDagPath(sel)
|
||||
selPolyIter = om2.MItMeshPolygon(selPath)
|
||||
return selPolyIter
|
||||
def MItMeshFaceVertex(sel):
|
||||
selPath = getDagPath(sel)
|
||||
selFaceIter = om2.MItMeshFaceVertex(selPath)
|
||||
return selFaceIter
|
||||
#UVSet
|
||||
def switchUVSet(sel):
|
||||
allUVSets = cmds.polyUVSet(sel,q=1,auv=1)
|
||||
if len(allUVSets) < 2:
|
||||
cmds.warning("Found less than 2 UV Sets!")
|
||||
return
|
||||
firstUVSetName = allUVSets[0]
|
||||
secondUVSetName = allUVSets[1]
|
||||
currentUVSetName = cmds.polyUVSet(q=1,cuv=1)
|
||||
otherUVSetName = list( set(allUVSets).difference(set(currentUVSetName)))
|
||||
try:
|
||||
cmds.polyUVSet(sel,uvs = firstUVSetName, nuv=secondUVSetName, reorder=1)
|
||||
except:
|
||||
newUVSet = cmds.polyUVSet(sel,cr=1)
|
||||
newUVSet = newUVSet[0]
|
||||
cmds.polyUVSet(sel, uvs = firstUVSetName ,nuv= newUVSet, cp=1)
|
||||
cmds.polyUVSet(sel, uvs = secondUVSetName ,nuv= firstUVSetName, cp=1)
|
||||
cmds.polyUVSet(sel, uvs = newUVSet ,nuv= secondUVSetName, cp=1)
|
||||
cmds.polyUVSet(sel, uvs = newUVSet, d=1)
|
||||
if currentUVSetName == firstUVSetName:
|
||||
cmds.polyUVSet(sel,uvs = secondUVSetName , e=1,cuv=1)
|
||||
else:
|
||||
cmds.polyUVSet(sel,uvs = firstUVSetName , e=1,cuv=1)
|
||||
cmds.polyUVSet(sel,currentUVSet=1,uvSet=otherUVSetName)
|
||||
#UI
|
||||
|
||||
def turnToolBtnOff(self,buttonName):
|
||||
pass
|
||||
windowName = self.window_name
|
||||
mainWindow = self.parentWidget()
|
||||
ldmt_mainWindow = mainWindow.findChild(QMainWindow,'LDMT_mainUI')
|
||||
exec("buttonObj = ldmt_mainWindow.ui.%s"%(buttonName))
|
||||
buttonObj.setStyleSheet('\
|
||||
QPushButton{\
|
||||
border:1px solid rgb(30,30,30);\
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(175, 175,175, 235), stop:1 rgba(235, 235, 235, 195));\
|
||||
color:rgb(25,25,25);}\
|
||||
QPushButton:hover{\
|
||||
border:1px solid rgb(30,30,30);\
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(190, 190, 190, 225), stop:1 rgba(245, 245, 245, 195));\
|
||||
color:rgb(25,25,25);\
|
||||
}\
|
||||
QPushButton:pressed{ \
|
||||
border:1px solid rgb(30,30,30);\
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(215, 215, 215, 195), stop:1 rgba(155, 155,155, 235));\
|
||||
color:rgb(25,25,25);}\
|
||||
')
|
||||
def showAttributeEditor():
|
||||
mel.eval("AttributeEditor;")
|
||||
def showChannelBox():
|
||||
mel.eval("AttributeEditor;")
|
||||
cmds.ShowAttributeEditorOrChannelBox()
|
||||
|
517
Scripts/Modeling/Edit/LDMT/ldmt_core/mayaMixin.py
Normal file
517
Scripts/Modeling/Edit/LDMT/ldmt_core/mayaMixin.py
Normal file
@ -0,0 +1,517 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Maya mixin classes to add common functionality for custom PyQt/PySide widgets in Maya.
|
||||
|
||||
* MayaQWidgetBaseMixin Mixin that should be applied to all custom QWidgets created for Maya
|
||||
to automatically handle setting the objectName and parenting
|
||||
|
||||
* MayaQWidgetDockableMixin Mixin that adds dockable capabilities within Maya controlled with
|
||||
the show() function
|
||||
"""
|
||||
|
||||
import uuid
|
||||
|
||||
from maya import cmds
|
||||
from maya import mel
|
||||
from maya import OpenMayaUI as omui
|
||||
|
||||
# Import available PySide or PyQt package, as it will work with both
|
||||
try:
|
||||
from Qt.QtCore import Qt, QPoint, QSize
|
||||
from Qt.QtCore import Signal
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtCompat import wrapInstance
|
||||
_qtImported = 'PySide'
|
||||
except ImportError, e1:
|
||||
try:
|
||||
from Qt.QtCore import Qt, QPoint, QSize
|
||||
from Qt.QtCore import pyqtSignal as Signal
|
||||
from Qt.QtGui import *
|
||||
from sip import wrapinstance as wrapInstance
|
||||
_qtImported = 'PyQt4'
|
||||
except ImportError, e2:
|
||||
raise ImportError, '%s, %s'%(e1,e2)
|
||||
|
||||
class MayaQWidgetBaseMixin(object):
|
||||
'''
|
||||
Handle common actions for Maya Qt widgets during initialization:
|
||||
* auto-naming a Widget so it can be looked up as a string through
|
||||
maya.OpenMayaUI.MQtUtil.findControl()
|
||||
* parenting the widget under the main maya window if no parent is explicitly
|
||||
specified so not to have the Window disappear when the instance variable
|
||||
goes out of scope
|
||||
|
||||
Integration Notes:
|
||||
Inheritance ordering: This class must be placed *BEFORE* the Qt class for proper execution
|
||||
This is needed to workaround a bug where PyQt/PySide does not call super() in its own __init__ functions
|
||||
|
||||
Example:
|
||||
class MyQWidget(MayaQWidgetBaseMixin, QPushButton):
|
||||
def __init__(self, parent=None):
|
||||
super(MyQWidget, self).__init__(parent=parent)
|
||||
self.setText('Push Me')
|
||||
myWidget = MyQWidget()
|
||||
myWidget.show()
|
||||
print myWidget.objectName()
|
||||
'''
|
||||
def __init__(self, parent=None, *args, **kwargs):
|
||||
super(MayaQWidgetBaseMixin, self).__init__(parent=parent, *args, **kwargs) # Init all baseclasses (including QWidget) of the main class
|
||||
self._initForMaya(parent=parent)
|
||||
|
||||
def _initForMaya(self, parent=None, *args, **kwargs):
|
||||
'''
|
||||
Handle the auto-parenting and auto-naming.
|
||||
|
||||
:Parameters:
|
||||
parent (string)
|
||||
Explicitly specify the QWidget parent. If 'None', then automatically
|
||||
parent under the main Maya window
|
||||
'''
|
||||
# Set parent to Maya main window if parent=None
|
||||
if parent == None:
|
||||
self._makeMayaStandaloneWindow()
|
||||
|
||||
# Set a unique object name string so Maya can easily look it up
|
||||
if self.objectName() == '':
|
||||
self.setObjectName('%s_%s'%(self.__class__.__name__, uuid.uuid4()))
|
||||
|
||||
def _makeMayaStandaloneWindow(self):
|
||||
'''Make a standalone window, though parented under Maya's mainWindow.
|
||||
The parenting under Maya's mainWindow is done so that the QWidget will not
|
||||
auto-destroy itself when the instance variable goes out of scope.
|
||||
'''
|
||||
origParent = self.parent()
|
||||
|
||||
# Parent under the main Maya window
|
||||
mainWindowPtr = omui.MQtUtil.mainWindow()
|
||||
mainWindow = wrapInstance(long(mainWindowPtr), QMainWindow)
|
||||
self.setParent(mainWindow)
|
||||
|
||||
# Make this widget appear as a standalone window even though it is parented
|
||||
if isinstance(self, QDockWidget):
|
||||
self.setWindowFlags(Qt.Dialog|Qt.FramelessWindowHint)
|
||||
else:
|
||||
self.setWindowFlags(Qt.Window)
|
||||
|
||||
# Delete the parent QDockWidget if applicable
|
||||
if isinstance(origParent, QDockWidget):
|
||||
origParent.close()
|
||||
|
||||
|
||||
class MayaQDockWidget(MayaQWidgetBaseMixin,QDockWidget):
|
||||
'''QDockWidget tailored for use with Maya.
|
||||
Mimics the behavior performed by Maya's internal QMayaDockWidget class and the dockControl command
|
||||
|
||||
:Signals:
|
||||
closeEventTriggered: emitted when a closeEvent occurs
|
||||
|
||||
:Known Issues:
|
||||
* Manually dragging the DockWidget to dock in the Main MayaWindow will have it resize to the 'sizeHint' size
|
||||
of the child widget() instead of preserving its existing size.
|
||||
'''
|
||||
# Custom Signals
|
||||
closeEventTriggered = Signal() # Qt Signal triggered when closeEvent occurs
|
||||
|
||||
def __init__(self, parent=None, *args, **kwargs):
|
||||
super(MayaQDockWidget, self).__init__(parent=parent, *args, **kwargs) # Init all baseclasses (including QWidget) of the main class
|
||||
|
||||
# == Mimic operations performed by Maya internal QmayaDockWidget ==
|
||||
self.setAttribute(Qt.WA_MacAlwaysShowToolWindow)
|
||||
|
||||
# WORKAROUND: The mainWindow.handleDockWidgetVisChange may not be present on some PyQt and PySide systems.
|
||||
# Handle case if it fails to connect to the attr.
|
||||
mainWindowPtr = omui.MQtUtil.mainWindow()
|
||||
mainWindow = wrapInstance(long(mainWindowPtr), QMainWindow)
|
||||
try:
|
||||
self.visibilityChanged.connect(mainWindow.handleDockWidgetVisChange)
|
||||
except AttributeError, e:
|
||||
# Error connecting visibilityChanged trigger to mainWindow.handleDockWidgetVisChange.
|
||||
# Falling back to using MEL command directly.
|
||||
mel.eval('evalDeferred("updateEditorToggleCheckboxes()")') # Currently mainWindow.handleDockWidgetVisChange only makes this updateEditorToggleCheckboxes call
|
||||
|
||||
def setArea(self, area):
|
||||
'''Set the docking area
|
||||
'''
|
||||
# Skip setting the area if no area value passed in
|
||||
if area == Qt.NoDockWidgetArea:
|
||||
return
|
||||
# Mimic operations performed by Maya dockControl command
|
||||
mainWindowPtr = omui.MQtUtil.mainWindow()
|
||||
mainWindow = wrapInstance(long(mainWindowPtr), QMainWindow)
|
||||
childrenList = mainWindow.children()
|
||||
foundDockWidgetToTab = False
|
||||
for child in childrenList:
|
||||
# Create Tabbed dock if a QDockWidget already at that area
|
||||
if (child != self) and (isinstance(child, QDockWidget)):
|
||||
if not child.isHidden() and not child.isFloating():
|
||||
if mainWindow.dockWidgetArea(child) == area:
|
||||
mainWindow.tabifyDockWidget(child, self)
|
||||
self.raise_()
|
||||
foundDockWidgetToTab = True
|
||||
break
|
||||
# If no other QDockWidget at that area, then just add it
|
||||
if not foundDockWidgetToTab:
|
||||
mainWindow.addDockWidget(area, self)
|
||||
|
||||
|
||||
def resizeEvent(self, evt):
|
||||
'''Store off the 'savedSize' property used by Maya's QMainWindow to set the
|
||||
size of the widget when it is being docked.
|
||||
'''
|
||||
self.setProperty('savedSize', self.size())
|
||||
return super(MayaQDockWidget, self).resizeEvent(evt)
|
||||
|
||||
def closeEvent(self, evt):
|
||||
'''Hide the QDockWidget and trigger the closeEventTriggered signal
|
||||
'''
|
||||
# Handle the standard closeEvent()
|
||||
super(MayaQDockWidget, self).closeEvent(evt)
|
||||
|
||||
if evt.isAccepted():
|
||||
# Force visibility to False
|
||||
self.setVisible(False) # since this does not seem to have happened already
|
||||
|
||||
# Emit that a close event is occurring
|
||||
self.closeEventTriggered.emit()
|
||||
|
||||
class MayaQWidgetDockableMixin(MayaQWidgetBaseMixin):
|
||||
'''
|
||||
Handle Maya dockable actions controlled with the show() function.
|
||||
|
||||
Integration Notes:
|
||||
Inheritance ordering: This class must be placed *BEFORE* the Qt class for proper execution
|
||||
This is needed to workaround a bug where PyQt/PySide does not call super() in its own __init__ functions
|
||||
|
||||
Example:
|
||||
class MyQWidget(MayaQWidgetDockableMixin, QPushButton):
|
||||
def __init__(self, parent=None):
|
||||
super(MyQWidget, self).__init__(parent=parent)
|
||||
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred )
|
||||
self.setText('Push Me')
|
||||
myWidget = MyQWidget()
|
||||
myWidget.show(dockable=True)
|
||||
myWidget.show(dockable=False)
|
||||
print myWidget.showRepr()
|
||||
'''
|
||||
def setDockableParameters(self, dockable=None, floating=None, area=None, allowedArea=None, width=None, height=None, x=None, y=None, *args, **kwargs):
|
||||
'''
|
||||
Set the dockable parameters.
|
||||
|
||||
:Parameters:
|
||||
dockable (bool)
|
||||
Specify if the window is dockable (default=False)
|
||||
floating (bool)
|
||||
Should the window be floating or docked (default=True)
|
||||
area (string)
|
||||
Default area to dock into (default='left')
|
||||
Options: 'top', 'left', 'right', 'bottom'
|
||||
allowedArea (string)
|
||||
Allowed dock areas (default='all')
|
||||
Options: 'top', 'left', 'right', 'bottom', 'all'
|
||||
width (int)
|
||||
Width of the window
|
||||
height (int)
|
||||
Height of the window
|
||||
x (int)
|
||||
left edge of the window
|
||||
y (int)
|
||||
top edge of the window
|
||||
|
||||
:See: show(), hide(), and setVisible()
|
||||
'''
|
||||
if (dockable == True) or (dockable == None and self.isDockable()): # == Handle docked window ==
|
||||
# Conversion parameters (used below)
|
||||
dockAreaStrMap = {
|
||||
'left' : Qt.LeftDockWidgetArea,
|
||||
'right' : Qt.RightDockWidgetArea,
|
||||
'top' : Qt.TopDockWidgetArea,
|
||||
'bottom' : Qt.BottomDockWidgetArea,
|
||||
'all' : Qt.AllDockWidgetAreas,
|
||||
'none' : Qt.NoDockWidgetArea, # Note: Not currently supported in maya dockControl command
|
||||
}
|
||||
|
||||
# Create dockControl (QDockWidget) if needed
|
||||
if dockable == True and not self.isDockable():
|
||||
# Retrieve original position and size
|
||||
# Position
|
||||
if x == None:
|
||||
x = self.x()
|
||||
if y == None:
|
||||
y = self.y()
|
||||
# Size
|
||||
unininitializedSize = QSize(640,480) # Hardcode: (640,480) is the default size for a QWidget
|
||||
if self.size() == unininitializedSize:
|
||||
# Get size from widget sizeHint if size not yet initialized (before the first show())
|
||||
widgetSizeHint = self.sizeHint()
|
||||
else:
|
||||
widgetSizeHint = self.size() # use the current size of the widget
|
||||
if width == None:
|
||||
width = widgetSizeHint.width()
|
||||
if height == None:
|
||||
height = widgetSizeHint.height()
|
||||
|
||||
# Create the QDockWidget
|
||||
dockWidget = MayaQDockWidget()
|
||||
dockWidget.setWindowTitle(self.windowTitle())
|
||||
dockWidget.setWidget(self)
|
||||
|
||||
# By default, when making dockable, make it floating
|
||||
# This addresses an issue on Windows with the window decorators
|
||||
# not showing up. Setting this here will cause setFloating() to be called below.
|
||||
if floating == None:
|
||||
floating = True
|
||||
|
||||
# Hook up signals
|
||||
dockWidget.topLevelChanged.connect(self.floatingChanged)
|
||||
dockWidget.closeEventTriggered.connect(self.dockCloseEventTriggered)
|
||||
else:
|
||||
if floating == True:
|
||||
# Retrieve original position (if floating)
|
||||
pos = self.parent().mapToGlobal( QPoint(0,0) )
|
||||
if x == None:
|
||||
x = pos.x()
|
||||
if y == None:
|
||||
y = pos.y()
|
||||
|
||||
# Retrieve original size
|
||||
if width == None:
|
||||
width = self.width()
|
||||
if height == None:
|
||||
height = self.height()
|
||||
|
||||
# Get dock widget identifier
|
||||
dockWidget = self.parent()
|
||||
|
||||
# Update dock values
|
||||
if area != None:
|
||||
areaValue = dockAreaStrMap.get(area, Qt.LeftDockWidgetArea)
|
||||
dockWidget.setArea(areaValue)
|
||||
if allowedArea != None:
|
||||
areaValue = dockAreaStrMap.get(allowedArea, Qt.AllDockWidgetAreas)
|
||||
dockWidget.setAllowedArea(areaValue)
|
||||
if floating != None:
|
||||
dockWidget.setFloating(floating)
|
||||
|
||||
# Position window
|
||||
if dockWidget.isFloating() and ((x != None) or (y != None)):
|
||||
dockPos = dockWidget.mapToGlobal( QPoint(0,0) )
|
||||
if x == None:
|
||||
x = dockPos.x()
|
||||
if y == None:
|
||||
y = dockPos.y()
|
||||
dockWidget.move(x,y)
|
||||
if (width != None) or (height != None):
|
||||
if width == None:
|
||||
width = self.width()
|
||||
if height == None:
|
||||
height = self.height()
|
||||
# Perform first resize on dock, determine delta with widget, and resize with that adjustment
|
||||
# Result: Keeps the content widget at the same size whether under the QDockWidget or a standalone window
|
||||
dockWidget.resize(width, height) # Size once to know the difference in the dockWidget to the targetSize
|
||||
dockWidgetSize = dockWidget.size() + QSize(width,height)-self.size() # find the delta and add it to the current dock size
|
||||
# Perform the final resize (call MayaQDockWidget.resize() which also sets the 'savedSize' property used for sizing when docking to the Maya MainWindow)
|
||||
dockWidget.resize(dockWidgetSize)
|
||||
|
||||
else: # == Handle Standalone Window ==
|
||||
# Make standalone as needed
|
||||
if dockable == False and self.isDockable():
|
||||
# Retrieve original position and size
|
||||
dockPos = self.parent().mapToGlobal( QPoint(0,0) )
|
||||
if x == None:
|
||||
x = dockPos.x()
|
||||
if y == None:
|
||||
y = dockPos.y()
|
||||
if width == None:
|
||||
width = self.width()
|
||||
if height == None:
|
||||
height = self.height()
|
||||
# Turn into a standalone window and reposition
|
||||
currentVisibility = self.isVisible()
|
||||
self._makeMayaStandaloneWindow() # Set the parent back to Maya and remove the parent dock widget
|
||||
self.setVisible(currentVisibility)
|
||||
|
||||
# Handle position and sizing
|
||||
if (width != None) or (height != None):
|
||||
if width == None:
|
||||
width = self.width()
|
||||
if height == None:
|
||||
height = self.height()
|
||||
self.resize(width, height)
|
||||
if (x != None) or (y != None):
|
||||
if x == None:
|
||||
x = self.x()
|
||||
if y == None:
|
||||
y = self.y()
|
||||
self.move(x,y)
|
||||
|
||||
def show(self, *args, **kwargs):
|
||||
'''
|
||||
Show the QWidget window. Overrides standard QWidget.show()
|
||||
|
||||
:See: setDockableParameters() for a list of parameters
|
||||
'''
|
||||
# Update the dockable parameters first (if supplied)
|
||||
if len(args) or len(kwargs):
|
||||
self.setDockableParameters(*args, **kwargs)
|
||||
|
||||
# Handle the standard setVisible() operation of show()
|
||||
QWidget.setVisible(self, True) # NOTE: Explicitly calling QWidget.setVisible() as using super() breaks in PySide: super(self.__class__, self).show()
|
||||
|
||||
# Handle special case if the parent is a QDockWidget (dockControl)
|
||||
parent = self.parent()
|
||||
if isinstance(parent, QDockWidget):
|
||||
parent.show()
|
||||
|
||||
def hide(self, *args, **kwargs):
|
||||
'''Hides the widget. Will hide the parent widget if it is a QDockWidget.
|
||||
Overrides standard QWidget.hide()
|
||||
'''
|
||||
# Update the dockable parameters first (if supplied)
|
||||
if len(args) or len(kwargs):
|
||||
self.setDockableParameters(*args, **kwargs)
|
||||
|
||||
# Handle special case if the parent is a QDockWidget (dockControl)
|
||||
parent = self.parent()
|
||||
if isinstance(parent, QDockWidget):
|
||||
parent.hide()
|
||||
|
||||
QWidget.setVisible(self, False) # NOTE: Explicitly calling QWidget.setVisible() as using super() breaks in PySide: super(self.__class__, self).show()
|
||||
|
||||
def setVisible(self, makeVisible, *args, **kwargs):
|
||||
'''
|
||||
Show/hide the QWidget window. Overrides standard QWidget.setVisible() to pass along additional arguments
|
||||
|
||||
:See: show() and hide()
|
||||
'''
|
||||
if (makeVisible == True):
|
||||
return self.show(*args, **kwargs)
|
||||
else:
|
||||
return self.hide(*args, **kwargs)
|
||||
|
||||
def raise_(self):
|
||||
'''Raises the widget to the top. Will raise the parent widget if it is a QDockWidget.
|
||||
Overrides standard QWidget.raise_()
|
||||
'''
|
||||
# Handle special case if the parent is a QDockWidget (dockControl)
|
||||
parent = self.parent()
|
||||
if isinstance(parent, QDockWidget):
|
||||
parent.raise_()
|
||||
else:
|
||||
QWidget.raise_(self) # NOTE: Explicitly using QWidget as using super() breaks in PySide: super(self.__class__, self).show()
|
||||
|
||||
def isDockable(self):
|
||||
'''Return if the widget is currently dockable (under a QDockWidget)
|
||||
|
||||
:Return: bool
|
||||
'''
|
||||
parent = self.parent()
|
||||
return isinstance(parent, QDockWidget)
|
||||
|
||||
def isFloating(self):
|
||||
'''Return if the widget is currently floating (under a QDockWidget)
|
||||
Will return True if is a standalone window OR is a floating dockable window.
|
||||
|
||||
:Return: bool
|
||||
'''
|
||||
parent = self.parent()
|
||||
if not isinstance(parent, QDockWidget):
|
||||
return True
|
||||
else:
|
||||
return parent.isFloating()
|
||||
|
||||
def floatingChanged(self, isFloating):
|
||||
'''Triggered when QDockWidget.topLevelChanged() signal is triggered.
|
||||
Stub function. Override to perform actions when this happens.
|
||||
'''
|
||||
pass
|
||||
|
||||
def dockCloseEventTriggered(self):
|
||||
'''Triggered when QDockWidget.closeEventTriggered() signal is triggered.
|
||||
Stub function. Override to perform actions when this happens.
|
||||
'''
|
||||
pass
|
||||
|
||||
def dockArea(self):
|
||||
'''Return area if the widget is currently docked to the Maya MainWindow
|
||||
Will return None if not dockable
|
||||
|
||||
:Return: str
|
||||
'''
|
||||
dockControlQt = self.parent()
|
||||
|
||||
if not isinstance(dockControlQt, QDockWidget):
|
||||
return None
|
||||
else:
|
||||
mainWindowPtr = omui.MQtUtil.mainWindow()
|
||||
mainWindow = wrapInstance(long(mainWindowPtr), QMainWindow)
|
||||
dockAreaMap = {
|
||||
Qt.LeftDockWidgetArea : 'left',
|
||||
Qt.RightDockWidgetArea : 'right',
|
||||
Qt.TopDockWidgetArea : 'top',
|
||||
Qt.BottomDockWidgetArea : 'bottom',
|
||||
Qt.AllDockWidgetAreas : 'all',
|
||||
Qt.NoDockWidgetArea : 'none', # Note: 'none' not supported in maya dockControl command
|
||||
}
|
||||
dockWidgetAreaBitmap = mainWindow.dockWidgetArea(dockControlQt)
|
||||
return dockAreaMap[dockWidgetAreaBitmap]
|
||||
|
||||
def setWindowTitle(self, val):
|
||||
'''Sets the QWidget's title and also it's parent QDockWidget's title if dockable.
|
||||
|
||||
:Return: None
|
||||
'''
|
||||
# Handle the standard setVisible() operation of show()
|
||||
QWidget.setWindowTitle(self, val) # NOTE: Explicitly calling QWidget.setWindowTitle() as using super() breaks in PySide: super(self.__class__, self).show()
|
||||
|
||||
# Handle special case if the parent is a QDockWidget (dockControl)
|
||||
parent = self.parent()
|
||||
if isinstance(parent, QDockWidget):
|
||||
parent.setWindowTitle(val)
|
||||
|
||||
def showRepr(self):
|
||||
'''Present a string of the parameters used to reproduce the current state of the
|
||||
widget used in the show() command.
|
||||
|
||||
:Return: str
|
||||
'''
|
||||
reprDict = {}
|
||||
reprDict['dockable'] = self.isDockable()
|
||||
reprDict['floating'] = self.isFloating()
|
||||
reprDict['area'] = self.dockArea()
|
||||
#reprDict['allowedArea'] = ??
|
||||
if reprDict['dockable'] == True:
|
||||
dockCtrl = self.parent()
|
||||
pos = dockCtrl.mapToGlobal( QPoint(0,0) )
|
||||
else:
|
||||
pos = self.pos()
|
||||
sz = self.geometry().size()
|
||||
reprDict['x'] = pos.x()
|
||||
reprDict['y'] = pos.y()
|
||||
reprDict['width'] = sz.width()
|
||||
reprDict['height'] = sz.height()
|
||||
|
||||
# Construct the repr show() string
|
||||
reprShowList = ['%s=%r'%(k,v) for k,v in reprDict.items() if v != None]
|
||||
reprShowStr = 'show(%s)'%(', '.join(reprShowList))
|
||||
return reprShowStr
|
||||
# Copyright (C) 1997-2014 Autodesk, Inc., and/or its licensors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# The coded instructions, statements, computer programs, and/or related
|
||||
# material (collectively the "Data") in these files contain unpublished
|
||||
# information proprietary to Autodesk, Inc. ("Autodesk") and/or its licensors,
|
||||
# which is protected by U.S. and Canadian federal copyright law and by
|
||||
# international treaties.
|
||||
#
|
||||
# The Data is provided for use exclusively by You. You have the right to use,
|
||||
# modify, and incorporate this Data into other products for purposes authorized
|
||||
# by the Autodesk software license agreement, without fee.
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. AUTODESK
|
||||
# DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTIES
|
||||
# INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF NON-INFRINGEMENT,
|
||||
# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR ARISING FROM A COURSE
|
||||
# OF DEALING, USAGE, OR TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS
|
||||
# LICENSORS BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL,
|
||||
# DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK AND/OR ITS
|
||||
# LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY OR PROBABILITY OF SUCH DAMAGES.
|
||||
|
26
Scripts/Modeling/Edit/LDMT/ldmt_deleteNamespace.py
Normal file
26
Scripts/Modeling/Edit/LDMT/ldmt_deleteNamespace.py
Normal file
@ -0,0 +1,26 @@
|
||||
import maya.cmds as cmds
|
||||
def remove_namespaces(node):
|
||||
|
||||
try:
|
||||
# Note rsplit instead of split
|
||||
|
||||
namespace, name = node.rsplit(":", 1)
|
||||
except:
|
||||
namespace, name = None, node
|
||||
|
||||
if namespace:
|
||||
try:
|
||||
cmds.rename(node, name)
|
||||
except RuntimeError:
|
||||
# Can't remove namespaces from read-only nodes
|
||||
# E.g. namespaces embedded in references
|
||||
pass
|
||||
|
||||
def deleteNamespace():
|
||||
for node in cmds.ls(sl=1):
|
||||
# Remove namespaces of all children first
|
||||
for descendent in cmds.listRelatives(node, allDescendents=True):
|
||||
remove_namespaces(descendent)
|
||||
|
||||
# Finally, remove namespace from current selection
|
||||
remove_namespaces(node)
|
0
Scripts/Modeling/Edit/LDMT/ldmt_exe/__init__.py
Normal file
0
Scripts/Modeling/Edit/LDMT/ldmt_exe/__init__.py
Normal file
BIN
Scripts/Modeling/Edit/LDMT/ldmt_exe/instantMesh.exe
Normal file
BIN
Scripts/Modeling/Edit/LDMT/ldmt_exe/instantMesh.exe
Normal file
Binary file not shown.
2
Scripts/Modeling/Edit/LDMT/ldmt_exe/removePyc.bat
Normal file
2
Scripts/Modeling/Edit/LDMT/ldmt_exe/removePyc.bat
Normal file
@ -0,0 +1,2 @@
|
||||
@echo off
|
||||
python removePyc.py %*
|
14
Scripts/Modeling/Edit/LDMT/ldmt_exe/removePyc.py
Normal file
14
Scripts/Modeling/Edit/LDMT/ldmt_exe/removePyc.py
Normal file
@ -0,0 +1,14 @@
|
||||
import os
|
||||
def deleteFileWithFormat(targetFolder, targetFormat):
|
||||
for root,dirs,files in os.walk(targetFolder):
|
||||
for file in files:
|
||||
filePath = os.path.join(root,file)
|
||||
if filePath.endswith(targetFormat):
|
||||
os.remove(filePath)
|
||||
def run():
|
||||
getCurrentFolder = os.getcwd()
|
||||
targetFolder = getCurrentFolder[:-9]
|
||||
deleteFileWithFormat(targetFolder,'pyc')
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
47
Scripts/Modeling/Edit/LDMT/ldmt_fixReverse.py
Normal file
47
Scripts/Modeling/Edit/LDMT/ldmt_fixReverse.py
Normal file
@ -0,0 +1,47 @@
|
||||
import maya.cmds as cmds
|
||||
|
||||
def fixReverse():
|
||||
cmds.undoInfo(ock = 1)
|
||||
sel = cmds.ls(sl=1)
|
||||
selAll = cmds.filterExpand(sel,sm=12)
|
||||
if selAll == None:
|
||||
cmds.warning("Nothing Selected!")
|
||||
return
|
||||
for sel_child in selAll:
|
||||
cmds.select(sel_child)
|
||||
fixReverseDo(sel_child)
|
||||
cmds.select(sel,r=1)
|
||||
cmds.undoInfo(cck = 1)
|
||||
|
||||
def dotProduct(vecA,vecB):
|
||||
return vecA[0]*vecB[0] + vecA[1]*vecB[1] + vecA[2]*vecB[2]
|
||||
|
||||
def fixReverseDo(sel_child):
|
||||
selShape = sel_child
|
||||
if len(selShape) == 0:
|
||||
print("Nothing Selected!")
|
||||
else:
|
||||
node_CPOM = cmds.createNode('closestPointOnMesh')
|
||||
selShape_worldMesh = selShape + '.worldMesh[0]'
|
||||
selShape_worldMatrix = selShape + '.worldMatrix[0]'
|
||||
node_CPOM_inMesh = node_CPOM + '.inMesh'
|
||||
node_CPOM_inPosition = node_CPOM + '.inPosition'
|
||||
node_CPOM_inputMatrix = node_CPOM + ".inputMatrix"
|
||||
node_CPOM_result_normal = node_CPOM + ".result.normal"
|
||||
node_CPOM_outPosition = node_CPOM + ".position"
|
||||
persp_translate = "persp.translate"
|
||||
|
||||
cmds.connectAttr(selShape_worldMesh, node_CPOM_inMesh ,force=1)
|
||||
cmds.connectAttr(persp_translate, node_CPOM_inPosition ,force=1)
|
||||
cmds.connectAttr(selShape_worldMatrix, node_CPOM_inputMatrix ,force=1)
|
||||
|
||||
vec_persp_pos = cmds.getAttr(persp_translate)
|
||||
vec_closestPoint_pos = cmds.getAttr(node_CPOM_outPosition)
|
||||
vec_closestPoint_normal = cmds.getAttr(node_CPOM_result_normal)
|
||||
vec_persp_closestPoint = [vec_persp_pos[0][0] - vec_closestPoint_pos[0][0],
|
||||
vec_persp_pos[0][1] - vec_closestPoint_pos[0][1],
|
||||
vec_persp_pos[0][2] - vec_closestPoint_pos[0][2]]
|
||||
dotProductResult = dotProduct(vec_persp_closestPoint,vec_closestPoint_normal[0])
|
||||
if dotProductResult<0:
|
||||
cmds.polyNormal(selShape,normalMode=0,userNormalMode=1,ch=1)
|
||||
cmds.delete(node_CPOM)
|
61
Scripts/Modeling/Edit/LDMT/ldmt_function/ldmt_loadUIFile.py
Normal file
61
Scripts/Modeling/Edit/LDMT/ldmt_function/ldmt_loadUIFile.py
Normal file
@ -0,0 +1,61 @@
|
||||
#from Qt.QtCompat import wrapInstance, getCppPointer
|
||||
import os
|
||||
import maya.cmds as cmds
|
||||
import maya.OpenMayaUI as omui
|
||||
try:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtWidgets import *
|
||||
from Qt import __version__
|
||||
# from Qt.QtUiTools import QUiLoader
|
||||
from Qt.QtCompat import loadUi
|
||||
# from pyside2uic import *
|
||||
from Qt.QtCompat import wrapInstance
|
||||
|
||||
except ImportError:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
from Qt import __version__
|
||||
# from pysideuic import *
|
||||
from Qt.QtCompat import wrapInstance
|
||||
# from cStringIO import StringIO
|
||||
# import xml.etree.ElementTree as xml
|
||||
|
||||
def get_maya_window():
|
||||
|
||||
ptr = omui.MQtUtil.mainWindow()
|
||||
#if ptr is not None:
|
||||
return wrapInstance(int(ptr), QMainWindow)
|
||||
|
||||
def load_ui_file(ui_path):
|
||||
if not os.path.exists(ui_path):
|
||||
cmds.warning("UI file not found: {}".format(ui_path))
|
||||
return None
|
||||
# ui_file = QFile(ui_path)
|
||||
# ui_file.open(QFile.ReadOnly)
|
||||
# ui = loadUi(ui_file)
|
||||
ui = loadUi(ui_path)
|
||||
# ui = QUiLoader().load(ui_file)
|
||||
# ui_file.close()
|
||||
return ui
|
||||
|
||||
def load_ui_type(ui_path):
|
||||
pass
|
||||
# parsed = xml.parse(ui_file)
|
||||
# widget_class = parsed.find('widget').get('class')
|
||||
# form_class = parsed.find('class').text
|
||||
|
||||
# with open(ui_file,'r') as f:
|
||||
# o = StringIO()
|
||||
# frame = {}
|
||||
|
||||
# compileUi(f, o, indent = 0)
|
||||
# pyc = compile(o.getvalue(), '<string>', 'exec')
|
||||
# exec(pyc, frame)
|
||||
|
||||
|
||||
# # Fetch the base_class and form class based on their type in the xml from design
|
||||
# form_class = frame['Ui_{0}'.format(form_class)]
|
||||
# base_class = eval('{0}'.format(widget_class))
|
||||
|
||||
# return form_class, base_class
|
@ -0,0 +1,30 @@
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
import maya.api.OpenMaya as om2
|
||||
|
||||
def morph2UV(baseObj):
|
||||
sel = baseObj
|
||||
selList = om2.MSelectionList()
|
||||
selList.add(sel)
|
||||
path = selList.getDagPath(0)
|
||||
myMesh = om2.MFnMesh(path)
|
||||
newPointArray = om2.MPointArray()
|
||||
space = om2.MSpace.kWorld
|
||||
myMesh_UVs = myMesh.getUVs()
|
||||
myMesh_points = myMesh.getPoints()
|
||||
# for i in range(myMesh.numVertices):
|
||||
myMesh_itVertex = om2.MItMeshVertex(path)
|
||||
points = om2.MPointArray()
|
||||
while not myMesh_itVertex.isDone():
|
||||
vertIndex = myMesh_itVertex.index()
|
||||
gotUV = myMesh_itVertex.getUV()
|
||||
point = om2.MPoint(gotUV[0],gotUV[1],0)
|
||||
points.append(point)
|
||||
myMesh_itVertex.next()
|
||||
myMesh.setPoints(points,space)
|
||||
|
||||
def runMorph2UV(sel):
|
||||
baseObjDup = cmds.duplicate(sel)
|
||||
baseObj = baseObjDup[0]
|
||||
morph2UV(baseObj)
|
||||
return baseObj
|
75
Scripts/Modeling/Edit/LDMT/ldmt_function/ldmt_morphToUV.py
Normal file
75
Scripts/Modeling/Edit/LDMT/ldmt_function/ldmt_morphToUV.py
Normal file
@ -0,0 +1,75 @@
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
import maya.api.OpenMaya as om2
|
||||
def deleteNoUV():
|
||||
selObj = cmds.ls(sl=1,o=1)
|
||||
selObj = selObj[0]
|
||||
selObj_face = selObj + '.f[*]'
|
||||
selObj_face = cmds.ls(selObj_face, fl=1)
|
||||
selObj_uv = cmds.polyListComponentConversion(selObj,tuv=1)
|
||||
selObj_face_hasUV = cmds.polyListComponentConversion(selObj_uv,tf=1)
|
||||
selObj_face_hasUV = cmds.ls(selObj_face_hasUV, fl=1)
|
||||
selObj_face_noUV = list(set(selObj_face).difference(set(selObj_face_hasUV)))
|
||||
if selObj_face_noUV:
|
||||
cmds.delete(selObj_face_noUV)
|
||||
return selObj
|
||||
|
||||
def splitIfOnUVBorder():
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
sel = sel[0]
|
||||
selList = om2.MGlobal.getActiveSelectionList()
|
||||
selListPath = selList.getDagPath(0)
|
||||
vertIt = om2.MItMeshVertex(selListPath)
|
||||
selMesh = om2.MFnMesh(selListPath)
|
||||
vertIdToSplit = []
|
||||
vertToSplit = []
|
||||
while not vertIt.isDone():
|
||||
uvIndices = vertIt.getUVIndices()
|
||||
uvIndices = list(set(uvIndices))
|
||||
if len(uvIndices)>=2:
|
||||
vertIdToSplit.append(vertIt.index())
|
||||
elif vertIt.onBoundary():
|
||||
vertIdToSplit.append(vertIt.index())
|
||||
vertIt.next()
|
||||
for i in range(len(vertIdToSplit)):
|
||||
vertToSplit.append(sel+'.vtx['+str(vertIdToSplit[i])+']')
|
||||
cmds.polySplitVertex(vertToSplit,cch=0)
|
||||
|
||||
def morph2UV():
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
sel = sel[0]
|
||||
selList = om2.MSelectionList()
|
||||
selList.add(sel)
|
||||
path = selList.getDagPath(0)
|
||||
myMesh = om2.MFnMesh(path)
|
||||
newPointArray = om2.MPointArray()
|
||||
space = om2.MSpace.kWorld
|
||||
myMesh_UVs = myMesh.getUVs()
|
||||
myMesh_points = myMesh.getPoints()
|
||||
# for i in range(myMesh.numVertices):
|
||||
myMesh_itVertex = om2.MItMeshVertex(path)
|
||||
points = om2.MPointArray()
|
||||
while not myMesh_itVertex.isDone():
|
||||
vertIndex = myMesh_itVertex.index()
|
||||
gotUV = myMesh_itVertex.getUV()
|
||||
point = om2.MPoint(gotUV[0],gotUV[1],0)
|
||||
points.append(point)
|
||||
myMesh_itVertex.next()
|
||||
myMesh.setPoints(points,space)
|
||||
|
||||
def runMorph2UV():
|
||||
baseObj = cmds.ls(sl=1,o=1) #1. inputmesh
|
||||
baseObjDup = cmds.duplicate() #2. duplicate
|
||||
mel.eval("FreezeTransformations")
|
||||
mel.eval("ResetTransformations")
|
||||
baseObj = baseObjDup[0]
|
||||
deleteNoUV()
|
||||
splitIfOnUVBorder()
|
||||
morph2UV()
|
||||
currentSelection = cmds.ls(sl=1)
|
||||
currentUV = cmds.polyListComponentConversion(currentSelection,tuv=1)
|
||||
cmds.polyMergeVertex(currentSelection,d=0.0001,cch=0)
|
||||
cmds.polyMergeUV(currentUV,d=0.001,cch=0) # fix split
|
||||
cmds.select(baseObj,r=1)
|
||||
if __name__ == "__main__":
|
||||
runMorph2UV()
|
@ -0,0 +1,7 @@
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
def normalFacet():
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
cmds.polyNormalPerVertex(sel,ufn=1)
|
||||
mel.eval('SetToFaceNormals;')
|
||||
mel.eval('DeleteHistory;')
|
200
Scripts/Modeling/Edit/LDMT/ldmt_instantMeshes.py
Normal file
200
Scripts/Modeling/Edit/LDMT/ldmt_instantMeshes.py
Normal file
@ -0,0 +1,200 @@
|
||||
import os
|
||||
import math
|
||||
import tempfile
|
||||
from ldmt_function.ldmt_loadUIFile import get_maya_window
|
||||
import maya.OpenMayaUI as omui
|
||||
import subprocess
|
||||
from ldmt_core import ldmt_cmds as ld
|
||||
from functools import partial
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
|
||||
from Qt.QtWidgets import *
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtCore import *
|
||||
# from Qt.QtUiTools import QUiLoader
|
||||
from Qt.QtCompat import loadUi
|
||||
import maya.cmds as cmds
|
||||
|
||||
import maya.OpenMaya as om
|
||||
import maya.api.OpenMaya as om2
|
||||
import random
|
||||
import ast
|
||||
|
||||
LDMTPATH = ld.getPath('LDMT')
|
||||
ldmt_uifile = LDMTPATH + '/ldmt_ui/ldmt_instantMeshes.ui'
|
||||
# ldmt_list_form, ldmt_list_base = load_ui_type(ldmt_uifile)
|
||||
ldmt_window_name = 'ldmt_instantMeshes'
|
||||
ldmt_button_name = 'btn_'+ldmt_window_name.split('_')[1]
|
||||
|
||||
'''
|
||||
#Functions
|
||||
'''
|
||||
|
||||
'''
|
||||
#UI
|
||||
'''
|
||||
class ldmt_cls(QDialog):
|
||||
def __init__(self, parent = get_maya_window()):
|
||||
super(ldmt_cls, self).__init__(parent)
|
||||
self.window_name = ldmt_window_name
|
||||
self.setWindowTitle(ldmt_window_name)
|
||||
self.setWindowFlags(Qt.Window)
|
||||
# self.move(QCursor.pos() + QPoint(20,20))
|
||||
self.set_ui()
|
||||
self.setupBtn()
|
||||
|
||||
self.temp_dir = os.path.join(LDMTPATH, 'temp')
|
||||
if not os.path.exists(self.temp_dir):
|
||||
os.makedirs(self.temp_dir)
|
||||
# self.installStartBar()
|
||||
|
||||
def set_ui(self):
|
||||
main_layout = QVBoxLayout(self)
|
||||
|
||||
# ui_file = QFile(ldmt_uifile)
|
||||
# ui_file.open(QFile.ReadOnly)
|
||||
self.ui = loadUi(ldmt_uifile)
|
||||
# self.ui = QUiLoader().load(ui_file)
|
||||
# ui_file.close()
|
||||
|
||||
main_layout.addWidget(self.ui)
|
||||
|
||||
def setupBtn(self):
|
||||
self.ui.btn_sendToExe.clicked.connect(self.sendToExe)
|
||||
self.ui.btn_remesh.clicked.connect(self.remesh)
|
||||
self.ui.text_targetCount.setPlainText("50%")
|
||||
self.ui.statusbar.showMessage(ld.tag())
|
||||
|
||||
def sendToExe(self):
|
||||
sel=cmds.ls(sl=1,o=1)
|
||||
if sel == []:
|
||||
InstantMeshPath = LDMTPATH + "/ldmt_exe/instantMesh.exe"
|
||||
subprocess.Popen(InstantMeshPath,False)
|
||||
else:
|
||||
self.instantMeshes_sendToExe()
|
||||
|
||||
def remesh(self):
|
||||
targetCount = self.ui.text_targetCount.toPlainText()
|
||||
try:
|
||||
if targetCount.endswith('%'):
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
sel = sel[0]
|
||||
currentFaceCount = int(cmds.polyEvaluate(sel, f=True))
|
||||
targetCount = 2*int(currentFaceCount*float(targetCount[:-1])/100)
|
||||
else:
|
||||
targetCount = int(targetCount)
|
||||
except:
|
||||
ld.msg('Please input a number or ratio!')
|
||||
return
|
||||
self.instantMeshes_remesh(targetCount)
|
||||
|
||||
def instantMeshes_sendToExe(self,face_count=None):
|
||||
inst_mesh_path = LDMTPATH + "/ldmt_exe/instantMesh.exe"
|
||||
if not os.path.exists(inst_mesh_path):
|
||||
cmds.warning('Instant Mesh path not found!')
|
||||
return
|
||||
# Get current selection
|
||||
sel_obj = cmds.ls(sl=True)
|
||||
if sel_obj:
|
||||
print('Processing Instant Mesh...')
|
||||
# Create temp file for OBJ export
|
||||
# temp = tempfile.NamedTemporaryFile(prefix='instantMesh_', suffix='.obj', delete=False)
|
||||
# temp_path = temp.name
|
||||
|
||||
temp_file = os.path.join(self.temp_dir, 'instantMesh_temp.obj')
|
||||
# Make sure OBJexport is loaded
|
||||
if not cmds.pluginInfo('objExport', q=True, loaded=True):
|
||||
cmds.loadPlugin('objExport')
|
||||
# Save the currently selected object as an OBJ
|
||||
cmds.file(temp_file, force=True, exportSelected=True, type="OBJexport")
|
||||
# run instamesh command on the OBJ
|
||||
# print(temp_path)
|
||||
print("Instant Mesh start")
|
||||
some_command = inst_mesh_path + " " + temp_file
|
||||
p = subprocess.Popen(some_command, False)
|
||||
# temp.close()
|
||||
else:
|
||||
cmds.warning('No objects selected...')
|
||||
|
||||
def instantMeshes_remesh(self,face_count=None):
|
||||
inst_mesh_path = LDMTPATH + "/ldmt_exe/instantMesh.exe"
|
||||
if not os.path.exists(inst_mesh_path):
|
||||
cmds.warning('Instant Mesh path not found!')
|
||||
return
|
||||
# Get current selection
|
||||
sel_obj = cmds.ls(sl=True)
|
||||
if sel_obj:
|
||||
print('Processing Instant Mesh...')
|
||||
# if no polycount set just double the amount of the source object
|
||||
if not face_count:
|
||||
face_count = int(cmds.polyEvaluate(sel_obj, f=True))
|
||||
face_count *= 2
|
||||
face_count /= 2
|
||||
face_count = int(face_count)
|
||||
# Create temp file for OBJ export
|
||||
# temp = tempfile.NamedTemporaryFile(prefix='instantMesh_', suffix='.obj', delete=False)
|
||||
# temp_path = temp.name
|
||||
temp_path = os.path.join(self.temp_dir, 'instantMesh_temp.obj')
|
||||
# Make sure OBJexport is loaded
|
||||
if not cmds.pluginInfo('objExport', q=True, loaded=True):
|
||||
cmds.loadPlugin('objExport')
|
||||
# Save the currently selected object as an OBJ
|
||||
cmds.file(temp_path, force=True, exportSelected=True, type="OBJexport")
|
||||
# run instamesh command on the OBJ
|
||||
print(temp_path)
|
||||
print("Instant Mesh start")
|
||||
some_command = inst_mesh_path + " " + temp_path + " -o " + temp_path + " -f " + str(face_count) + " -D" + " -b"
|
||||
p = subprocess.Popen(some_command, stdout=subprocess.PIPE, shell=True)
|
||||
p.communicate()
|
||||
p.wait()
|
||||
print("Instant Mesh end")
|
||||
print(some_command)
|
||||
# import back the temp OBJ file
|
||||
returnedNodes = cmds.file(temp_path,
|
||||
i=True,
|
||||
type="OBJ",
|
||||
rnn=True,
|
||||
ignoreVersion=True,
|
||||
options="mo=1",
|
||||
loadReferenceDepth="all")
|
||||
# delete the temp file
|
||||
# temp.close()
|
||||
# Select the imported nodes
|
||||
if returnedNodes:
|
||||
cmds.select(returnedNodes, r=True)
|
||||
print("Instant Mesh done...")
|
||||
else:
|
||||
cmds.warning('No objects selected...')
|
||||
|
||||
def installStartBar(self):
|
||||
allQWidgets = self.ui.findChildren(QWidget)
|
||||
for i in allQWidgets:
|
||||
i.installEventFilter(self)
|
||||
|
||||
def eventFilter(self, obj, event ):
|
||||
'''Connect signals on mouse over'''
|
||||
if event.type() == QEvent.Enter:
|
||||
self.oldMessage = ld.tag()
|
||||
# self.statusbar.showMessage(' '+obj.statusTip(),0)
|
||||
elif event.type() == QEvent.Leave:
|
||||
# self.statusbar.showMessage(' '+self.oldMessage, 0)
|
||||
pass
|
||||
event.accept()
|
||||
return False
|
||||
|
||||
def closeEvent(self,event):
|
||||
# ld.turnToolBtnOff(self,ldmt_button_name)
|
||||
cmds.deleteUI(ldmt_window_name)
|
||||
|
||||
def ldmt_show():
|
||||
if cmds.window(ldmt_window_name, exists=True):
|
||||
cmds.deleteUI(ldmt_window_name)
|
||||
app = QApplication.instance()
|
||||
dialog = ldmt_cls(parent=app.activeWindow())
|
||||
|
||||
dialog.show()
|
||||
app.exec_()
|
||||
|
||||
if __name__ == '__main__':
|
||||
ldmt_show()
|
190
Scripts/Modeling/Edit/LDMT/ldmt_marvelousTool.py
Normal file
190
Scripts/Modeling/Edit/LDMT/ldmt_marvelousTool.py
Normal file
@ -0,0 +1,190 @@
|
||||
import os
|
||||
import math
|
||||
from ldmt_function.ldmt_loadUIFile import get_maya_window, load_ui_file
|
||||
import maya.OpenMayaUI as omui
|
||||
from ldmt_core import ldmt_cmds as ld
|
||||
from ldmt_function import ldmt_morphToUV
|
||||
from functools import partial
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
|
||||
try:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtWidgets import *
|
||||
# from Qt.QtUiTools import *
|
||||
from Qt import __version__
|
||||
from Qt.QtCompat import wrapInstance
|
||||
except ImportError:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtUiTools import *
|
||||
from Qt import __version__
|
||||
from Qt.QtCompat import wrapInstance
|
||||
|
||||
import maya.OpenMaya as om
|
||||
import maya.api.OpenMaya as om2
|
||||
import random
|
||||
import ast
|
||||
|
||||
LDMTPATH = ld.getPath('LDMT')
|
||||
ldmt_uifile = LDMTPATH + '/ldmt_ui/ldmt_marvelousTool.ui'
|
||||
ldmt_window_name = 'ldmt_marvelousTool'
|
||||
ldmt_button_name = 'btn_'+ldmt_window_name.split('_')[1]
|
||||
|
||||
'''
|
||||
#UI
|
||||
'''
|
||||
class ldmt_cls(QDialog):
|
||||
def __init__(self, parent = get_maya_window()):
|
||||
super(ldmt_cls, self).__init__(parent)
|
||||
self.window_name = ldmt_window_name
|
||||
self.setWindowTitle(ldmt_window_name)
|
||||
self.setWindowFlags(Qt.Window)
|
||||
self.move(QCursor.pos() + QPoint(50,-200))
|
||||
# update status bar so it's not only show in help line window.
|
||||
self.set_ui()
|
||||
self.setupBtn()
|
||||
# self.statusbar.showMessage(ld.tag())
|
||||
# self.installStartBar()
|
||||
|
||||
def set_ui(self):
|
||||
main_layout = QVBoxLayout(self)
|
||||
self.ui = load_ui_file(ldmt_uifile)
|
||||
if self.ui is None:
|
||||
cmds.warning("UI file not found: {}".format(ldmt_uifile))
|
||||
return
|
||||
main_layout.addWidget(self.ui)
|
||||
|
||||
def setupBtn(self):
|
||||
self.ui.btn_flatten.clicked.connect(self.flatten)
|
||||
self.ui.btn_makePairs.clicked.connect(self.makePairs)
|
||||
self.ui.slider_blendshape.setMinimum(0)
|
||||
self.ui.slider_blendshape.setMaximum(100)
|
||||
self.ui.slider_blendshape.valueChanged.connect(self.blendshapeChange)
|
||||
# self.btn_makePairs.clicked.connect(self.makePairs)
|
||||
|
||||
def blendshapeChange(self):
|
||||
blendValue = float(self.ui.slider_blendshape.value())/100
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
for i in sel:
|
||||
selShape = cmds.listRelatives(i,s=1)
|
||||
selShape = selShape[0]
|
||||
wrapNode = cmds.listConnections(selShape,type="wrap")
|
||||
wrapNode = wrapNode[0]
|
||||
wrapNode_connections = cmds.listConnections(wrapNode)
|
||||
patternName = ''
|
||||
for j in wrapNode_connections:
|
||||
if j.endswith('_pattern'):
|
||||
patternName = j
|
||||
patternShape = cmds.listRelatives(patternName,s=1)
|
||||
patternShape = patternShape[0]
|
||||
blendshapeNode = cmds.listConnections(patternShape,type="blendShape")
|
||||
cmds.blendShape(blendshapeNode,e=1,w=(0,blendValue))
|
||||
|
||||
def flatten(self):
|
||||
from ldmt_function import ldmt_morphToGarment
|
||||
from ldmt_function import ldmt_normalFacet
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
selBB = cmds.polyEvaluate(b=1)
|
||||
garmentHeight = selBB[1][1]-selBB[1][0]
|
||||
garmentMaxX = selBB[0][1]
|
||||
patternList = []
|
||||
for i in sel:
|
||||
pattern = ldmt_morphToGarment.runMorph2UV(i)
|
||||
newName = i+'_pattern'
|
||||
patternList.append(newName)
|
||||
cmds.rename(pattern,newName)
|
||||
cmds.select(patternList)
|
||||
ldmt_normalFacet.normalFacet()
|
||||
cmds.scale(garmentHeight,garmentHeight,garmentHeight)
|
||||
cmds.move(garmentMaxX,0,0)
|
||||
cmds.group(sel,n="ldmt_marvelousTool_garments#")
|
||||
cmds.group(patternList,n="ldmt_marvelousTool_patterns#")
|
||||
|
||||
def makePairs(self):
|
||||
sel = cmds.ls(os=1)
|
||||
garments = cmds.listRelatives(sel[0]) # len(garments)
|
||||
patterns = cmds.listRelatives(sel[1]) # len(patterns)
|
||||
retopos = cmds.listRelatives(sel[2]) # len(retopos)
|
||||
retopos_BB_width = {}
|
||||
retopos_BB_length = {}
|
||||
retopos_BB_center = {}
|
||||
patterns_BB_width = {}
|
||||
patterns_BB_length = {}
|
||||
patterns_BB_center = {}
|
||||
# In case that uv doesn't exists.
|
||||
cmds.select(retopos,r=1)
|
||||
mel.eval("performPolyAutoProj 0;")
|
||||
cmds.select(sel,r=1)
|
||||
# In case wrong bb
|
||||
for i in retopos:
|
||||
cmds.polyMergeVertex(i, d=0.001)
|
||||
# Matching
|
||||
for i in retopos:
|
||||
BB = cmds.polyEvaluate(i,b=1)
|
||||
retopos_BB_width[i] = BB[0][1] - BB[0][0]
|
||||
retopos_BB_length[i] = BB[1][1] - BB[1][0]
|
||||
retopos_BB_center[i] = [(BB[0][1] + BB[0][0])/2, (BB[1][1] + BB[1][0])/2]
|
||||
for i in patterns:
|
||||
BB = cmds.polyEvaluate(i,b=1)
|
||||
patterns_BB_width[i] = BB[0][1] - BB[0][0]
|
||||
patterns_BB_length[i] = BB[1][1] - BB[1][0]
|
||||
patterns_BB_center[i] = [(BB[0][1] + BB[0][0])/2, (BB[1][1] + BB[1][0])/2]
|
||||
pair_pattern_retopo={} # len(pair_pattern_retopo)
|
||||
for i in patterns:
|
||||
for j in retopos:
|
||||
if abs(patterns_BB_width[i] - retopos_BB_width[j]) < 1 \
|
||||
and abs(patterns_BB_length[i] - retopos_BB_length[j]) < 1 \
|
||||
and abs(patterns_BB_center[i][0] - retopos_BB_center[j][0]) < 1 \
|
||||
and abs(patterns_BB_center[i][1] - retopos_BB_center[j][1]) < 1:
|
||||
pair_pattern_retopo[i] = j
|
||||
for i in pair_pattern_retopo:
|
||||
cmds.transferAttributes(i,pair_pattern_retopo[i],transferUVs=1)
|
||||
for i in pair_pattern_retopo:
|
||||
cmds.select(pair_pattern_retopo[i],i,r=1)
|
||||
cmds.CreateWrap()
|
||||
for i in pair_pattern_retopo:
|
||||
pairGarment = i[:-8]
|
||||
pattern = i
|
||||
blendObjs = [pairGarment,pattern] # 0: target 1: origin
|
||||
blendName = cmds.blendShape(blendObjs,o='world',n='clothTransfer#')
|
||||
cmds.hide(sel[1])
|
||||
cmds.displaySurface(sel[0],x=1)
|
||||
cmds.hide(sel[1])
|
||||
cmds.displaySurface(sel[0],x=1)
|
||||
layerName = cmds.createDisplayLayer( n = "garment#", e=1)
|
||||
cmds.editDisplayLayerMembers(layerName,sel[0])
|
||||
cmds.setAttr(layerName+'.displayType',2)
|
||||
|
||||
def installStartBar(self):
|
||||
allQWidgets = self.findChildren(QWidget)
|
||||
for i in allQWidgets:
|
||||
i.installEventFilter(self)
|
||||
|
||||
def eventFilter(self, obj, event ):
|
||||
'''Connect signals on mouse over'''
|
||||
if event.type() == QEvent.Enter:
|
||||
self.oldMessage = ld.tag()
|
||||
self.statusbar.showMessage(' '+obj.statusTip(),0)
|
||||
elif event.type() == QEvent.Leave:
|
||||
self.statusbar.showMessage(' '+self.oldMessage, 0)
|
||||
pass
|
||||
event.accept()
|
||||
return False
|
||||
|
||||
# def closeEvent(self,event):
|
||||
# ld.turnToolBtnOff(self,ldmt_button_name)
|
||||
# cmds.deleteUI(ldmt_window_name)
|
||||
|
||||
def ldmt_show():
|
||||
if cmds.window(ldmt_window_name, exists=True):
|
||||
cmds.deleteUI(ldmt_window_name)
|
||||
|
||||
app = QApplication.instance()
|
||||
dialog = ldmt_cls(parent=app.activeWindow())
|
||||
dialog.show()
|
||||
app.exec_()
|
||||
|
||||
if __name__ == '__main__':
|
||||
ldmt_show()
|
32
Scripts/Modeling/Edit/LDMT/ldmt_move2rdUVIn.py
Normal file
32
Scripts/Modeling/Edit/LDMT/ldmt_move2rdUVIn.py
Normal file
@ -0,0 +1,32 @@
|
||||
# About ####################
|
||||
# Auther: Liu Dian
|
||||
# Email: xgits@outlook.com
|
||||
# Website: www.xgits.com
|
||||
# Version: Pro
|
||||
# License: GPL
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
import maya.api.OpenMaya as om2
|
||||
|
||||
def LD_move2rdUVIn():
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
sel = sel[0]
|
||||
selList = om2.MSelectionList()
|
||||
selList.add(sel)
|
||||
selPath = selList.getDagPath(0)
|
||||
selMesh = om2.MFnMesh(selPath)
|
||||
|
||||
uvid_uv = [] # generate {uvid:[u,v],} from MFnMesh.getUVs()
|
||||
uvNameIn2rd = []
|
||||
uvArray = selMesh.getUVs()
|
||||
|
||||
for i in range(len(uvArray[0])):
|
||||
uvid_uv.append([uvArray[0][i],uvArray[1][i]])
|
||||
|
||||
for uvid in range(len(uvid_uv)):
|
||||
u = uvid_uv[uvid][0]
|
||||
v = uvid_uv[uvid][1]
|
||||
if u>1 and u<2 and v>0 and v<1:
|
||||
uvNameIn2rd.append(sel+'.map['+str(uvid)+']')
|
||||
cmds.polyEditUV(uvNameIn2rd,u=-1)
|
||||
|
361
Scripts/Modeling/Edit/LDMT/ldmt_moveOverlapUVOut.py
Normal file
361
Scripts/Modeling/Edit/LDMT/ldmt_moveOverlapUVOut.py
Normal file
@ -0,0 +1,361 @@
|
||||
# About ####################
|
||||
# Auther: Liu Dian
|
||||
# Email: xgits@outlook.com
|
||||
# Website: www.xgits.com
|
||||
# Version: Pro
|
||||
# License: GPL
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
import maya.api.OpenMaya as om2
|
||||
|
||||
def getUVEdgeDic(sel):
|
||||
selList = om2.MSelectionList()
|
||||
selList.add(sel)
|
||||
selPath = selList.getDagPath(0)
|
||||
selMesh = om2.MFnMesh(selPath)
|
||||
selVtxIter = om2.MItMeshVertex(selPath)
|
||||
selEdgeIter = om2.MItMeshEdge(selPath)
|
||||
selFaceIter = om2.MItMeshPolygon(selPath)
|
||||
|
||||
uvid_uv = [] # generate {uvid:[u,v],} from MFnMesh.getUVs()
|
||||
vtxid_uvid = []
|
||||
edgeid_vtxid = []
|
||||
edgeid_uvid = [] #edgeid_vtxid + vtxid_uvid
|
||||
faceid_edgeid = []
|
||||
faceid_uvid = []
|
||||
edgeid_faceid = [] #faceid_edgeid reverse
|
||||
uvedgeid_uvid = [] # get { uvedgeid: [uvid1, uvid2]} On border
|
||||
|
||||
uvid_usi = selMesh.getUvShellsIds()
|
||||
uvid_usi = uvid_usi[1]
|
||||
uvArray = selMesh.getUVs()
|
||||
for i in range(len(uvArray[0])):
|
||||
uvid_uv.append([uvArray[0][i],uvArray[1][i]])
|
||||
|
||||
while not selVtxIter.isDone(): #get {[[uvid1,uvid2],...]}
|
||||
vtxid_uvid.append(list(set(selVtxIter.getUVIndices())))
|
||||
selVtxIter.next()
|
||||
|
||||
while not selEdgeIter.isDone(): #get edge to vtx
|
||||
edgeid_vtxid.append([selEdgeIter.vertexId(0),selEdgeIter.vertexId(1)])
|
||||
edgeid_faceid.append(selEdgeIter.getConnectedFaces())
|
||||
selEdgeIter.next()
|
||||
|
||||
for edgeid in range(len(edgeid_vtxid)): # get {[[uvid1,uvid2,uvid3],...]}
|
||||
vtx0 = edgeid_vtxid[edgeid][0]
|
||||
vtx1 = edgeid_vtxid[edgeid][1]
|
||||
edgeid_uvid.append(vtxid_uvid[vtx0] + vtxid_uvid[vtx1])
|
||||
|
||||
while not selFaceIter.isDone(): # get {[[uvid1,uvid2,uvid3,uvid4], ...] }
|
||||
verts = selFaceIter.getVertices()
|
||||
faceid_edgeid.append(selFaceIter.getEdges())
|
||||
uvids=[]
|
||||
for index in range(len(verts)):
|
||||
uvids.append(selFaceIter.getUVIndex(index)) #necessary for uvedgeid
|
||||
faceid_uvid.append(uvids)
|
||||
selFaceIter.next()
|
||||
|
||||
for edgeid in range(len(edgeid_faceid)):
|
||||
faceids = edgeid_faceid[edgeid]
|
||||
edgeuvids = set(edgeid_uvid[edgeid])
|
||||
numface = len(faceids)
|
||||
if numface == 1: #OnBorder
|
||||
uvids = faceid_uvid[faceids[0]]
|
||||
uvedgeid_uvid.append(list(edgeuvids.intersection(uvids)))
|
||||
continue
|
||||
elif numface == 2:
|
||||
uvidsA = faceid_uvid[faceids[0]]
|
||||
uvidsB = faceid_uvid[faceids[1]]
|
||||
intersectUV = list(set(uvidsA).intersection(uvidsB))
|
||||
intersectUV_len = len(intersectUV)
|
||||
if intersectUV_len<2:
|
||||
if intersectUV_len == 1:
|
||||
for uv in edgeuvids:
|
||||
if uv == intersectUV[0]:
|
||||
continue
|
||||
elif uv in uvidsA or uv in uvidsB:
|
||||
uvedgeid_uvid.append([intersectUV[0],uv])
|
||||
else:
|
||||
uvedgeid_uvid.append(list(edgeuvids.intersection(uvidsA)))
|
||||
uvedgeid_uvid.append(list(edgeuvids.intersection(uvidsB)))
|
||||
else:
|
||||
print("Cleanup mesh first!!!!")
|
||||
|
||||
usi_uvid = {}
|
||||
usi_uvidOnBord = {}
|
||||
usi_uvedgeidOnBord = {}
|
||||
usi_bb = {}
|
||||
|
||||
for uvid in range(len(uvid_usi)):
|
||||
usi = uvid_usi[uvid]
|
||||
if usi in usi_uvid:
|
||||
usi_uvid[usi].append(uvid)
|
||||
else:
|
||||
usi_uvid[usi] = [uvid]
|
||||
|
||||
for uvedgeid in range(len(uvedgeid_uvid)):
|
||||
usi = uvid_usi[uvedgeid_uvid[uvedgeid][0]]
|
||||
if usi in usi_uvedgeidOnBord:
|
||||
usi_uvedgeidOnBord[usi].append(uvedgeid)
|
||||
else:
|
||||
usi_uvedgeidOnBord[usi] = [uvedgeid]
|
||||
|
||||
for usi in usi_uvedgeidOnBord:
|
||||
edgeids = usi_uvedgeidOnBord[usi]
|
||||
uvsOnBord = []
|
||||
for edgeid in edgeids:
|
||||
uvsOnBord = uvsOnBord + uvedgeid_uvid[edgeid]
|
||||
usi_uvidOnBord[usi] = list(set(uvsOnBord))
|
||||
|
||||
for usi in usi_uvidOnBord:
|
||||
umin = 1
|
||||
umax = 0
|
||||
vmin = 1
|
||||
vmax = 0
|
||||
for uvid in usi_uvidOnBord[usi]:
|
||||
u = uvid_uv[uvid][0]
|
||||
v = uvid_uv[uvid][1]
|
||||
if u < umin:
|
||||
umin = u
|
||||
if u > umax:
|
||||
umax = u
|
||||
if v < vmin:
|
||||
vmin = v
|
||||
if v > vmax:
|
||||
vmax = v
|
||||
usi_bb[usi] = [[umin,umax],[vmin,vmax]]
|
||||
|
||||
usi_bbarea = {}
|
||||
for i in range(len(usi_uvid)): #get {usi:area,} from usi_bb
|
||||
usi_bbarea[i] = abs(usi_bb[i][0][1]-usi_bb[i][0][0])*abs(usi_bb[i][1][1]-usi_bb[i][1][0])
|
||||
bbarea_usi = sorted(zip(usi_bbarea.values(), usi_bbarea.keys())) # get [(minarea, usi0),...,( maxarea, usi99)]
|
||||
bbarea_usi.reverse()
|
||||
|
||||
uvedgeid_uv = []
|
||||
for uvedgeid in range(len(uvedgeid_uvid)):
|
||||
uvidA = uvedgeid_uvid[uvedgeid][0]
|
||||
uvidB = uvedgeid_uvid[uvedgeid][1]
|
||||
uA = uvid_uv[uvidA][0]
|
||||
vA = uvid_uv[uvidA][1]
|
||||
uB = uvid_uv[uvidB][0]
|
||||
vB = uvid_uv[uvidB][1]
|
||||
if vB >= vA:
|
||||
uvedgeid_uv.append([[uA,vA],[uB,vB]])
|
||||
else:
|
||||
uvedgeid_uv.append([[uB,vB],[uA,vA]])
|
||||
|
||||
return usi_uvid, uvid_uv, uvedgeid_uvid, usi_uvidOnBord, usi_uvedgeidOnBord, usi_bb, bbarea_usi, uvedgeid_uv
|
||||
|
||||
def getFacesHaveNoUV(sel):
|
||||
selList = om2.MSelectionList()
|
||||
selList.add(sel)
|
||||
selPath = selList.getDagPath(0)
|
||||
selVtxIter= om2.MItMeshVertex(selPath)
|
||||
faceidWithNoUV = []
|
||||
faceWithNoUV = []
|
||||
while not selVtxIter.isDone():
|
||||
if selVtxIter.numUVs()==0:
|
||||
faceidWithNoUV += selVtxIter.getConnectedFaces()
|
||||
selVtxIter.next()
|
||||
faceidWithNoUV = list(set(faceidWithNoUV))
|
||||
for faceid in faceidWithNoUV:
|
||||
faceWithNoUV+=[sel+'.f['+str(faceid)+']']
|
||||
return faceWithNoUV
|
||||
|
||||
def LD_moveOverlapUVOut():
|
||||
TOLERANCE = 4
|
||||
p = 10**TOLERANCE
|
||||
selForSkip = cmds.ls(sl=1)
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
if selForSkip != sel:
|
||||
selUVidForSkip = cmds.polyListComponentConversion(selForSkip,tuv=1)
|
||||
selUVidForSkip = cmds.ls(selUVidForSkip,fl=1)
|
||||
else:
|
||||
selUVidForSkip = []
|
||||
sel = sel[0]
|
||||
faceWithNoUV = getFacesHaveNoUV(sel)
|
||||
if faceWithNoUV !=[]:
|
||||
cmds.select(faceWithNoUV,r=1)
|
||||
cmds.warning("Some Faces have no UVs!")
|
||||
return
|
||||
uvDic = getUVEdgeDic(sel) #uvDic[6]
|
||||
usi_uvid = uvDic[0]
|
||||
uvid_uv = uvDic[1]
|
||||
uvedgeid_uvid = uvDic[2]
|
||||
usi_uvidOnBord = uvDic[3]
|
||||
usi_uvedgeidOnBord = uvDic[4]
|
||||
usi_bb = uvDic[5]
|
||||
bbarea_usi = uvDic[6]
|
||||
uvedgeid_uv = uvDic[7]
|
||||
|
||||
uvNotPass = set() # len(uvNotPass) Filter out stacking uvs
|
||||
skipList = set()
|
||||
skipListTemp = set()
|
||||
intersectList = {}
|
||||
usi_uvidOnBord_final = {}
|
||||
usi_uvedgeidOnBord_final = {}
|
||||
|
||||
# prepare
|
||||
for tupleA in range(len(bbarea_usi)):
|
||||
usiA = bbarea_usi[tupleA][1]
|
||||
skipListTemp.add(usiA)
|
||||
|
||||
# fast detect
|
||||
bb_uminA = usi_bb[usiA][0][0]
|
||||
bb_umaxA = usi_bb[usiA][0][1]
|
||||
bb_vminA = usi_bb[usiA][1][0]
|
||||
bb_vmaxA = usi_bb[usiA][1][1]
|
||||
|
||||
for tupleB in range(len(bbarea_usi)):
|
||||
usiB = bbarea_usi[tupleB][1]
|
||||
|
||||
#faset detect
|
||||
bb_uminB = usi_bb[usiB][0][0]
|
||||
bb_umaxB = usi_bb[usiB][0][1]
|
||||
bb_vminB = usi_bb[usiB][1][0]
|
||||
bb_vmaxB = usi_bb[usiB][1][1]
|
||||
if bb_uminA > bb_umaxB or\
|
||||
bb_umaxA < bb_uminB or\
|
||||
bb_vminA > bb_vmaxB or\
|
||||
bb_vmaxA < bb_vminB :
|
||||
continue
|
||||
|
||||
if usiB in skipListTemp:
|
||||
continue
|
||||
if ifUVShellStack(usiA,usiB,usi_bb, p):
|
||||
skipList.add(usiB)
|
||||
skipListTemp.add(usiB)
|
||||
elif ifUVShellIntersect(usiA,usiB,usi_uvedgeidOnBord, uvedgeid_uv, usi_bb):
|
||||
skipListTemp.add(usiB)
|
||||
skipList.add(usiB)
|
||||
elif ifUVShellContain(usiA,usiB,usi_uvedgeidOnBord,usi_uvidOnBord,uvedgeid_uv,uvid_uv):
|
||||
skipList.add(usiB)
|
||||
skipListTemp.add(usiB)
|
||||
|
||||
uvidsToMove = []
|
||||
uvNamesToMove = set()
|
||||
# calculate final list
|
||||
for usi in skipList:
|
||||
uvidsToMove += usi_uvid[usi]
|
||||
|
||||
for uvid in uvidsToMove:
|
||||
uvNamesToMove.add(sel+'.map['+str(uvid)+']')
|
||||
|
||||
for index in range(len(selUVidForSkip)):
|
||||
selUVidForSkip[index] = selUVidForSkip[index].split('.')[1]
|
||||
|
||||
selToSkip = []
|
||||
for uvName in uvNamesToMove:
|
||||
uvName = uvName.split('.')[1]
|
||||
if uvName in selUVidForSkip:
|
||||
selToSkip.append(sel+'.'+uvName)
|
||||
for i in selToSkip:
|
||||
uvNamesToMove.remove(i)
|
||||
|
||||
uvNamesToMove = list(uvNamesToMove)
|
||||
cmds.polyEditUV(uvNamesToMove,u=1)
|
||||
|
||||
def ifUVShellStack(usiA, usiB, usi_bb, p):
|
||||
# fast filter
|
||||
usiA_umin = float(int(usi_bb[usiA][0][0] * p))/p
|
||||
usiB_umin = float(int(usi_bb[usiB][0][0] * p))/p
|
||||
if not usiA_umin == usiB_umin:
|
||||
return 0
|
||||
|
||||
usiA_umax = float(int(usi_bb[usiA][0][1] * p))/p
|
||||
usiA_vmin = float(int(usi_bb[usiA][1][0] * p))/p
|
||||
usiA_vmax = float(int(usi_bb[usiA][1][1] * p))/p
|
||||
usiB_umax = float(int(usi_bb[usiB][0][1] * p))/p
|
||||
usiB_vmin = float(int(usi_bb[usiB][1][0] * p))/p
|
||||
usiB_vmax = float(int(usi_bb[usiB][1][1] * p))/p
|
||||
if usiA_umax == usiB_umax and usiA_vmin == usiB_vmin and usiA_vmax == usiB_vmax:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def ifUVShellIntersect(usiA, usiB, usi_uvedgeidOnBord, uvedgeid_uv, usi_bb):
|
||||
for edgeA in usi_uvedgeidOnBord[usiA]:
|
||||
ax = uvedgeid_uv[edgeA][0][0]
|
||||
ay = uvedgeid_uv[edgeA][0][1]
|
||||
bx = uvedgeid_uv[edgeA][1][0]
|
||||
by = uvedgeid_uv[edgeA][1][1]
|
||||
|
||||
# fast filter
|
||||
abx = [ax,bx]
|
||||
aby = [ay,by]
|
||||
if bx<ax:
|
||||
abx = [bx,ax]
|
||||
if by<ay:
|
||||
aby = [by,ay]
|
||||
|
||||
# bound filter
|
||||
bb_usiB = usi_bb[usiB]
|
||||
bb_uminB = bb_usiB[0][0]
|
||||
bb_umaxB = bb_usiB[0][1]
|
||||
bb_vminB = bb_usiB[1][0]
|
||||
bb_vmaxB = bb_usiB[1][1]
|
||||
|
||||
if abx[0] > bb_umaxB or\
|
||||
abx[1] < bb_uminB or\
|
||||
aby[0] > bb_vmaxB or\
|
||||
aby[1] < bb_vminB:
|
||||
continue
|
||||
|
||||
for edgeB in usi_uvedgeidOnBord[usiB]:
|
||||
cx = uvedgeid_uv[edgeB][0][0]
|
||||
cy = uvedgeid_uv[edgeB][0][1]
|
||||
dx = uvedgeid_uv[edgeB][1][0]
|
||||
dy = uvedgeid_uv[edgeB][1][1]
|
||||
|
||||
# fast filter
|
||||
cdx = [cx,dx]
|
||||
cdy = [cy,dy]
|
||||
if dx<cx:
|
||||
cdx = [dx,cx]
|
||||
if dy<cy:
|
||||
cdy = [dy,cy]
|
||||
if abx[0] > cdx[1] or\
|
||||
abx[1] < cdx[0] or\
|
||||
aby[0] > cdy[1] or\
|
||||
aby[1] < cdy[0]:
|
||||
continue
|
||||
|
||||
x1 = bx - ax
|
||||
y1 = by - ay
|
||||
x2 = cx - ax
|
||||
y2 = cy - ay
|
||||
cross1 = x1*y2-x2*y1
|
||||
x2 = dx - ax
|
||||
y2 = dy - ay
|
||||
cross2 = x1*y2-x2*y1
|
||||
x1 = dx - cx
|
||||
y1 = dy - cy
|
||||
x2 = ax - cx
|
||||
y2 = ay - cy
|
||||
cross3 = x1*y2-x2*y1
|
||||
x2 = bx - cx
|
||||
y2 = by - cy
|
||||
cross4 = x1*y2-x2*y1
|
||||
if (cross1*cross2 <= 0 and cross3*cross4<=0):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def ifUVShellContain(usiA,usiB,usi_uvedgeidOnBord,usi_uvidOnBord,uvedgeid_uv,uvid_uv):
|
||||
uvid = usi_uvidOnBord[usiB][0]
|
||||
intersects = 0
|
||||
ray_u = uvid_uv[uvid][0]
|
||||
ray_v = uvid_uv[uvid][1]
|
||||
|
||||
for edge in usi_uvedgeidOnBord[usiA]:
|
||||
u0 = uvedgeid_uv[edge][0][0]
|
||||
v0 = uvedgeid_uv[edge][0][1]
|
||||
u1 = uvedgeid_uv[edge][1][0]
|
||||
v1 = uvedgeid_uv[edge][1][1]
|
||||
if (v1 >= ray_v and v0 < ray_v):
|
||||
if ((u0-ray_u)*(v1-ray_v)-(v0-ray_v)*(u1-ray_u)) < 0:
|
||||
intersects += 1
|
||||
if intersects%2 == 1:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
# checkUVBleed_0()
|
||||
# cProfile.run('checkUVBleed_0()')
|
11
Scripts/Modeling/Edit/LDMT/ldmt_normalFacet.py
Normal file
11
Scripts/Modeling/Edit/LDMT/ldmt_normalFacet.py
Normal file
@ -0,0 +1,11 @@
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
def normalFacet():
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
if not sel:
|
||||
cmds.warning("No selected objects")
|
||||
return
|
||||
cmds.polyNormalPerVertex(sel,ufn=1)
|
||||
mel.eval('SetToFaceNormals;')
|
||||
mel.eval('DeleteHistory;')
|
||||
|
139
Scripts/Modeling/Edit/LDMT/ldmt_quickExport.py
Normal file
139
Scripts/Modeling/Edit/LDMT/ldmt_quickExport.py
Normal file
@ -0,0 +1,139 @@
|
||||
import os
|
||||
import math
|
||||
from ldmt_function.ldmt_loadUIFile import get_maya_window, load_ui_file
|
||||
import maya.OpenMayaUI as omui
|
||||
from ldmt_core import ldmt_cmds as ld
|
||||
from functools import partial
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
from functools import partial
|
||||
|
||||
try:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtWidgets import *
|
||||
# from Qt.QtUiTools import *
|
||||
# from Qt.QtCompat import loadUi
|
||||
from Qt import __version__
|
||||
from Qt.QtCompat import wrapInstance
|
||||
except ImportError:
|
||||
from Qt.QtCore import *
|
||||
from Qt.QtGui import *
|
||||
# from Qt.QtUiTools import *
|
||||
from Qt import __version__
|
||||
from Qt.QtCompat import wrapInstance
|
||||
|
||||
import maya.OpenMaya as om
|
||||
import maya.api.OpenMaya as om2
|
||||
import random
|
||||
import ast
|
||||
|
||||
LDMTPATH = ld.getPath('LDMT')
|
||||
ldmt_uifile = LDMTPATH + '/ldmt_ui/ldmt_quickExport.ui'
|
||||
ldmt_window_name = 'ldmt_quickExport'
|
||||
ldmt_button_name = 'btn_'+ldmt_window_name.split('_')[1]
|
||||
|
||||
'''
|
||||
#UI
|
||||
'''
|
||||
class ldmt_cls(QDialog):
|
||||
def __init__(self, parent = get_maya_window()):
|
||||
super(ldmt_cls, self).__init__(parent)
|
||||
self.window_name = ldmt_window_name
|
||||
self.setWindowTitle(ldmt_window_name)
|
||||
self.setWindowFlags(Qt.Window)
|
||||
self.set_ui()
|
||||
# self.setupUi(self)
|
||||
self.move(QCursor.pos() + QPoint(20,20))
|
||||
# update status bar so it's not only show in help line window.
|
||||
self.setupBtn()
|
||||
# self.statusbar.showMessage(ld.tag())
|
||||
# self.installStartBar()
|
||||
|
||||
def set_ui(self):
|
||||
main_layout = QVBoxLayout(self)
|
||||
self.ui = load_ui_file(ldmt_uifile)
|
||||
main_layout.addWidget(self.ui)
|
||||
|
||||
def setupBtn(self):
|
||||
self.ui.btn_export.clicked.connect(self.quickExport)
|
||||
|
||||
def quickExport(self):
|
||||
currentFormat = self.ui.box_format.currentText()
|
||||
print(currentFormat)
|
||||
fullpath = cmds.file(query=1 ,location=1)
|
||||
|
||||
if fullpath == 'unknown':
|
||||
mayaPath = mel.eval('getenv MAYA_LOCATION')
|
||||
exportPath = mayaPath+'/bin/'
|
||||
else:
|
||||
filename = cmds.file(q=1,sn=1,shn=1)
|
||||
exportPath = fullpath[:-len(filename)]
|
||||
# subprocess.Popen('explorer '+ filepath +'', shell=True)
|
||||
sel = cmds.ls(sl=1,o=1)
|
||||
exportFolder = exportPath+"models/"
|
||||
if not os.path.exists(exportFolder):
|
||||
os.mkdir(exportFolder)
|
||||
exportName = exportFolder+sel[0].split('|')[-1]
|
||||
|
||||
if currentFormat == 'OBJ':
|
||||
if cmds.pluginInfo("objExport",q=1,l=1) !=1:
|
||||
cmds.loadPlugin("objExport",qt=1)
|
||||
cmds.file(exportName, force=True, options='groups=1;ptgroups=1;materials=1;smoothing=1;normals=1', type='OBJexport', pr=True, es=True)
|
||||
|
||||
elif currentFormat == 'FBX':
|
||||
if cmds.pluginInfo("fbxmaya",q=1,l=1) !=1:
|
||||
cmds.loadPlugin("fbxmaya",qt=1)
|
||||
fbxExportName = exportName+".fbx"
|
||||
mel.eval('FBXExportScaleFactor 1;')
|
||||
mel.eval('FBXExportInAscii -v 1;')
|
||||
mel.eval('FBXExportSmoothingGroups -v 1;')
|
||||
mel.eval('FBXExportSmoothMesh -v 1;')
|
||||
mel.eval('FBXExportTriangulate -v 0;')
|
||||
mel.eval('FBXExportUpAxis y;')
|
||||
mel.eval('FBXExport -f "'+ fbxExportName +'" -s;')
|
||||
|
||||
elif currentFormat == 'UE4':
|
||||
if cmds.pluginInfo("fbxmaya",q=1,l=1) !=1:
|
||||
cmds.loadPlugin("fbxmaya",qt=1)
|
||||
fbxExportName = exportName+".fbx"
|
||||
mel.eval('FBXExportScaleFactor 1;')
|
||||
mel.eval('FBXExportInAscii -v 1;')
|
||||
mel.eval('FBXExportSmoothingGroups -v 1;')
|
||||
mel.eval('FBXExportSmoothMesh -v 1;')
|
||||
mel.eval('FBXExportTriangulate -v 1;')
|
||||
mel.eval('FBXExportUpAxis y;')
|
||||
mel.eval('FBXExport -f "'+ fbxExportName +'" -s;')
|
||||
mel.eval('system("load '+ exportFolder +'");')
|
||||
|
||||
def installStartBar(self):
|
||||
allQWidgets = self.findChildren(QWidget)
|
||||
for i in allQWidgets:
|
||||
i.installEventFilter(self)
|
||||
|
||||
def eventFilter(self, obj, event ):
|
||||
'''Connect signals on mouse over'''
|
||||
if event.type() == QEvent.Enter:
|
||||
self.oldMessage = ld.tag()
|
||||
self.statusbar.showMessage(' '+obj.statusTip(),0)
|
||||
elif event.type() == QEvent.Leave:
|
||||
self.statusbar.showMessage(' '+self.oldMessage, 0)
|
||||
pass
|
||||
event.accept()
|
||||
return False
|
||||
|
||||
# def closeEvent(self,event):
|
||||
# ld.turnToolBtnOff(self,ldmt_button_name)
|
||||
# cmds.deleteUI(ldmt_window_name)
|
||||
|
||||
def ldmt_show():
|
||||
if cmds.window(ldmt_window_name, exists=True):
|
||||
cmds.deleteUI(ldmt_window_name)
|
||||
|
||||
app = QApplication.instance()
|
||||
dialog = ldmt_cls(parent=app.activeWindow())
|
||||
dialog.show()
|
||||
app.exec_()
|
||||
|
||||
if __name__ == '__main__':
|
||||
ldmt_show()
|
288
Scripts/Modeling/Edit/LDMT/ldmt_ui/ldmt_checkUVBleed.ui
Normal file
288
Scripts/Modeling/Edit/LDMT/ldmt_ui/ldmt_checkUVBleed.ui
Normal file
@ -0,0 +1,288 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ldmt_checkUVBleed</class>
|
||||
<widget class="QMainWindow" name="ldmt_checkUVBleed">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>200</width>
|
||||
<height>120</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>120</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>120</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Check UV Bleed</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QMainWindow{
|
||||
background-color: rgb(68,68,68);
|
||||
}
|
||||
QWidget#centralwidget{
|
||||
background-color: rgb(68,68,68);
|
||||
}
|
||||
QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
|
||||
QRadioButton{
|
||||
color:rgb(175,175,175);
|
||||
}
|
||||
QCheckBox{
|
||||
color:rgb(175,175,175);
|
||||
}
|
||||
|
||||
QStatusBar QLabel {
|
||||
border: 3px solid white;
|
||||
}
|
||||
|
||||
QStatusBar {
|
||||
color: rgb(175,175,175);
|
||||
}
|
||||
|
||||
QStatusBar::item {
|
||||
border: 1px solid red;
|
||||
border-radius: 3px;
|
||||
}</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="statusTip">
|
||||
<string>Input group count.</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color:rgb(200,200,200);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Shell Bleed ( pixel )</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="text_shellBleed">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Set shell to shell min distance.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-radius: 4px;
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: rgb(30,30,30, 215);
|
||||
color:rgb(175,175,175);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>32</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="btn_check">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Check if uv bleed is too short.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Check</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="statusTip">
|
||||
<string>Input group count.</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color:rgb(200,200,200);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Border Bleed ( pixel )</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="text_borderBleed">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Set shell to border min distance.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-radius: 4px;
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: rgb(30,30,30, 215);
|
||||
color:rgb(175,175,175);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>16</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="statusTip">
|
||||
<string>Input group count.</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color:rgb(200,200,200);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Texture Size</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="box_textureSize">
|
||||
<property name="statusTip">
|
||||
<string>Choose texture size.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>4096</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2048</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1024</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>512</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar">
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
212
Scripts/Modeling/Edit/LDMT/ldmt_ui/ldmt_cleanMesh.ui
Normal file
212
Scripts/Modeling/Edit/LDMT/ldmt_ui/ldmt_cleanMesh.ui
Normal file
@ -0,0 +1,212 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ldmt_cleanMesh</class>
|
||||
<widget class="QMainWindow" name="ldmt_cleanMesh">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>180</width>
|
||||
<height>90</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>180</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>180</width>
|
||||
<height>120</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Clean Mesh</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QMainWindow{
|
||||
background-color: rgb(68,68,68);
|
||||
}
|
||||
QWidget#centralwidget{
|
||||
background-color: rgb(68,68,68);
|
||||
}
|
||||
QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
|
||||
QRadioButton{
|
||||
color:rgb(175,175,175);
|
||||
}
|
||||
QCheckBox{
|
||||
color:rgb(175,175,175);
|
||||
}
|
||||
|
||||
QStatusBar QLabel {
|
||||
border: 3px solid white;
|
||||
}
|
||||
|
||||
QStatusBar {
|
||||
color: rgb(175,175,175);
|
||||
}
|
||||
|
||||
QStatusBar::item {
|
||||
border: 1px solid red;
|
||||
border-radius: 3px;
|
||||
}</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>180</width>
|
||||
<height>70</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>180</width>
|
||||
<height>70</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="btn_cleanup">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Cleanup n edge or sharing edges.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cleanup Matching Polygons</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="btn_select">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Select n edge or sharing edges.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Matching Polygons</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar">
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
480
Scripts/Modeling/Edit/LDMT/ldmt_ui/ldmt_clothTransfer.ui
Normal file
480
Scripts/Modeling/Edit/LDMT/ldmt_ui/ldmt_clothTransfer.ui
Normal file
@ -0,0 +1,480 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ldmt_clothTransfer</class>
|
||||
<widget class="QMainWindow" name="ldmt_clothTransfer">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>200</width>
|
||||
<height>130</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>130</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Cloth Transfer Tool</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QMainWindow{
|
||||
background-color: rgb(68,68,68);
|
||||
}
|
||||
QWidget#centralwidget{
|
||||
background-color: rgb(68,68,68);
|
||||
}
|
||||
QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
|
||||
QRadioButton{
|
||||
color:rgb(175,175,175);
|
||||
}
|
||||
QCheckBox{
|
||||
color:rgb(175,175,175);
|
||||
}
|
||||
|
||||
QStatusBar QLabel {
|
||||
border: 3px solid white;
|
||||
}
|
||||
|
||||
QStatusBar {
|
||||
color: rgb(175,175,175);
|
||||
}
|
||||
|
||||
QStatusBar::item {
|
||||
border: 1px solid red;
|
||||
border-radius: 3px;
|
||||
}</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="btn_setCloth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Set cloth you want to transfer.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Cloth</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="btn_setOrigin">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Set origin body.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Origin</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QPushButton" name="btn_setTarget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Set target body.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set Target</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="btn_selectTarget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Click to select the faces you set as target.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: rgb(30, 30, 30, 215);
|
||||
color:rgb(175,175,175);}
|
||||
|
||||
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: rgb(75,75,75, 215);
|
||||
color:rgb(175,175,175);}
|
||||
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: rgb(100,100,100, 215);
|
||||
color:rgb(175,175,175);}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="btn_selectOrigin">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Click to select the verts you set as target.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: rgb(30, 30, 30, 215);
|
||||
color:rgb(175,175,175);}
|
||||
|
||||
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: rgb(75,75,75, 215);
|
||||
color:rgb(175,175,175);}
|
||||
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: rgb(100,100,100, 215);
|
||||
color:rgb(175,175,175);}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="btn_selectCloth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Click to select the meshes you set as base mesh.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: rgb(30, 30, 30, 215);
|
||||
color:rgb(175,175,175);}
|
||||
|
||||
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: rgb(75,75,75, 215);
|
||||
color:rgb(175,175,175);}
|
||||
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: rgb(100,100,100, 215);
|
||||
color:rgb(175,175,175);}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="btn_transfer">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Click to run the trasferring process.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">*.QPushButton{
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(135, 135, 135, 225), stop:1 rgba(185,185, 185, 195));
|
||||
border:1px solid rgb(30,30,30);
|
||||
color: rgb( 25,25,25 );
|
||||
}
|
||||
*.QPushButton:hover{
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(155, 155, 155, 225), stop:1 rgba(205,205, 205, 195));
|
||||
border:1px solid rgb(30,30,30);
|
||||
color: rgb( 25,25,25 );
|
||||
text-decoration: underline!important;
|
||||
}
|
||||
*.QPushButton:pressed{
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(175, 175, 175, 195), stop:1 rgba(115,115, 115, 225));
|
||||
border:1px solid rgb(30,30,30);
|
||||
color: rgb( 25,25,25 );
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Transfer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar">
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
259
Scripts/Modeling/Edit/LDMT/ldmt_ui/ldmt_instantMeshes.ui
Normal file
259
Scripts/Modeling/Edit/LDMT/ldmt_ui/ldmt_instantMeshes.ui
Normal file
@ -0,0 +1,259 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ldmt_instantMeshes</class>
|
||||
<widget class="QMainWindow" name="ldmt_instantMeshes">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>240</width>
|
||||
<height>80</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>240</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>240</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Instant Meshes Tool</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QMainWindow{
|
||||
background-color: rgb(68,68,68);
|
||||
}
|
||||
QWidget#centralwidget{
|
||||
background-color: rgb(68,68,68);
|
||||
}
|
||||
QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
|
||||
QRadioButton{
|
||||
color:rgb(175,175,175);
|
||||
}
|
||||
QCheckBox{
|
||||
color:rgb(175,175,175);
|
||||
}
|
||||
|
||||
QStatusBar QLabel {
|
||||
border: 3px solid white;
|
||||
}
|
||||
|
||||
QStatusBar {
|
||||
color: rgb(175,175,175);
|
||||
}
|
||||
|
||||
QStatusBar::item {
|
||||
border: 1px solid red;
|
||||
border-radius: 3px;
|
||||
}</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>240</width>
|
||||
<height>60</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>240</width>
|
||||
<height>60</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="btn_remesh">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Remesh selection right on sight.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remesh</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="btn_sendToExe">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>90</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Send selection to InstantMeshes.exe</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Send To InstantMeshes.exe</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="statusTip">
|
||||
<string>Input a count like 5000, or target ratio 50%.</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color:rgb(200,200,200);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Target Triangle Count or %</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPlainTextEdit" name="text_targetCount">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">border-radius: 4px;
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: rgb(30,30,30, 215);
|
||||
color:rgb(175,175,175);</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar">
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
245
Scripts/Modeling/Edit/LDMT/ldmt_ui/ldmt_marvelousTool.ui
Normal file
245
Scripts/Modeling/Edit/LDMT/ldmt_ui/ldmt_marvelousTool.ui
Normal file
@ -0,0 +1,245 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ldmt_marvelousTool</class>
|
||||
<widget class="QMainWindow" name="ldmt_marvelousTool">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>300</width>
|
||||
<height>285</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>285</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>285</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Marvelous Tool</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QMainWindow{
|
||||
background-color: rgb(68,68,68);
|
||||
}
|
||||
QWidget#centralwidget{
|
||||
background-color: rgb(68,68,68);
|
||||
}
|
||||
QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
|
||||
QRadioButton{
|
||||
color:rgb(175,175,175);
|
||||
}
|
||||
QCheckBox{
|
||||
color:rgb(175,175,175);
|
||||
}
|
||||
|
||||
QStatusBar QLabel {
|
||||
border: 3px solid white;
|
||||
}
|
||||
|
||||
QStatusBar {
|
||||
color: rgb(175,175,175);
|
||||
}
|
||||
|
||||
QStatusBar::item {
|
||||
border: 1px solid red;
|
||||
border-radius: 3px;
|
||||
}</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>265</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>265</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="btn_flatten">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Select all unweld garments first.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Flatten Garment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="4">
|
||||
<widget class="QSlider" name="slider_blendshape">
|
||||
<property name="statusTip">
|
||||
<string>Change blendshape value.</string>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2" colspan="2">
|
||||
<widget class="QPushButton" name="btn_makePairs">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Select all groups of garment, pattern and retopo first. </string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Make Pairs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="4">
|
||||
<widget class="QTextBrowser" name="textBrowser">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color:rgb(40,40,40);
|
||||
color:rgb(200,200,200);
|
||||
border-radius:5px;
|
||||
padding:5px;</string>
|
||||
</property>
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">1. Select <span style=" color:#43ffa3;">Unweld Garments</span> in viewport.</p>
|
||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2. Click <span style=" color:#d49768;">Flatten Garment</span>, you'll get two groups, <span style=" color:#43ffa3;">Garment Group</span> and <span style=" color:#43ffa3;">Pattern Group</span>.</p>
|
||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">3. Import <span style=" color:#43ffa3;">Retopoed Patterns</span> from Zbrush.</p>
|
||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4. Make a <span style=" color:#43ffa3;">Group</span> of Retopoed Patterns.</p>
|
||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">5. In outliner, select all <span style=" color:#43ffa3;">Garment Group</span>, <span style=" color:#43ffa3;">Pattern Group</span> and <span style=" color:#43ffa3;">Retopoed Group </span>in order.</p>
|
||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">6. Click <span style=" color:#d49768;">Make Pairs</span>.</p></body></html></string>
|
||||
</property>
|
||||
<property name="overwriteMode">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar">
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
182
Scripts/Modeling/Edit/LDMT/ldmt_ui/ldmt_quickExport.ui
Normal file
182
Scripts/Modeling/Edit/LDMT/ldmt_ui/ldmt_quickExport.ui
Normal file
@ -0,0 +1,182 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ldmt_quickExport</class>
|
||||
<widget class="QMainWindow" name="ldmt_quickExport">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>150</width>
|
||||
<height>50</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>50</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>70</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Quick Export</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QMainWindow{
|
||||
background-color: rgb(68,68,68);
|
||||
}
|
||||
QWidget#centralwidget{
|
||||
background-color: rgb(68,68,68);
|
||||
}
|
||||
QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
|
||||
QRadioButton{
|
||||
color:rgb(175,175,175);
|
||||
}
|
||||
QCheckBox{
|
||||
color:rgb(175,175,175);
|
||||
}
|
||||
|
||||
QStatusBar QLabel {
|
||||
border: 3px solid white;
|
||||
}
|
||||
|
||||
QStatusBar {
|
||||
color: rgb(175,175,175);
|
||||
}
|
||||
|
||||
QStatusBar::item {
|
||||
border: 1px solid red;
|
||||
border-radius: 3px;
|
||||
}</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="box_format">
|
||||
<property name="statusTip">
|
||||
<string>Export format.</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>OBJ</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>FBX</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>UE4</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="btn_export">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Segoe UI</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>PointingHandCursor</cursorShape>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Export using format.</string>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QPushButton{
|
||||
border:1px solid rgb(30,30,30);
|
||||
border-radius:4px;
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(235, 158, 108, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:hover{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(189, 118, 57, 225), stop:1 rgba(255, 178, 128, 195));
|
||||
color:rgb(25,25,25);}
|
||||
QPushButton:pressed{
|
||||
border:1px solid rgb(30,30,30);
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(235, 158, 108, 195), stop:1 rgba( 189, 118, 57, 225));
|
||||
color:rgb(25,25,25);}
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Export</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar">
|
||||
<property name="statusTip">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
440
Scripts/Modeling/Edit/LDMT/patternRename.mel
Normal file
440
Scripts/Modeling/Edit/LDMT/patternRename.mel
Normal file
@ -0,0 +1,440 @@
|
||||
// Copyright (C) 1997-2014 Autodesk, Inc., and/or its licensors.
|
||||
// All rights reserved.
|
||||
//
|
||||
// The coded instructions, statements, computer programs, and/or related
|
||||
// material (collectively the "Data") in these files contain unpublished
|
||||
// information proprietary to Autodesk, Inc. ("Autodesk") and/or its licensors,
|
||||
// which is protected by U.S. and Canadian federal copyright law and by
|
||||
// international treaties.
|
||||
//
|
||||
// The Data is provided for use exclusively by You. You have the right to use,
|
||||
// modify, and incorporate this Data into other products for purposes authorized
|
||||
// by the Autodesk software license agreement, without fee.
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. AUTODESK
|
||||
// DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTIES
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF NON-INFRINGEMENT,
|
||||
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR ARISING FROM A COURSE
|
||||
// OF DEALING, USAGE, OR TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS
|
||||
// LICENSORS BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL,
|
||||
// DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK AND/OR ITS
|
||||
// LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY OR PROBABILITY OF SUCH DAMAGES.
|
||||
|
||||
//
|
||||
//
|
||||
// Bonus Tools Pattern Rename V1.02
|
||||
// 27.1.2011
|
||||
// (c) Autodesk 2011
|
||||
//
|
||||
// uses a list of patterns to remove or replace in object names
|
||||
//
|
||||
|
||||
proc string[] standardWindow( string $windowName, string $title, string $buttons[])
|
||||
{
|
||||
// this proc creates a standard window with a columnLayout and some button below
|
||||
// if $windowName is empty, a new window will be created (otherwise the existing window is shown
|
||||
//
|
||||
// it returns an array with:
|
||||
// - the UI name of the window
|
||||
// - the UI name of the columnLayout
|
||||
// - the names of the buttons
|
||||
//
|
||||
// The window is NOT shown, so that the contents can be added before the window appears
|
||||
global string $PRlistResultsUI;
|
||||
|
||||
if (!size($buttons)) error "The Window should have at least one Button";
|
||||
|
||||
string $result[];
|
||||
|
||||
if (!size($windowName)) $windowName = `window -w 406 -h 655 -title $title`;
|
||||
else if (`window -exists $windowName`) {
|
||||
showWindow $windowName;
|
||||
return { $windowName } ;
|
||||
} else window -w 406 -h 655 -title $title $windowName;
|
||||
|
||||
$result[0] = $windowName;
|
||||
|
||||
$form = `formLayout -nd 100`;
|
||||
|
||||
$tab = `tabLayout -tv 0 -scr 0 -cr 1`; // fuer ein saubers resize der children muss -scr auf 0 stehen !!
|
||||
|
||||
$form2 = `formLayout -nd 100`;
|
||||
|
||||
$result[1] = `columnLayout -adj true`;
|
||||
|
||||
setParent $form2;
|
||||
|
||||
$t = `text -label "Resulting Names"`;
|
||||
$PRlistResultsUI = `textScrollList`;
|
||||
|
||||
formLayout -edit
|
||||
-attachForm $result[1] "top" 0 // the columnLayout
|
||||
-attachForm $result[1] "left" 0
|
||||
-attachForm $result[1] "right" 0
|
||||
-attachNone $result[1] "bottom"
|
||||
|
||||
-attachControl $t "top" 0 $result[1] // the text above the results list
|
||||
-attachForm $t "left" 5
|
||||
-attachForm $t "right" 5
|
||||
-attachNone $t "bottom"
|
||||
|
||||
-attachControl $PRlistResultsUI "top" 0 $t // the results list
|
||||
-attachForm $PRlistResultsUI "left" 0
|
||||
-attachForm $PRlistResultsUI "right" 0
|
||||
-attachForm $PRlistResultsUI "bottom" 0
|
||||
$form2;
|
||||
|
||||
setParent $form;
|
||||
|
||||
$sep = `separator -h 10`;
|
||||
|
||||
for ( $b in $buttons ) $result[size($result)] = `button -label $b`;
|
||||
|
||||
formLayout -edit
|
||||
-attachForm $tab "top" 10 // the tabLayout
|
||||
-attachForm $tab "left" 5
|
||||
-attachForm $tab "right" 5
|
||||
-attachControl $tab "bottom" 5 $sep
|
||||
|
||||
-attachNone $sep "top" // the separator
|
||||
-attachForm $sep "left" 5
|
||||
-attachForm $sep "right" 5
|
||||
-attachControl $sep "bottom" 5 $result[2]
|
||||
$form;
|
||||
|
||||
int $last = size($result) - 1;
|
||||
|
||||
// attach the first button at left and bottom - and the last at right and bottom
|
||||
// if its only one button, then its completely attached
|
||||
formLayout -edit
|
||||
-attachNone $result[2] "top"
|
||||
-attachForm $result[2] "left" 5
|
||||
-attachForm $result[2] "bottom" 5
|
||||
|
||||
-attachNone $result[$last] "top"
|
||||
-attachForm $result[$last] "right" 5
|
||||
-attachForm $result[$last] "bottom" 5
|
||||
$form;
|
||||
|
||||
int $gapStep = 100 / size($buttons);
|
||||
for ( $i=3 ; $i<size($result) ; $i++ ) { // attach all the gaps between the buttons
|
||||
formLayout -edit
|
||||
|
||||
-attachPosition $result[$i-1] "right" 2 ($gapStep * ($i-2))
|
||||
|
||||
-attachPosition $result[$i] "left" 2 ($gapStep * ($i-2))
|
||||
-attachForm $result[$i] "bottom" 5
|
||||
$form;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
global string $PRobjects[];
|
||||
global string $PRsearchUI; // UI name of the input field
|
||||
global string $PRsearch[]; // list of strings to search
|
||||
global string $PRreplaceUI; // UI name of the input field
|
||||
global string $PRreplace[]; // list of strings to replace
|
||||
global string $PRlistSubsUI;
|
||||
global string $PRlistResultsUI;
|
||||
global string $PRmaxIterUI;
|
||||
global string $PRprefixUI;
|
||||
|
||||
global proc PRsaveToShelf()
|
||||
// saves the current rename to shelf
|
||||
// that shelf button will rename the current selection
|
||||
{
|
||||
global string $PRsearch[]; // list of strings to search
|
||||
global string $PRreplace[]; // list of strings to replace
|
||||
global string $PRmaxIterUI;
|
||||
global string $PRprefixUI;
|
||||
|
||||
string $text;
|
||||
string $iconText;
|
||||
string $result = `promptDialog
|
||||
-title "Rename Object"
|
||||
-message "Please enter a short help text for the Shelf Button: \n(the first four letters are the icon label)"
|
||||
-button "OK" -button "Cancel"
|
||||
-defaultButton "OK" -cancelButton "Cancel"
|
||||
-dismissString "Cancel"`;
|
||||
|
||||
if ($result == "OK") {
|
||||
$text = `promptDialog -query -text`;
|
||||
if (size($text)>3) $iconText = substring( $text, 1, 4);
|
||||
else $iconText = $text;
|
||||
if ($iconText=="") $iconText = "PatR";
|
||||
} else return; // User hit Cancel
|
||||
|
||||
int $maxIter = `intFieldGrp -q -v1 $PRmaxIterUI`;
|
||||
string $prefix = `textFieldGrp -q -text $PRprefixUI`;
|
||||
|
||||
string $shelfScript = "// Pattern Rename 1.02 (c) Autodesk 2011 - Roland Reyer\n// " + encodeString($text) + "\n\n";
|
||||
$shelfScript += "source patternRename.mel;\n";
|
||||
$shelfScript += "{\nstring $prefix = \"" + $prefix + "\";\n";
|
||||
$shelfScript += "int $maxIter = " + $maxIter + ";\n";
|
||||
|
||||
$shelfScript += "string $search[] = {";
|
||||
for ( $i=0 ; $i<size($PRsearch) ; $i++ ) $shelfScript += " \"" + encodeString( $PRsearch[$i]) + "\"" + ($i<size($PRsearch)-1 ? "," : " };\n");
|
||||
$shelfScript += "string $replace[] = {";
|
||||
for ( $i=0 ; $i<size($PRsearch) ; $i++ ) $shelfScript += " \"" + encodeString( $PRreplace[$i]) + "\"" + ($i<size($PRsearch)-1 ? "," : " };\n");
|
||||
|
||||
$shelfScript += "string $objects[];\n";
|
||||
$shelfScript += "string $namespaces[];\n";
|
||||
$shelfScript += "patternRenameLoadSelected( $objects, $namespaces);\n";
|
||||
$shelfScript += "string $newName[] = $objects;\n";
|
||||
$shelfScript += "$newName = doPatternRename( $newName, $search, $replace, $prefix, $maxIter);\n";
|
||||
$shelfScript += "for ( $i=0 ; $i<size($objects) ; $i++ ) {\n";
|
||||
$shelfScript += "\tcatch( \`rename ($namespaces[$i] + \":\" + $objects[$i]) ($namespaces[$i] + \":\" + $newName[$i])\`);\n";
|
||||
$shelfScript += "}\n}\n";
|
||||
|
||||
scriptToShelf ( $iconText, $shelfScript, true);
|
||||
// print("-----------------------------------\n");
|
||||
// print $shelfScript;
|
||||
// print("-----------------------------------\n");
|
||||
}
|
||||
|
||||
global proc int PRisValidObjectName( string $name)
|
||||
{
|
||||
// bug fix / the function isValidObjectName (match) has a bug
|
||||
if ( !size(match( "^[a-zA-Z]", $name)) || size(match( "([^a-zA-Z0-9_])", $name)) || size( match( " ", $name))) return 0; // special character or spaces or number at beginning found
|
||||
else return 1;
|
||||
}
|
||||
|
||||
global proc string[] doPatternRename( string $obj[], string $search[], string $replace[], string $prefix, int $maxIter)
|
||||
{
|
||||
int $warn = 0;
|
||||
|
||||
for ( $i=0 ; $i<size( $obj) ; $i++ ) {
|
||||
for ( $j=0 ; $j<size($search) ; $j++ ) {
|
||||
int $before = -1;
|
||||
int $iter = 0;
|
||||
do {
|
||||
$before = size($obj[$i]);
|
||||
$obj[$i] = substitute( $search[$j], $obj[$i], $replace[$j]);
|
||||
$iter++;
|
||||
} while ($before != size($obj[$i]) && $iter<$maxIter);
|
||||
}
|
||||
$obj[$i] = $prefix + $obj[$i];
|
||||
if (!PRisValidObjectName( $obj[$i])) $warn = 1;
|
||||
}
|
||||
if ($warn) warning "At least one name in the list is not valid!";
|
||||
return $obj;
|
||||
}
|
||||
|
||||
global proc patternRename()
|
||||
{
|
||||
global string $PRobjects[];
|
||||
global string $PRmaxIterUI;
|
||||
global string $PRprefixUI;
|
||||
global string $PRsearchUI; // UI name of the input field
|
||||
global string $PRsearch[]; // list of strings to search
|
||||
global string $PRreplaceUI; // UI name of the input field
|
||||
global string $PRreplace[]; // list of strings to replace
|
||||
global string $PRlistSubsUI;
|
||||
global string $PRlistResultsUI;
|
||||
|
||||
string $uiNames[] = standardWindow( "patternRenameWin", "Pattern Rename", { "Rename", "Reload", "Refresh"
|
||||
, "Shelf Button"
|
||||
, "Close"});
|
||||
int $closeIndex = size($uiNames);
|
||||
setParent $uiNames[1];
|
||||
$PRmaxIterUI = `intFieldGrp -label "Max Iterations" -v1 20 -cc "patternRenameUpdate()"`;
|
||||
$PRprefixUI = `textFieldGrp -cc "patternRenameUpdate()" -label "Prefix" -text ""`;
|
||||
separator -style "none" -h 10;
|
||||
|
||||
$PRsearchUI = `textFieldGrp -cc "patternRenameUpdate()" -label "Search" -text ""`;
|
||||
$PRreplaceUI = `textFieldGrp -cc "patternRenameUpdate()" -label "Replace" -text ""`;
|
||||
separator -style "none" -h 10;
|
||||
|
||||
// $form = `formLayout -adj true`;
|
||||
button -label "Add" -c "patternRenameAdd()";
|
||||
text -label "Search and Replace Strings";
|
||||
|
||||
$PRlistSubsUI = `textScrollList -allowMultiSelection 1`;
|
||||
textScrollList -e -sc ("{int $i[0] = `textScrollList -q -selectIndexedItem $PRlistSubsUI`; textFieldGrp -e -text$PRsearch[$i[0]-1] $PRsearchUI; textFieldGrp -e -text $PRreplace[$i[0]-1] $PRreplaceUI ;patternRenameUpdate();}") $PRlistSubsUI;
|
||||
button -label "Remove" -c "patternRenameRemove()";
|
||||
separator -style "none" -h 10;
|
||||
// text -label "Resulting Names";
|
||||
// $PRlistResultsUI = `textScrollList`;
|
||||
|
||||
button -e -c ("patternRenameGo()") $uiNames[2]; // RENAME Button
|
||||
button -e -c ("patternRenameReload()") $uiNames[3]; // RELOAD Button
|
||||
button -e -c ("patternRenameReload();PRredrawSearchReplaceList(0);") $uiNames[4]; // REFRESH Button
|
||||
button -e -c ("PRsaveToShelf();") $uiNames[5]; // SHELF BUTTON
|
||||
//button -e -c ("deleteUI " + $uiNames[0]) $uiNames[$closeIndex]; // CLOSE Button
|
||||
patternRenameReload();
|
||||
PRredrawSearchReplaceList(0);
|
||||
showWindow $uiNames[0];
|
||||
}
|
||||
|
||||
global proc PRredrawSearchReplaceList( int $select)
|
||||
{
|
||||
global string $PRobjects[];
|
||||
global string $PRmaxIterUI;
|
||||
global string $PRsearchUI; // UI name of the input field
|
||||
global string $PRsearch[]; // list of strings to search
|
||||
global string $PRreplaceUI; // UI name of the input field
|
||||
global string $PRreplace[]; // list of strings to replace
|
||||
global string $PRlistSubsUI;
|
||||
global string $PRlistResultsUI;
|
||||
|
||||
textScrollList -e -ra $PRlistSubsUI;
|
||||
for ( $i=0 ; $i<size($PRsearch) ; $i++ ) {
|
||||
if (size($PRreplace[$i])) textScrollList -e -a ($PRsearch[$i] + " ----> " + $PRreplace[$i]) $PRlistSubsUI;
|
||||
else textScrollList -e -a ($PRsearch[$i]) $PRlistSubsUI;
|
||||
}
|
||||
int $totalItems = `textScrollList -q -numberOfItems $PRlistSubsUI`;
|
||||
if ($totalItems) textScrollList -e -selectIndexedItem (min($totalItems, ($select+1))) $PRlistSubsUI;
|
||||
}
|
||||
|
||||
|
||||
|
||||
global proc patternRenameUpdate()
|
||||
{
|
||||
global string $PRobjects[];
|
||||
global string $PRsearchUI; // UI name of the input field
|
||||
global string $PRsearch[]; // list of strings to search
|
||||
global string $PRreplaceUI; // UI name of the input field
|
||||
global string $PRreplace[]; // list of strings to replace
|
||||
global string $PRlistResultsUI;
|
||||
|
||||
global string $PRmaxIterUI;
|
||||
global string $PRprefixUI;
|
||||
|
||||
int $maxIter = `intFieldGrp -q -v1 $PRmaxIterUI`;
|
||||
string $prefix = `textFieldGrp -q -text $PRprefixUI`;
|
||||
$obj = $PRobjects;
|
||||
string $newSearch = `textFieldGrp -q -text $PRsearchUI`;
|
||||
string $newReplace = `textFieldGrp -q -text $PRreplaceUI`;
|
||||
|
||||
string $orgSearch[] = $PRsearch;
|
||||
string $orgReplace[] = $PRreplace;
|
||||
|
||||
if ($newReplace=="" || isValidString( $newReplace, "([a-zA-Z0-9_])*")) { // no spaces allowed
|
||||
if ($newSearch != "") {
|
||||
for ( $i=0 ; $i<size($PRsearch) && $newSearch!=$PRsearch[$i] ; $i++ ) ;
|
||||
|
||||
$PRsearch[$i] = $newSearch;
|
||||
$PRreplace[$i] = $newReplace;
|
||||
}
|
||||
} else warning "No spaces or special characters in replace string allowed - input ignored";
|
||||
|
||||
textScrollList -e -ra $PRlistResultsUI;
|
||||
|
||||
if (size($obj) && size($PRsearch)) $obj = doPatternRename( $obj, $PRsearch, $PRreplace, $prefix, $maxIter);
|
||||
|
||||
for ( $o in $obj ) textScrollList -e -a $o $PRlistResultsUI;
|
||||
|
||||
$PRsearch = $orgSearch;
|
||||
$PRreplace = $orgReplace;
|
||||
|
||||
}
|
||||
|
||||
global proc patternRenameRemove()
|
||||
{
|
||||
global string $PRobjects[];
|
||||
global string $PRsearchUI; // UI name of the input field
|
||||
global string $PRsearch[]; // list of strings to search
|
||||
global string $PRreplaceUI; // UI name of the input field
|
||||
global string $PRreplace[]; // list of strings to replace
|
||||
global string $PRlistSubsUI;
|
||||
global string $PRlistResultsUI;
|
||||
|
||||
int $sel[] = `textScrollList -q -selectIndexedItem $PRlistSubsUI`;
|
||||
for ( $i=size($sel)-1 ; $i>-1 ; $i-- ) {
|
||||
textScrollList -e -removeIndexedItem $sel[$i] $PRlistSubsUI;
|
||||
stringArrayRemoveAtIndex( $sel[$i]-1, $PRsearch);
|
||||
stringArrayRemoveAtIndex( $sel[$i]-1, $PRreplace);
|
||||
}
|
||||
|
||||
textFieldGrp -e -text "" $PRsearchUI;
|
||||
textFieldGrp -e -text "" $PRreplaceUI;
|
||||
patternRenameUpdate();
|
||||
}
|
||||
|
||||
global proc patternRenameAdd()
|
||||
{
|
||||
global string $PRobjects[];
|
||||
global string $PRsearchUI; // UI name of the input field
|
||||
global string $PRsearch[]; // list of strings to search
|
||||
global string $PRreplaceUI; // UI name of the input field
|
||||
global string $PRreplace[]; // list of strings to replace
|
||||
global string $PRlistSubsUI;
|
||||
global string $PRlistResultsUI;
|
||||
|
||||
|
||||
string $newSearch = `textFieldGrp -q -text $PRsearchUI`;
|
||||
string $newReplace = `textFieldGrp -q -text $PRreplaceUI`;
|
||||
|
||||
if ( $newReplace=="" || isValidString( $newReplace, "([a-zA-Z0-9_])*")) { // no spaces allowed
|
||||
if ($newSearch == "") return;
|
||||
for ( $i=0 ; $i<size($PRsearch) && $newSearch!=$PRsearch[$i] ; $i++ ) ;
|
||||
|
||||
$PRsearch[$i] = $newSearch;
|
||||
$PRreplace[$i] = $newReplace;
|
||||
textFieldGrp -e -text "" $PRsearchUI;
|
||||
textFieldGrp -e -text "" $PRreplaceUI;
|
||||
|
||||
PRredrawSearchReplaceList( $i);
|
||||
patternRenameUpdate();
|
||||
} else warning "No spaces or special characters in replace string allowed - nothing added";
|
||||
}
|
||||
|
||||
global proc patternRenameLoadSelected( string $objects[], string $namespaces[])
|
||||
{
|
||||
$objects = `ls -sl`;
|
||||
clear $namespaces;
|
||||
// now cut off ALL namespaces
|
||||
for ( $i=0 ; $i<size($objects) ; $i++ ) {
|
||||
string $tmp[];
|
||||
int $anz = tokenize( $objects[$i], ":", $tmp);
|
||||
// take the complete name, cut off the last portion = ALL trailing namespaces
|
||||
if ($anz>1) $namespaces[$i] = substring( $objects[$i], 1, size($objects[$i]) - size($tmp[$anz-1]) - 1);
|
||||
else $namespaces[0] = "";
|
||||
// the last token is the object name
|
||||
$objects[$i] = $tmp[$anz-1];
|
||||
}
|
||||
}
|
||||
|
||||
global proc patternRenameReload()
|
||||
{
|
||||
global string $PRobjects[];
|
||||
global string $PRnamespaces[];
|
||||
|
||||
patternRenameLoadSelected( $PRobjects, $PRnamespaces);
|
||||
/* $PRobjects = `ls -sl`;
|
||||
clear $PRnamespaces;
|
||||
// now cut off ALL namespaces
|
||||
for ( $i=0 ; $i<size($PRobjects) ; $i++ ) {
|
||||
string $tmp[];
|
||||
int $anz = tokenize( $PRobjects[$i], ":", $tmp);
|
||||
// take the complete name, cut off the last portion = ALL trailing namespaces
|
||||
if ($anz>1) $PRnamespaces[$i] = substring( $PRobjects[$i], 1, size($PRobjects[$i]) - size($tmp[$anz-1]) - 1);
|
||||
else $PRnamespaces[0] = "";
|
||||
// the last token is the object name
|
||||
$PRobjects[$i] = $tmp[$anz-1];
|
||||
}
|
||||
*/ patternRenameUpdate();
|
||||
}
|
||||
|
||||
global proc patternRenameGo()
|
||||
{
|
||||
global string $PRobjects[];
|
||||
global string $PRnamespaces[];
|
||||
global string $PRsearch[]; // list of strings to search
|
||||
global string $PRreplace[]; // list of strings to replace
|
||||
|
||||
global string $PRmaxIterUI;
|
||||
global string $PRprefixUI;
|
||||
|
||||
int $maxIter = `intFieldGrp -q -v1 $PRmaxIterUI`;
|
||||
string $prefix = `textFieldGrp -q -text $PRprefixUI`;
|
||||
$obj = $PRobjects;
|
||||
$obj = doPatternRename( $obj, $PRsearch, $PRreplace, $prefix, $maxIter);
|
||||
for ( $i=0 ; $i<size($PRobjects) ; $i++ ) {
|
||||
catch( `rename ($PRnamespaces[$i] + ":" + $PRobjects[$i]) ($PRnamespaces[$i] + ":" + $obj[$i])`);
|
||||
}
|
||||
clear $PRobjects;
|
||||
clear $PRnamespaces;
|
||||
PRredrawSearchReplaceList( $i);
|
||||
patternRenameUpdate();
|
||||
}
|
6
Scripts/Modeling/Edit/LDMT/temp/instantMesh_temp.mtl
Normal file
6
Scripts/Modeling/Edit/LDMT/temp/instantMesh_temp.mtl
Normal file
@ -0,0 +1,6 @@
|
||||
newmtl initialShadingGroup
|
||||
illum 4
|
||||
Kd 0.50 0.50 0.50
|
||||
Ka 0.00 0.00 0.00
|
||||
Tf 1.00 1.00 1.00
|
||||
Ni 1.00
|
74
Scripts/Modeling/Edit/LDMT/temp/instantMesh_temp.obj
Normal file
74
Scripts/Modeling/Edit/LDMT/temp/instantMesh_temp.obj
Normal file
@ -0,0 +1,74 @@
|
||||
v -0.334695 -0.333687 0.327576
|
||||
v -0.291528 -0.00363303 0.290792
|
||||
v -0.5 -0.00132766 -0.000194052
|
||||
v -0.290984 -0.292044 -0.00310225
|
||||
v -0.00172517 -0.294468 0.288113
|
||||
v -0.000869247 -0.00853432 0.5
|
||||
v -0.333118 0.325223 0.335069
|
||||
v -0.290686 0.289218 0.0027514
|
||||
v -0.289914 -0.000383876 -0.291317
|
||||
v -0.331467 -0.329182 -0.335327
|
||||
v -0.00169757 -0.5 -0.00594062
|
||||
v 0.329869 -0.337513 0.325327
|
||||
v 0.289696 -0.00521014 0.290542
|
||||
v -0.00039845 0.286972 0.293759
|
||||
v -0.00085076 0.5 0.0058371
|
||||
v -0.333335 0.331917 -0.327388
|
||||
v -5.72049e-05 0.00275149 -0.5
|
||||
v 0.00068111 -0.289822 -0.293995
|
||||
v 0.290004 -0.292403 -0.0031428
|
||||
v 0.5 -0.00221821 -0.0018842
|
||||
v 0.332859 0.324151 0.332961
|
||||
v 0.29023 0.289194 0.00233276
|
||||
v -0.000121877 0.291596 -0.288312
|
||||
v 0.290765 0.0008099 -0.291527
|
||||
v 0.331206 -0.32928 -0.335457
|
||||
v 0.33075 0.334572 -0.327378
|
||||
vn -0.936133 -0.252615 0.244623
|
||||
vn -0.252594 -0.26096 0.931717
|
||||
vn -0.935508 0.250647 0.248999
|
||||
vn -0.934493 -0.249386 -0.254028
|
||||
vn -0.248922 -0.937364 0.243692
|
||||
vn 0.255397 -0.26256 0.930502
|
||||
vn -0.248013 0.244705 0.937341
|
||||
vn -0.255431 0.930561 0.262318
|
||||
vn -0.935341 0.249493 -0.250781
|
||||
vn -0.248122 -0.244255 -0.93743
|
||||
vn -0.249774 -0.933245 -0.2582
|
||||
vn 0.245743 -0.938359 0.24309
|
||||
vn 0.933076 -0.254126 0.254536
|
||||
vn 0.251923 0.245147 0.936183
|
||||
vn 0.257129 0.92935 0.264939
|
||||
vn -0.251658 0.935371 -0.248493
|
||||
vn -0.250509 0.260182 -0.932497
|
||||
vn 0.250541 -0.242097 -0.937347
|
||||
vn 0.251564 -0.933547 -0.255353
|
||||
vn 0.934524 0.247687 0.255571
|
||||
vn 0.934234 -0.252621 -0.251773
|
||||
vn 0.2512 0.936379 -0.245139
|
||||
vn 0.251523 0.259795 -0.932332
|
||||
vn 0.934311 0.254613 -0.249472
|
||||
f 1//1 2//1 3//1 4//1
|
||||
f 1//2 5//2 6//2 2//2
|
||||
f 7//3 8//3 3//3 2//3
|
||||
f 3//4 9//4 10//4 4//4
|
||||
f 1//5 4//5 11//5 5//5
|
||||
f 6//6 5//6 12//6 13//6
|
||||
f 7//7 2//7 6//7 14//7
|
||||
f 7//8 14//8 15//8 8//8
|
||||
f 3//9 8//9 16//9 9//9
|
||||
f 17//10 18//10 10//10 9//10
|
||||
f 11//11 4//11 10//11 18//11
|
||||
f 11//12 19//12 12//12 5//12
|
||||
f 20//13 13//13 12//13 19//13
|
||||
f 6//14 13//14 21//14 14//14
|
||||
f 15//15 14//15 21//15 22//15
|
||||
f 15//16 23//16 16//16 8//16
|
||||
f 17//17 9//17 16//17 23//17
|
||||
f 17//18 24//18 25//18 18//18
|
||||
f 11//19 18//19 25//19 19//19
|
||||
f 20//20 22//20 21//20 13//20
|
||||
f 20//21 19//21 25//21 24//21
|
||||
f 15//22 22//22 26//22 23//22
|
||||
f 17//23 23//23 26//23 24//23
|
||||
f 20//24 24//24 26//24 22//24
|
Reference in New Issue
Block a user