This commit is contained in:
2025-12-05 08:08:44 +08:00
parent e0d4d0c364
commit 1f10abfb32
2909 changed files with 2470486 additions and 3024 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,103 @@
global proc AEahogeShapeTemplate(string $nodeName)
{
editorTemplate -beginScrollLayout;
editorTemplate -beginLayout "Seed" -collapse true;
editorTemplate -addControl "seed";
editorTemplate -endLayout;
editorTemplate -beginLayout "Color" -collapse false;
AEaddRampControl($nodeName + ".colorRamp");
editorTemplate -beginLayout "Mutant Color" -collapse true;
editorTemplate -l "Mutant Color" -addControl "mutantColor";
editorTemplate -l "Mutant Percent" -addControl "mutantPercent";
editorTemplate -l "Mutant Fuzziness" -addControl "mutantFuzziness";
editorTemplate -endLayout;
editorTemplate -beginLayout "Randomize Color" -collapse true;
editorTemplate -l "Randomize Color" -addControl "randomizeColor";
editorTemplate -l "Randomize Saturation" -addControl "randomizeSaturation";
editorTemplate -l "Randomize Value" -addControl "randomizeValue";
editorTemplate -endLayout;
editorTemplate -beginLayout "Absolute Length" -collapse true;
editorTemplate -l "Use Absolute Length" -addControl "useAbsoluteLength";
editorTemplate -l "Absolute Length" -addControl "absoluteLength";
editorTemplate -endLayout;
editorTemplate -endLayout;
editorTemplate -beginLayout "General" -collapse false;
editorTemplate -l "Segments" -addControl "numSegments";
editorTemplate -l "Curves" -addControl "numCurves";
editorTemplate -endLayout;
editorTemplate -beginLayout "Width" -collapse false;
editorTemplate -l "Width" -addControl "width";
AEaddRampControl($nodeName + ".widthRamp");
editorTemplate -endLayout;
editorTemplate -beginLayout "Noise" -collapse false;
editorTemplate -l "Random Placement" -addControl "randomPlacement";
editorTemplate -l "Random Placement Type" -addControl "randomPlacementType";
editorTemplate -l "Noise" -addControl "noise";
editorTemplate -l "Frequency" -addControl "frequency";
editorTemplate -l "Octaves" -addControl "octaves";
editorTemplate -l "Persistence" -addControl "persistence";
AEaddRampControl($nodeName + ".noiseRamp");
editorTemplate -beginLayout "Randomize Frequency" -collapse true;
editorTemplate -l "Enable Randomize Frequency" -addControl "enableRandomizeFrequency";
editorTemplate -l "Randomize Frequency Min" -addControl "randomizeFrequencyMin";
editorTemplate -l "Randomize Frequency Max" -addControl "randomizeFrequencyMax";
AEaddRampControl($nodeName + ".randomizeFrequencyDistribution");
editorTemplate -endLayout;
editorTemplate -beginLayout "Randomize Noise" -collapse true;
editorTemplate -l "Randomize Noise" -addControl "randomizeNoise";
AEaddRampControl($nodeName + ".randomizeNoiseDistribution");
editorTemplate -endLayout;
editorTemplate -endLayout;
editorTemplate -beginLayout "Cut" -collapse false;
editorTemplate -l "Cut" -addControl "cut";
editorTemplate -l "Compress Noise Frequency" -addControl "compressNoiseFrequency";
AEaddRampControl($nodeName + ".cutDistribution");
editorTemplate -endLayout;
editorTemplate -beginLayout "Spray" -collapse false;
editorTemplate -l "Fill" -addControl "fill";
editorTemplate -l "Shift" -addControl "shift";
editorTemplate -l "Spray Along Normal" -addControl "sprayAlongNormal";
editorTemplate -l "Spray" -addControl "spray";
AEaddRampControl($nodeName + ".sprayRamp");
AEaddRampControl($nodeName + ".sprayDistribution");
editorTemplate -endLayout;
editorTemplate -beginLayout "Multistrand" -collapse false;
editorTemplate -l "Multistrand" -addControl "multistrand";
editorTemplate -l "Multistrand Percent" -addControl "multistrandPercent";
editorTemplate -l "Multistrand Randomize" -addControl "multistrandRandomize";
editorTemplate -l "Multistrand Randomize Tip" -addControl "multistrandRandomizeTip";
editorTemplate -l "Multistrand Twist" -addControl "multistrandTwist";
editorTemplate -l "Multistrand Twist Randomize" -addControl "multistrandTwistRandomize";
editorTemplate -l "Multistrand Spray" -addControl "multistrandSpray";
editorTemplate -l "Multistrand Randomize Spray" -addControl "multistrandRandomizeSpray";
AEaddRampControl($nodeName + ".multistrandSprayRamp");
editorTemplate -endLayout;
editorTemplate -beginLayout "Arnold" -collapse true;
editorTemplate -l "Mode" -addControl "aiMode";
editorTemplate -l "Min Pixel Width" -addControl "aiMinPixelWidth";
editorTemplate -endLayout;
editorTemplate -beginLayout "Viewport" -collapse true;
editorTemplate -l "Display Mode" -addControl "displayMode";
editorTemplate -l "Preview Percent" -addControl "previewPercent";
editorTemplate -l "Preview Sides" -addControl "previewSides";
editorTemplate -endLayout;
AEsurfaceShapeTemplate $nodeName;
editorTemplate -addExtraControls;
editorTemplate -endScrollLayout;
}

View File

@@ -0,0 +1,32 @@
global proc AEnurbopusNodeTemplate(string $nodeName)
{
editorTemplate -beginScrollLayout;
editorTemplate -beginLayout "General" -collapse false;
editorTemplate -l "Up Vector" -addControl "upVector";
editorTemplate -l "Method" -addControl "method";
editorTemplate -l "Shape" -addControl "shape";
editorTemplate -l "U Segments" -addControl "uSegments";
editorTemplate -l "V Segments" -addControl "vSegments";
editorTemplate -l "Segments Power" -addControl "segmentsPower";
editorTemplate -l "Radius" -addControl "radius";
editorTemplate -l "Scale Y" -addControl "scaleY";
editorTemplate -l "Rotate" -addControl "rotate";
editorTemplate -l "twist" -addControl "twist";
AEaddRampControl($nodeName + ".ramp");
editorTemplate -endLayout;
editorTemplate -beginLayout "Orientation" -collapse false;
editorTemplate -l "Use Mesh Normal" -addControl "useMeshNormal";
editorTemplate -l "Orient Method" -addControl "orientMethod";
editorTemplate -l "Orient" -addControl "orient";
editorTemplate -l "Orient Point" -addControl "orientPoint";
editorTemplate -l "Orient Segment" -addControl "orientSegment";
editorTemplate -endLayout;
AEdependNodeTemplate $nodeName;
editorTemplate -addExtraControls;
editorTemplate -endScrollLayout;
}

View File

@@ -0,0 +1,484 @@
global proc ahogeTools()
{
if (`menu -exists ahogeToolsMenu`)
{
deleteUI ahogeToolsMenu;
}
else
{
menu -l "Ahoge"
-tearOff true
-p "MayaWindow" ahogeToolsMenu;
menuItem -l "Ahoge"
-c "python(\"import ahoge_ui;ahoge_ui.create_ahoge()\")"
-ann "Create an ahogeShape node with a random seed and connect the selected surfaces"
-i "ahogeShape.png"
-p ahogeToolsMenu;
menuItem -optionBox true
-c "python(\"import ahoge_ui;ahoge_ui.create_ahoge_options()\")"
-p ahogeToolsMenu;
menuItem -l "Connect"
-c "ahogeTools_connect"
-ann "Connect the selected nurbs surfaces to the selected ahogeShape nodes"
-i "ahoge_connect.png"
-p ahogeToolsMenu;
menuItem -l "Disconnect"
-c "ahogeTools_disconnect"
-ann "Disconnect the selected nurbs surfaces from the selected ahogeShape nodes"
-i "ahoge_disconnect.png"
-p ahogeToolsMenu;
menuItem -l "Duplicate"
-subMenu true
-ann "Duplicate ahogeShape nodes"
-i "ahoge_duplicate.png"
-p ahogeToolsMenu ahogeToolsMenu_duplicate_menu;
menuItem -l "Ahoge"
-c "ahogeTools_duplicateAhoge"
-ann "Duplicate the selected ahogeShape nodes and set random seeds"
-i "ahogeShape.png"
-p ahogeToolsMenu_duplicate_menu;
menuItem -l "Ahoge and Connect"
-c "ahogeTools_duplicateAhoge_connect"
-ann "Duplicate the selected ahogeShape nodes, connect the selected surfaces to them, and set random seeds"
-i "ahoge_connect.png"
-p ahogeToolsMenu_duplicate_menu;
menuItem -l "Extra"
-subMenu true
-ann "Extra nodes"
-i "ahoge_extra.png"
-p ahogeToolsMenu ahogeToolsMenu_extra_menu;
menuItem -l "Nurbopus"
-c "python(\"import ahoge_ui;ahoge_ui.create_nurbopus()\")"
-ann "Select curves and optionally a mesh to create Nurbopus"
-i "out_nurbopusNode.png"
-p ahogeToolsMenu_extra_menu;
menuItem -optionBox true
-c "python(\"import ahoge_ui;ahoge_ui.create_nurbopus_options()\")"
-p ahogeToolsMenu_extra_menu;
menuItem -l "Connect"
-c "ahogeTools_nurbopus_connect"
-ann "Select surfaces that have Nurbopus and curves to connect the selected curves to the Nurbopus node"
-i "ahoge_connect.png"
-p ahogeToolsMenu_extra_menu;
menuItem -l "Detach"
-c "ahogeTools_nurbopus_detach"
-ann "Disconnect the selected surfaces from their Nurbopus node, duplicate the Nurbopus node, and connect the duplicated Nurbopus node to the curves of the selected surfaces"
-i "ahoge_detach.png"
-p ahogeToolsMenu_extra_menu;
menuItem -l "Miscellaneous"
-subMenu true
-ann "Miscellaneous Tools"
-i "ahoge_misc.png"
-p ahogeToolsMenu ahogeToolsMenu_misc_menu;
menuItem -l "Fix Surfaces"
-c "ahogeTools_fixSurfaces"
-ann "Select Nurbs Surfaces and a Mesh to fix the Surfaces"
-i "ahoge_fix.png"
-p ahogeToolsMenu_misc_menu;
menuItem -l "Select Connected Surfaces"
-c "ahogeTools_selectConnectedSurfaces"
-ann "Select Nurbs Surfaces that are connected to the selected Ahoge Shapes"
-i "aselect.png"
-p ahogeToolsMenu_misc_menu;
menuItem -l "Disconnect Connected Surfaces"
-c "ahogeTools_disconnectConnectedSurfaces"
-ann "Disconnect Nurbs Surfaces that are connected to the selected Ahoge Shapes"
-i "ahoge_disconnect.png"
-p ahogeToolsMenu_misc_menu;
menuItem -l "Select"
-subMenu true
-ann "Select ahogeShape nodes"
-pmc "ahogeTools_select_pmc"
-i "aselect.png"
-p ahogeToolsMenu ahogeToolsMenu_select_menu;
menuItem -l "Convert"
-subMenu true
-ann "Convert ahogeShape nodes"
-i "ahoge_convert.png"
-p ahogeToolsMenu ahogeToolsMenu_convert_menu;
menuItem -l "Convert to Curves"
-c "ahogeTools_convertToCurves"
-ann "Convert the selected ahogeShape nodes to nurbs curves"
-i "curveEP.png"
-p ahogeToolsMenu_convert_menu;
menuItem -l "Export"
-subMenu true
-ann "Export ahogeShape nodes"
-i "ahoge_export.png"
-p ahogeToolsMenu ahogeToolsMenu_export_menu;
menuItem -l "Export Alembic"
-c "python(\"import ahoge_ui;ahoge_ui.export_alembic_options()\")"
-ann "Export ahogeShape nodes to Alembic"
-i "ahoge_abc.png"
-p ahogeToolsMenu_export_menu;
menuItem -d true -p ahogeToolsMenu;
menuItem -l "Support"
-c "ahogeTools_support"
-ann "Get support and updates"
-i "ahoge_info.png"
-p ahogeToolsMenu;
}
}
global proc ahogeTools_disconnect_attr( string $left, string $right )
{
string $connections[] = `listConnections -p true $left`;
string $connection;
for ($connection in $connections)
{
string $ending = `match "\[[0-9]+\]$" $connection`;
string $short = `substring $connection 1 (size($connection) - size($ending))`;
if ( $short == $right )
{
disconnectAttr $left $connection;
}
}
}
global proc ahogeTools_connect()
{
string $surfaces[] = `ls -sl -dag -type "nurbsSurface"`;
string $ahogeShapes[] = `ls -sl -dag -type "ahogeShape"`;
string $ahogeShape;
for ($ahogeShape in $ahogeShapes)
{
string $inputSurfaces[] = `listConnections -p true ($ahogeShape + ".inputSurfaces")`;
string $inputSurfacesObj[] = `listConnections -p false ($ahogeShape + ".inputSurfaces")`;
$inputSurfacesObj = `ls -dag -type "nurbsSurface" $inputSurfacesObj`;
string $connect;
for ($connect in $inputSurfaces)
{
ahogeTools_disconnect_attr $connect ($ahogeShape + ".inputSurfaces");
}
string $surfacesToAdd[] = {};
string $surface;
for ($surface in $surfaces)
{
if (!stringArrayContains($surface, $inputSurfacesObj))
{
$surfacesToAdd[size($surfacesToAdd)] = $surface;
}
}
string $diffSurfaces[] = stringArrayCatenate($inputSurfacesObj, $surfacesToAdd);
int $i = 0;
for (; $i < size($diffSurfaces); $i++ )
{
connectAttr ($diffSurfaces[$i] + ".worldSpace[0]") ($ahogeShape + ".inputSurfaces[" + $i + "]");
}
}
}
global proc ahogeTools_disconnect()
{
string $surfaces[] = `ls -sl -dag -type "nurbsSurface"`;
string $ahogeShapes[] = `ls -sl -dag -type "ahogeShape"`;
string $ahogeShape;
for ($ahogeShape in $ahogeShapes)
{
string $inputSurfaces[] = `listConnections -p true ($ahogeShape + ".inputSurfaces")`;
string $inputSurfacesObj[] = `listConnections -p false ($ahogeShape + ".inputSurfaces")`;
$inputSurfacesObj = `ls -dag -type "nurbsSurface" $inputSurfacesObj`;
string $connect;
for ($connect in $inputSurfaces)
{
ahogeTools_disconnect_attr $connect ($ahogeShape + ".inputSurfaces");
}
string $diffSurfaces[] = stringArrayRemove($surfaces, $inputSurfacesObj);
int $i = 0;
for (; $i < size($diffSurfaces); $i++ )
{
connectAttr ($diffSurfaces[$i] + ".worldSpace[0]") ($ahogeShape + ".inputSurfaces[" + $i + "]");
}
}
}
global proc ahogeTools_duplicateAhoge()
{
string $ahoges[] = `ls -dag -sl -l -type ahogeShape`;
string $ahoge;
for ($ahoge in $ahoges)
{
string $dup[] = `duplicate -ic $ahoge`;
setAttr ($dup[0] + ".seed") (int(rand(100000)));
}
}
global proc ahogeTools_duplicateAhoge_connect()
{
string $ahoges[] = `ls -dag -sl -l -type ahogeShape`;
string $surfaces[] = `ls -dag -sl -l -type nurbsSurface`;
if (size($ahoges) < 1) error "you haven't selected any ahogeShapes";
if (size($surfaces) < 1) error "you haven't selected any surfaces";
string $ahoge;
for ($ahoge in $ahoges)
{
string $dup[] = `duplicate $ahoge`;
string $multiInstances[] = `listAttr ($dup[0] + ".inputSurfaces[*]")`;
string $multiInstance;
for ($multiInstance in $multiInstances)
{
removeMultiInstance -b true ($dup[0] + "." + $multiInstance);
}
int $i = 0;
for (; $i < size($surfaces); $i++)
{
connectAttr -f ($surfaces[$i] + ".worldSpace[0]") ($dup[0] + ".inputSurfaces[" + $i + "]");
}
setAttr ($dup[0] + ".seed") (int(rand(100000)));
}
}
global proc ahogeTools_select_pmc()
{
menu -e -dai ahogeToolsMenu_select_menu;
string $ahogeShapes[] = `ls -l -type ahogeShape`;
string $ahogeShapesSelected[] = `ls -sl -dag -l -type ahogeShape`;
string $node;
for ($node in $ahogeShapes)
{
string $name[] = `listRelatives -parent $node`;
menuItem -cb (stringArrayContains($node, $ahogeShapesSelected)) -l $name[0] -c ("select " + $node) -p ahogeToolsMenu_select_menu;
}
if (!size($ahogeShapes)) menuItem -l "Nothing" -en false -p ahogeToolsMenu_select_menu;
}
global proc ahogeTools_convertToCurves()
{
string $ahogeShape[] = `ls -l -sl -dag -type "ahogeShape"`;
string $node;
for ($node in $ahogeShape)
{
int $num = `getAttr ($node + ".numSegments")` + 1;
float $cvs[] = `getAttr ($node + ".outputPoints")`;
string $parent[] = `listRelatives -f -parent $node`;
float $m[] = `xform -q -ws -m $parent[0]`;
int $numCurves = size($cvs) / $num / 3;
int $i = 0;
for (; $i < $numCurves; $i++)
{
string $curve = "curve -d 3";
int $j = 0;
for (; $j < $num; $j++)
{
vector $p = << $cvs[$i*$num*3+$j*3], $cvs[$i*$num*3+$j*3 + 1], $cvs[$i*$num*3+$j*3 + 2] >>;
$p = pointMatrixMult($p, $m);
$p += <<$m[12], $m[13], $m[14]>>;
$curve += " -p " + ($p.x) + " " + ($p.y) + " " + ($p.z);
}
eval $curve;
}
}
}
global proc ahogeTools_support()
{
python("import webbrowser;webbrowser.open('https://boosty.to/ahoge')");
}
// Misc
global proc float ahoge_distance(vector $v1, vector $v2)
{
return sqrt(pow(($v1.x) - ($v2.x), 2) + pow(($v1.y) - ($v2.y), 2) + pow(($v1.z) - ($v2.z), 2));
}
global proc ahogeTools_fixSurfaces()
{
string $surfaces[] = `ls -dag -sl -l -type nurbsSurface`;
string $meshes[] = `ls -dag -sl -l -type mesh`;
if (!size($surfaces)) error "No nurbsSurfaces selected";
if (size($meshes) != 1) error "Select a mesh";
string $surface;
for ($surface in $surfaces)
{
// reverse direction
if ((`getAttr ($surface + ".fu")` == 0) &&
((`getAttr ($surface + ".fv")` == 1) ||
(`getAttr ($surface + ".fv")` == 2)))
{
reverseSurface -d 3 -ch 0 -rpo 1 $surface;
reverseSurface -d 0 -ch 0 -rpo 1 $surface;
}
vector $first_point = << 0, 0, 0 >>;
vector $second_point = << 0, 0, 0 >>;
int $i = 0;
for (; $i < 4; $i++)
{
$first_point += `pointOnSurface -top true -u (float($i) / 4) -v 0.0 -position $surface`;
$second_point += `pointOnSurface -top true -u (float($i) / 4) -v 1.0 -position $surface`;
}
$first_point = $first_point / 4;
$second_point = $second_point / 4;
// check for inverted normals first
vector $norm = `pointOnSurface -u 0.0 -v 0.0 -nn $surface`;
vector $origin = `pointOnSurface -u 0.0 -v 0.0 -position $surface`;
if (dot($norm, $first_point - $origin) > 0)
{
reverseSurface -d 0 -ch 0 -rpo 1 $surface;
}
//print($first_point.x + " " + $first_point.y + " " + $first_point.z + "\n");
//print($second_point.x + " " + $second_point.y + " " + $second_point.z + "\n");
vector $first_point_surface = `ahogeCmd -m $meshes[0] -cp ($first_point.x) ($first_point.y) ($first_point.z)`;
vector $second_point_surface = `ahogeCmd -m $meshes[0] -cp ($second_point.x) ($second_point.y) ($second_point.z)`;
float $first_point_distance = ahoge_distance($first_point, $first_point_surface);
float $second_point_distance = ahoge_distance($second_point, $second_point_surface);
if ($first_point_distance < $second_point_distance) // needs to reverse V then
{
reverseSurface -d 1 -ch 0 -rpo 1 $surface;
reverseSurface -d 0 -ch 0 -rpo 1 $surface;
}
}
}
global proc ahogeTools_selectConnectedSurfaces()
{
string $ahogeShapes[] = `ls -sl -dag -type "ahogeShape"`;
string $result[] = {};
string $ahogeShape;
for ($ahogeShape in $ahogeShapes)
{
string $inputSurfacesObj[] = `listConnections -p false ($ahogeShape + ".inputSurfaces")`;
$inputSurfacesObj = `ls -dag -type "nurbsSurface" $inputSurfacesObj`;
string $surface;
for ($surface in $inputSurfacesObj)
{
$result[size($result)] = $surface;
}
}
select $result;
}
global proc ahogeTools_disconnectConnectedSurfaces()
{
string $ahogeShapes[] = `ls -sl -dag -type "ahogeShape"`;
string $ahogeShape;
for ($ahogeShape in $ahogeShapes)
{
string $inputSurfaces[] = `listConnections -p true ($ahogeShape + ".inputSurfaces")`;
string $connect;
for ($connect in $inputSurfaces)
{
ahogeTools_disconnect_attr $connect ($ahogeShape + ".inputSurfaces");
}
}
}
global proc ahogeTools_nurbopus_connect()
{
string $surfaces[] = `ls -sl -dag -type "nurbsSurface"`;
if (size($surfaces) == 0) error "No nurbsSurface selected";
string $history[] = `listHistory $surfaces`;
string $nurbopuses[] = `ls -type "nurbopusNode" $history`;
string $curves[] = `ls -sl -dag -type "nurbsCurve"`;
if (size($nurbopuses) == 0) error "No nurbopusNode selected";
if (size($curves) == 0) error "No nurbsCurve selected";
string $nurbopus;
for ($nurbopus in $nurbopuses)
{
int $size = `getAttr -size ($nurbopus + ".inputCurves")`;
int $i = 0;
for (; $i < size($curves); $i++)
{
connectAttr ($curves[$i] + ".worldSpace[0]") ($nurbopus + ".inputCurves[" + ($size + $i) + "]");
string $surface = `createNode "nurbsSurface"`;
connectAttr ($nurbopus + ".outputSurfaces[" + ($size + $i) + "]") ($surface + ".create");
hyperShade -assign "initialShadingGroup" $surface;
}
}
}
global proc int ahogeTools_extract(string $str)
{
string $str_idx = `match "\[[0-9]+\]$" $str`;
string $array[];
tokenize $str_idx "[]" $array;
return int($array[0]);
}
global proc ahogeTools_nurbopus_detach()
{
string $surfaces[] = `ls -sl -dag -type "nurbsSurface"`;
if (size($surfaces) == 0) error "No nurbsSurface selected";
string $history[] = `listHistory $surfaces`;
string $nurbopuses[] = `ls -type "nurbopusNode" $history`;
if (size($nurbopuses) == 0) error "No nurbopusNode selected";
if (size($nurbopuses) != 1) error "Detach only works with a single nurbopusNode";
string $duplicate[] = `duplicate $nurbopuses[0]`;
int $connectionIndices[] = {};
int $i = 0;
for (; $i < size($surfaces); $i++)
{
string $surfaceCreate[] = `listConnections -c true -p true ($surfaces[$i] + ".create")`;
$connectionIndices[size($connectionIndices)] = ahogeTools_extract($surfaceCreate[1]);
}
string $output_surfaces[] = `listConnections -p false ($nurbopuses[0] + ".outputSurfaces")`;
$output_surfaces = `ls -dag -type "nurbsSurface" $output_surfaces`;
string $inputCurves[] = `listConnections -p true ($nurbopuses[0] + ".inputCurves")`;
string $inputCurvesObj[] = `listConnections -p false ($nurbopuses[0] + ".inputCurves")`;
$inputCurvesObj = `ls -dag -type "nurbsCurve" $inputCurvesObj`;
string $connect;
for ($connect in $inputCurves)
{
ahogeTools_disconnect_attr $connect ($nurbopuses[0] + ".inputCurves");
}
int $first_count = 0;
int $second_count = 0;
for ($i = 0; $i < size($inputCurvesObj); $i++)
{
if (intArrayContains($i, $connectionIndices))
{
connectAttr ($inputCurvesObj[$i] + ".worldSpace[0]") ($duplicate[0] + ".inputCurves[" + $first_count + "]");
connectAttr -f ($duplicate[0] + ".outputSurfaces[" + $first_count + "]") ($output_surfaces[$i] + ".create");
$first_count++;
}
else
{
connectAttr ($inputCurvesObj[$i] + ".worldSpace[0]") ($nurbopuses[0] + ".inputCurves[" + $second_count + "]");
connectAttr -f ($nurbopuses[0] + ".outputSurfaces[" + $second_count + "]") ($output_surfaces[$i] + ".create");
$second_count++;
}
}
}

View File

@@ -0,0 +1,489 @@
import maya.cmds as cmds
if cmds.about(version=True) == "2025":
from PySide6 import QtWidgets, QtGui
import shiboken6 as shiboken
else:
from PySide2 import QtWidgets, QtGui
import shiboken2 as shiboken
import maya.OpenMayaUI as omui
from enum import Enum
import random
import os
import pathlib
from datetime import datetime
import time
def get_scaling_ratio():
screen = QtGui.QGuiApplication.primaryScreen()
return screen.logicalDotsPerInch() / 96.0
scaling_ratio = get_scaling_ratio()
def maya_main_window():
main_window_pointer = omui.MQtUtil.mainWindow()
return shiboken.wrapInstance(int(main_window_pointer), QtWidgets.QWidget)
class OptionType(Enum):
Unknown = 1
Bool = 2
Int = 3
Float = 4
Option = 5
File = 6
class Option:
option_type = OptionType.Unknown
option_name = None
default = None
setting = None
widget = None
def __init__(self, option_name, option_type, default, setting, meta=None):
self.option_name = option_name
self.option_type = option_type
self.default = default
self.setting = setting
self.meta = meta
def make_widget(self, form_layout):
if self.option_type == OptionType.Bool:
self.widget = QtWidgets.QCheckBox()
self.widget.setChecked(self.default)
form_layout.addRow(self.option_name + ":", self.widget)
elif self.option_type == OptionType.Int:
self.widget = QtWidgets.QSpinBox()
self.widget.setFixedWidth(70 * scaling_ratio)
self.widget.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
if self.meta:
if "min" in self.meta:
self.widget.setMinimum(self.meta["min"])
if "max" in self.meta:
self.widget.setMaximum(self.meta["max"])
self.widget.setValue(self.default)
form_layout.addRow(self.option_name + ":", self.widget)
elif self.option_type == OptionType.Float:
self.widget = QtWidgets.QDoubleSpinBox()
self.widget.setDecimals(4)
self.widget.setSingleStep(0.01)
self.widget.setFixedWidth(70 * scaling_ratio)
self.widget.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
if self.meta:
if "min" in self.meta:
self.widget.setMinimum(self.meta["min"])
if "max" in self.meta:
self.widget.setMaximum(self.meta["max"])
self.widget.setValue(self.default)
form_layout.addRow(self.option_name + ":", self.widget)
elif self.option_type == OptionType.Option:
self.widget = QtWidgets.QComboBox()
if self.meta:
if "options" in self.meta:
for option in self.meta["options"]:
self.widget.addItem(option[1], option[0])
form_layout.addRow(self.option_name + ":", self.widget)
index = self.widget.findData(self.default)
self.widget.setCurrentIndex(index)
elif self.option_type == OptionType.File:
self.widget = QtWidgets.QLineEdit()
widget_layout = QtWidgets.QHBoxLayout()
widget_layout.setContentsMargins(0, 0, 0, 0)
browse_button = QtWidgets.QPushButton("Browse")
def browse_action():
path = self.widget.text()
file_filter = ""
if self.meta:
if "fileFilter" in self.meta:
file_filter = self.meta["fileFilter"]
result = cmds.fileDialog2(dir=path, fileFilter=file_filter, dialogStyle=2)
if result:
self.widget.setText(result[0])
browse_button.clicked.connect(browse_action)
widget_layout.addWidget(self.widget)
widget_layout.addWidget(browse_button)
form_layout.addRow(self.option_name + ":", widget_layout)
self.widget.setText(self.default)
def load(self):
if not self.widget:
return
if self.option_type == OptionType.Bool:
if cmds.optionVar(exists=self.setting):
value = bool(cmds.optionVar(q=self.setting))
self.widget.setChecked(value)
elif self.option_type == OptionType.Int:
if cmds.optionVar(exists=self.setting):
value = cmds.optionVar(q=self.setting)
self.widget.setValue(value)
elif self.option_type == OptionType.Float:
if cmds.optionVar(exists=self.setting):
value = cmds.optionVar(q=self.setting)
self.widget.setValue(value)
elif self.option_type == OptionType.Option:
if cmds.optionVar(exists=self.setting):
value = cmds.optionVar(q=self.setting)
index = self.widget.findData(value)
self.widget.setCurrentIndex(index)
elif self.option_type == OptionType.File:
if cmds.optionVar(exists=self.setting):
value = cmds.optionVar(q=self.setting)
self.widget.setText(value)
def save(self):
if not self.widget:
return
if self.option_type == OptionType.Bool:
if self.widget.isChecked():
cmds.optionVar(iv=(self.setting, 1))
else:
cmds.optionVar(iv=(self.setting, 0))
elif self.option_type == OptionType.Int:
cmds.optionVar(iv=(self.setting, self.widget.value()))
elif self.option_type == OptionType.Float:
cmds.optionVar(fv=(self.setting, self.widget.value()))
elif self.option_type == OptionType.Option:
cmds.optionVar(iv=(self.setting, self.widget.currentData()))
elif self.option_type == OptionType.File:
cmds.optionVar(sv=(self.setting, self.widget.text()))
def reset(self):
if not self.widget:
return
if self.option_type == OptionType.Bool:
self.widget.setChecked(self.default)
if self.default:
cmds.optionVar(iv=(self.setting, 1))
else:
cmds.optionVar(iv=(self.setting, 0))
elif self.option_type == OptionType.Int:
self.widget.setValue(self.default)
cmds.optionVar(iv=(self.setting, self.default))
elif self.option_type == OptionType.Float:
self.widget.setValue(self.default)
cmds.optionVar(fv=(self.setting, self.default))
elif self.option_type == OptionType.Option:
index = self.widget.findData(self.default)
self.widget.setCurrentIndex(index)
cmds.optionVar(iv=(self.setting, self.default))
elif self.option_type == OptionType.File:
self.widget.setText(self.default)
cmds.optionVar(sv=(self.setting, self.default))
class OptionsDialogType(Enum):
Create = 1
Export = 2
class OptionsDialog(QtWidgets.QDialog):
def __init__(self, options_dialog_type, title, command, options, parent=None):
super(OptionsDialog, self).__init__(parent)
self.setWindowTitle(title)
self.options_dialog_type = options_dialog_type
self.command = command
self.options = options
layout = QtWidgets.QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
menu_bar = QtWidgets.QMenuBar()
edit_menu = menu_bar.addMenu("Edit")
edit_menu.addAction("Save Settings", self.save)
edit_menu.addAction("Reset Settings", self.reset)
if self.options_dialog_type == OptionsDialogType.Export:
edit_menu.addSeparator()
edit_menu.addAction("Clear Log", self.clear_log)
layout.addWidget(menu_bar)
form_layout = QtWidgets.QFormLayout()
form_layout_margins = 8 * scaling_ratio
form_layout.setContentsMargins(
form_layout_margins, form_layout_margins, form_layout_margins, form_layout_margins)
for option in self.options:
option.make_widget(form_layout)
layout.addLayout(form_layout)
if options_dialog_type == OptionsDialogType.Create:
layout.addStretch()
buttons_layout = QtWidgets.QHBoxLayout()
layout.addLayout(buttons_layout)
buttons_layout_margins = 4 * scaling_ratio
buttons_layout.setContentsMargins(
buttons_layout_margins, buttons_layout_margins, buttons_layout_margins, buttons_layout_margins)
buttons_layout.setSpacing(4)
if options_dialog_type == OptionsDialogType.Create:
create_button = QtWidgets.QPushButton("Create")
apply_button = QtWidgets.QPushButton("Apply")
close_button = QtWidgets.QPushButton("Close")
create_button.clicked.connect(self.create)
apply_button.clicked.connect(self.apply)
close_button.clicked.connect(self.close)
buttons_layout.addWidget(create_button)
buttons_layout.addWidget(apply_button)
buttons_layout.addWidget(close_button)
elif options_dialog_type == OptionsDialogType.Export:
self.log = QtWidgets.QTextEdit()
#self.log.setFixedHeight(80)
self.log.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
self.log.setReadOnly(True)
form_layout.addRow("Log:", self.log)
export_button = QtWidgets.QPushButton("Export")
close_button = QtWidgets.QPushButton("Close")
export_button.clicked.connect(self.apply)
close_button.clicked.connect(self.close)
buttons_layout.addStretch()
buttons_layout.addWidget(export_button)
buttons_layout.addWidget(close_button)
self.load()
self.show()
def load(self):
for option in self.options:
option.load()
def save(self):
for option in self.options:
option.save()
def reset(self):
for option in self.options:
option.reset()
def create(self):
self.save()
self.command()
self.close()
def apply(self):
self.save()
if self.options_dialog_type == OptionsDialogType.Export:
start_time = time.time()
start_date = datetime.now()
self.log.moveCursor(QtGui.QTextCursor.End)
self.log.append("<font color=grey>Export started</font> " + str(start_date))
try:
self.command()
end_time = time.time()
end_date = datetime.now()
self.log.moveCursor(QtGui.QTextCursor.End)
self.log.append("<font color=grey>Export ended</font> " + str(end_date))
self.log.append("<font color=grey>Export took</font> %.4f <font color=grey>seconds</font>" % (end_time - start_time))
self.log.append("<font color=green>Done</font>")
except Exception as e:
self.log.moveCursor(QtGui.QTextCursor.End)
self.log.append("<font color=orange>%s</font>" % e)
self.log.append("<font color=red>Failure</font>")
else:
self.command()
def activate(self):
self.load()
self.show()
self.activateWindow()
def clear_log(self):
self.log.clear()
def get_value(setting):
if cmds.optionVar(exists=setting[1]):
return cmds.optionVar(q=setting[1])
return setting[0]
create_ahoge_window = None
create_ahoge_randomize_seed = [True, "ahoge_randomize_seed"]
create_ahoge_swap_uv = [True, "ahoge_randomize_swap_uv"]
create_ahoge_segments = [16, "ahoge_segments"]
create_ahoge_number_of_curves = [10, "ahoge_number_of_curves"]
create_ahoge_width = [0.01, "ahoge_width"]
def create_ahoge():
cmds.undoInfo(chunkName="create_ahoge", openChunk=True)
try:
randomize_seed = get_value(create_ahoge_randomize_seed)
swap_uv = get_value(create_ahoge_swap_uv)
segments = get_value(create_ahoge_segments)
number_of_curves = get_value(create_ahoge_number_of_curves)
width = get_value(create_ahoge_width)
surfaces = cmds.ls(sl=True, dag=True, type="nurbsSurface")
ahoge_shape = cmds.createNode("ahogeShape")
if randomize_seed:
cmds.setAttr(ahoge_shape + ".seed", random.randint(0, 10000))
cmds.setAttr(ahoge_shape + ".numSegments", segments)
cmds.setAttr(ahoge_shape + ".numCurves", number_of_curves)
cmds.setAttr(ahoge_shape + ".width", width)
for index, surface in enumerate(surfaces):
if swap_uv and cmds.getAttr(surface + ".fu") == 0 and cmds.getAttr(surface + ".fv") == 2:
cmds.warning(surface + " swapping UV")
cmds.reverseSurface(surface, d=3, ch=1, rpo=1)
cmds.reverseSurface(surface, d=0, ch=1, rpo=1)
cmds.connectAttr(surface + ".worldSpace[0]", ahoge_shape + ".inputSurfaces[" + str(index) + "]")
finally:
cmds.undoInfo(closeChunk=True)
def create_ahoge_options():
global create_ahoge_window
if not create_ahoge_window:
title = "Create Ahoge Options"
options = []
options.append(Option("Randomize Seed", OptionType.Bool, *create_ahoge_randomize_seed))
options.append(Option("Swap UV", OptionType.Bool, *create_ahoge_swap_uv))
options.append(Option("Segments", OptionType.Int, *create_ahoge_segments, {"min": 1, "max": 1000000}))
options.append(Option("Number of Curves", OptionType.Int, *create_ahoge_number_of_curves, {"min": 1, "max": 1000000}))
options.append(Option("Width", OptionType.Float, *create_ahoge_width, {"min": 0.0001, "max": 1000000.0}))
create_ahoge_window = OptionsDialog(OptionsDialogType.Create, title, create_ahoge, options, maya_main_window())
else:
create_ahoge_window.activate()
create_nurbopus_window = None
create_nurbopus_method = [1, "ahoge_nurbopus_method"]
create_nurbopus_shape = [0, "ahoge_nurbopus_shape"]
create_nurbopus_useg = [4, "ahoge_nurbopus_useg"]
create_nurbopus_vseg = [8, "ahoge_nurbopus_vseg"]
def create_nurbopus():
cmds.undoInfo(chunkName="create_nurbopus", openChunk=True)
try:
method = get_value(create_nurbopus_method)
shape = get_value(create_nurbopus_shape)
useg = get_value(create_nurbopus_useg)
vseg = get_value(create_nurbopus_vseg)
curves = cmds.ls(sl=True, dag=True, type="nurbsCurve")
if not curves:
cmds.error("No curves selected")
meshes = cmds.ls(sl=True, dag=True, type="mesh")
nurbopus = cmds.createNode("nurbopusNode")
cmds.setAttr(nurbopus + ".method", method)
cmds.setAttr(nurbopus + ".shape", shape)
cmds.setAttr(nurbopus + ".uSegments", useg)
cmds.setAttr(nurbopus + ".vSegments", vseg)
for index, curve in enumerate(curves):
cmds.connectAttr(curve + ".worldSpace[0]", nurbopus + ".inputCurves[" + str(index) + "]")
surface = cmds.createNode("nurbsSurface")
cmds.connectAttr(nurbopus + ".outputSurfaces[" + str(index) + "]", surface + ".create")
cmds.hyperShade(surface, assign="initialShadingGroup")
if meshes:
cmds.connectAttr(meshes[0] + ".worldMesh[0]", nurbopus + ".inputMesh")
cmds.select(nurbopus)
finally:
cmds.undoInfo(closeChunk=True)
def create_nurbopus_options():
global create_nurbopus_window
if not create_nurbopus_window:
title = "Create Nurbopus Options"
options = []
options.append(Option("Method", OptionType.Option, *create_nurbopus_method, {"options": [[0, "Up Vector"], [1, "Untwist"]]}))
options.append(Option("Shape", OptionType.Option, *create_nurbopus_shape, {"options": [[0, "circle"], [1, "line"]]}))
options.append(Option("U Segments", OptionType.Int, *create_nurbopus_useg, {"min": 1, "max": 1000000}))
options.append(Option("V Segments", OptionType.Int, *create_nurbopus_vseg, {"min": 1, "max": 1000000}))
create_nurbopus_window = OptionsDialog(OptionsDialogType.Create, title, create_nurbopus, options, maya_main_window())
else:
create_nurbopus_window.activate()
export_alembic_window = None
abc_path = pathlib.Path(os.environ["MAYA_APP_DIR"])
abc_path = abc_path / "projects" / "default" / "data" / "test.abc"
export_alembic_path = [str(abc_path), "ahoge_export_alembic_path"]
export_alembic_mode = [0, "ahoge_export_alembic_mode"]
export_alembic_time_range = [0, "ahoge_export_alembic_time_range"]
export_alembic_start = [1, "ahoge_export_alembic_start"]
export_alembic_end = [24, "ahoge_export_alembic_end"]
export_alembic_relative_sample = [False, "ahoge_export_alembic_relative_sample"]
export_alembic_low = [-0.2, "ahoge_export_alembic_low"]
export_alembic_high = [0.2, "ahoge_export_alembic_high"]
def export_alembic():
alembic_mode = get_value(export_alembic_mode)
alembic_time_range = get_value(export_alembic_time_range)
alembic_path = get_value(export_alembic_path)
start = get_value(export_alembic_start)
end = get_value(export_alembic_end)
relative_sample = get_value(export_alembic_relative_sample)
low = get_value(export_alembic_low)
high = get_value(export_alembic_high)
export_mode="default"
if alembic_mode == 1:
export_mode = "unreal"
elif alembic_mode == 2:
export_mode = "marmoset"
extra = ""
time_range = "current_frame"
if alembic_time_range == 1:
time_range = "time_slider"
elif alembic_time_range == 2:
time_range = "start_end"
extra += " -startEnd %d %d" % (start, end)
if relative_sample:
extra += " -relativeSample true -lowHigh %f %f" % (low, high)
print("ahogeCmd -e \"%s\" -exportMode \"%s\" -timeRange \"%s\"%s;" %
(alembic_path.replace("\\", "/"), export_mode, time_range, extra))
cmds.ahogeCmd(e=alembic_path,
exportMode=export_mode,
timeRange=time_range,
startEnd=(start, end),
relativeSample=relative_sample,
lowHigh=(low, high))
def export_alembic_options():
global export_alembic_window
if not export_alembic_window:
title = "Ahoge Export: Alembic"
options = []
options.append(Option("Path", OptionType.File, *export_alembic_path, {"fileFilter": "*.abc"}))
options.append(Option("Mode", OptionType.Option, *export_alembic_mode, {"options": [[0, "Default"], [1, "Unreal"], [2, "Marmoset"]]}))
options.append(Option("Time Range", OptionType.Option, *export_alembic_time_range, {"options": [[0, "Current Frame"], [1, "Time Slider"], [2, "Start/End"]]}))
options.append(Option("Start Frame", OptionType.Int, *export_alembic_start, {"min": -1000000, "max": 1000000}))
options.append(Option("End Frame", OptionType.Int, *export_alembic_end, {"min": -1000000, "max": 1000000}))
options.append(Option("Relative Sample", OptionType.Bool, *export_alembic_relative_sample))
options.append(Option("Low", OptionType.Float, *export_alembic_low, {"min": -1.0, "max": 0.0}))
options.append(Option("High", OptionType.Float, *export_alembic_high, {"min": 0.0, "max": 1.0}))
export_alembic_window = OptionsDialog(OptionsDialogType.Export, title, export_alembic, options, maya_main_window())
else:
export_alembic_window.activate()

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,103 @@
global proc AEahogeShapeTemplate(string $nodeName)
{
editorTemplate -beginScrollLayout;
editorTemplate -beginLayout "Seed" -collapse true;
editorTemplate -addControl "seed";
editorTemplate -endLayout;
editorTemplate -beginLayout "Color" -collapse false;
AEaddRampControl($nodeName + ".colorRamp");
editorTemplate -beginLayout "Mutant Color" -collapse true;
editorTemplate -l "Mutant Color" -addControl "mutantColor";
editorTemplate -l "Mutant Percent" -addControl "mutantPercent";
editorTemplate -l "Mutant Fuzziness" -addControl "mutantFuzziness";
editorTemplate -endLayout;
editorTemplate -beginLayout "Randomize Color" -collapse true;
editorTemplate -l "Randomize Color" -addControl "randomizeColor";
editorTemplate -l "Randomize Saturation" -addControl "randomizeSaturation";
editorTemplate -l "Randomize Value" -addControl "randomizeValue";
editorTemplate -endLayout;
editorTemplate -beginLayout "Absolute Length" -collapse true;
editorTemplate -l "Use Absolute Length" -addControl "useAbsoluteLength";
editorTemplate -l "Absolute Length" -addControl "absoluteLength";
editorTemplate -endLayout;
editorTemplate -endLayout;
editorTemplate -beginLayout "General" -collapse false;
editorTemplate -l "Segments" -addControl "numSegments";
editorTemplate -l "Curves" -addControl "numCurves";
editorTemplate -endLayout;
editorTemplate -beginLayout "Width" -collapse false;
editorTemplate -l "Width" -addControl "width";
AEaddRampControl($nodeName + ".widthRamp");
editorTemplate -endLayout;
editorTemplate -beginLayout "Noise" -collapse false;
editorTemplate -l "Random Placement" -addControl "randomPlacement";
editorTemplate -l "Random Placement Type" -addControl "randomPlacementType";
editorTemplate -l "Noise" -addControl "noise";
editorTemplate -l "Frequency" -addControl "frequency";
editorTemplate -l "Octaves" -addControl "octaves";
editorTemplate -l "Persistence" -addControl "persistence";
AEaddRampControl($nodeName + ".noiseRamp");
editorTemplate -beginLayout "Randomize Frequency" -collapse true;
editorTemplate -l "Enable Randomize Frequency" -addControl "enableRandomizeFrequency";
editorTemplate -l "Randomize Frequency Min" -addControl "randomizeFrequencyMin";
editorTemplate -l "Randomize Frequency Max" -addControl "randomizeFrequencyMax";
AEaddRampControl($nodeName + ".randomizeFrequencyDistribution");
editorTemplate -endLayout;
editorTemplate -beginLayout "Randomize Noise" -collapse true;
editorTemplate -l "Randomize Noise" -addControl "randomizeNoise";
AEaddRampControl($nodeName + ".randomizeNoiseDistribution");
editorTemplate -endLayout;
editorTemplate -endLayout;
editorTemplate -beginLayout "Cut" -collapse false;
editorTemplate -l "Cut" -addControl "cut";
editorTemplate -l "Compress Noise Frequency" -addControl "compressNoiseFrequency";
AEaddRampControl($nodeName + ".cutDistribution");
editorTemplate -endLayout;
editorTemplate -beginLayout "Spray" -collapse false;
editorTemplate -l "Fill" -addControl "fill";
editorTemplate -l "Shift" -addControl "shift";
editorTemplate -l "Spray Along Normal" -addControl "sprayAlongNormal";
editorTemplate -l "Spray" -addControl "spray";
AEaddRampControl($nodeName + ".sprayRamp");
AEaddRampControl($nodeName + ".sprayDistribution");
editorTemplate -endLayout;
editorTemplate -beginLayout "Multistrand" -collapse false;
editorTemplate -l "Multistrand" -addControl "multistrand";
editorTemplate -l "Multistrand Percent" -addControl "multistrandPercent";
editorTemplate -l "Multistrand Randomize" -addControl "multistrandRandomize";
editorTemplate -l "Multistrand Randomize Tip" -addControl "multistrandRandomizeTip";
editorTemplate -l "Multistrand Twist" -addControl "multistrandTwist";
editorTemplate -l "Multistrand Twist Randomize" -addControl "multistrandTwistRandomize";
editorTemplate -l "Multistrand Spray" -addControl "multistrandSpray";
editorTemplate -l "Multistrand Randomize Spray" -addControl "multistrandRandomizeSpray";
AEaddRampControl($nodeName + ".multistrandSprayRamp");
editorTemplate -endLayout;
editorTemplate -beginLayout "Arnold" -collapse true;
editorTemplate -l "Mode" -addControl "aiMode";
editorTemplate -l "Min Pixel Width" -addControl "aiMinPixelWidth";
editorTemplate -endLayout;
editorTemplate -beginLayout "Viewport" -collapse true;
editorTemplate -l "Display Mode" -addControl "displayMode";
editorTemplate -l "Preview Percent" -addControl "previewPercent";
editorTemplate -l "Preview Sides" -addControl "previewSides";
editorTemplate -endLayout;
AEsurfaceShapeTemplate $nodeName;
editorTemplate -addExtraControls;
editorTemplate -endScrollLayout;
}

View File

@@ -0,0 +1,32 @@
global proc AEnurbopusNodeTemplate(string $nodeName)
{
editorTemplate -beginScrollLayout;
editorTemplate -beginLayout "General" -collapse false;
editorTemplate -l "Up Vector" -addControl "upVector";
editorTemplate -l "Method" -addControl "method";
editorTemplate -l "Shape" -addControl "shape";
editorTemplate -l "U Segments" -addControl "uSegments";
editorTemplate -l "V Segments" -addControl "vSegments";
editorTemplate -l "Segments Power" -addControl "segmentsPower";
editorTemplate -l "Radius" -addControl "radius";
editorTemplate -l "Scale Y" -addControl "scaleY";
editorTemplate -l "Rotate" -addControl "rotate";
editorTemplate -l "twist" -addControl "twist";
AEaddRampControl($nodeName + ".ramp");
editorTemplate -endLayout;
editorTemplate -beginLayout "Orientation" -collapse false;
editorTemplate -l "Use Mesh Normal" -addControl "useMeshNormal";
editorTemplate -l "Orient Method" -addControl "orientMethod";
editorTemplate -l "Orient" -addControl "orient";
editorTemplate -l "Orient Point" -addControl "orientPoint";
editorTemplate -l "Orient Segment" -addControl "orientSegment";
editorTemplate -endLayout;
AEdependNodeTemplate $nodeName;
editorTemplate -addExtraControls;
editorTemplate -endScrollLayout;
}

View File

@@ -0,0 +1,484 @@
global proc ahogeTools()
{
if (`menu -exists ahogeToolsMenu`)
{
deleteUI ahogeToolsMenu;
}
else
{
menu -l "Ahoge"
-tearOff true
-p "MayaWindow" ahogeToolsMenu;
menuItem -l "Ahoge"
-c "python(\"import ahoge_ui;ahoge_ui.create_ahoge()\")"
-ann "Create an ahogeShape node with a random seed and connect the selected surfaces"
-i "ahogeShape.png"
-p ahogeToolsMenu;
menuItem -optionBox true
-c "python(\"import ahoge_ui;ahoge_ui.create_ahoge_options()\")"
-p ahogeToolsMenu;
menuItem -l "Connect"
-c "ahogeTools_connect"
-ann "Connect the selected nurbs surfaces to the selected ahogeShape nodes"
-i "ahoge_connect.png"
-p ahogeToolsMenu;
menuItem -l "Disconnect"
-c "ahogeTools_disconnect"
-ann "Disconnect the selected nurbs surfaces from the selected ahogeShape nodes"
-i "ahoge_disconnect.png"
-p ahogeToolsMenu;
menuItem -l "Duplicate"
-subMenu true
-ann "Duplicate ahogeShape nodes"
-i "ahoge_duplicate.png"
-p ahogeToolsMenu ahogeToolsMenu_duplicate_menu;
menuItem -l "Ahoge"
-c "ahogeTools_duplicateAhoge"
-ann "Duplicate the selected ahogeShape nodes and set random seeds"
-i "ahogeShape.png"
-p ahogeToolsMenu_duplicate_menu;
menuItem -l "Ahoge and Connect"
-c "ahogeTools_duplicateAhoge_connect"
-ann "Duplicate the selected ahogeShape nodes, connect the selected surfaces to them, and set random seeds"
-i "ahoge_connect.png"
-p ahogeToolsMenu_duplicate_menu;
menuItem -l "Extra"
-subMenu true
-ann "Extra nodes"
-i "ahoge_extra.png"
-p ahogeToolsMenu ahogeToolsMenu_extra_menu;
menuItem -l "Nurbopus"
-c "python(\"import ahoge_ui;ahoge_ui.create_nurbopus()\")"
-ann "Select curves and optionally a mesh to create Nurbopus"
-i "out_nurbopusNode.png"
-p ahogeToolsMenu_extra_menu;
menuItem -optionBox true
-c "python(\"import ahoge_ui;ahoge_ui.create_nurbopus_options()\")"
-p ahogeToolsMenu_extra_menu;
menuItem -l "Connect"
-c "ahogeTools_nurbopus_connect"
-ann "Select surfaces that have Nurbopus and curves to connect the selected curves to the Nurbopus node"
-i "ahoge_connect.png"
-p ahogeToolsMenu_extra_menu;
menuItem -l "Detach"
-c "ahogeTools_nurbopus_detach"
-ann "Disconnect the selected surfaces from their Nurbopus node, duplicate the Nurbopus node, and connect the duplicated Nurbopus node to the curves of the selected surfaces"
-i "ahoge_detach.png"
-p ahogeToolsMenu_extra_menu;
menuItem -l "Miscellaneous"
-subMenu true
-ann "Miscellaneous Tools"
-i "ahoge_misc.png"
-p ahogeToolsMenu ahogeToolsMenu_misc_menu;
menuItem -l "Fix Surfaces"
-c "ahogeTools_fixSurfaces"
-ann "Select Nurbs Surfaces and a Mesh to fix the Surfaces"
-i "ahoge_fix.png"
-p ahogeToolsMenu_misc_menu;
menuItem -l "Select Connected Surfaces"
-c "ahogeTools_selectConnectedSurfaces"
-ann "Select Nurbs Surfaces that are connected to the selected Ahoge Shapes"
-i "aselect.png"
-p ahogeToolsMenu_misc_menu;
menuItem -l "Disconnect Connected Surfaces"
-c "ahogeTools_disconnectConnectedSurfaces"
-ann "Disconnect Nurbs Surfaces that are connected to the selected Ahoge Shapes"
-i "ahoge_disconnect.png"
-p ahogeToolsMenu_misc_menu;
menuItem -l "Select"
-subMenu true
-ann "Select ahogeShape nodes"
-pmc "ahogeTools_select_pmc"
-i "aselect.png"
-p ahogeToolsMenu ahogeToolsMenu_select_menu;
menuItem -l "Convert"
-subMenu true
-ann "Convert ahogeShape nodes"
-i "ahoge_convert.png"
-p ahogeToolsMenu ahogeToolsMenu_convert_menu;
menuItem -l "Convert to Curves"
-c "ahogeTools_convertToCurves"
-ann "Convert the selected ahogeShape nodes to nurbs curves"
-i "curveEP.png"
-p ahogeToolsMenu_convert_menu;
menuItem -l "Export"
-subMenu true
-ann "Export ahogeShape nodes"
-i "ahoge_export.png"
-p ahogeToolsMenu ahogeToolsMenu_export_menu;
menuItem -l "Export Alembic"
-c "python(\"import ahoge_ui;ahoge_ui.export_alembic_options()\")"
-ann "Export ahogeShape nodes to Alembic"
-i "ahoge_abc.png"
-p ahogeToolsMenu_export_menu;
menuItem -d true -p ahogeToolsMenu;
menuItem -l "Support"
-c "ahogeTools_support"
-ann "Get support and updates"
-i "ahoge_info.png"
-p ahogeToolsMenu;
}
}
global proc ahogeTools_disconnect_attr( string $left, string $right )
{
string $connections[] = `listConnections -p true $left`;
string $connection;
for ($connection in $connections)
{
string $ending = `match "\[[0-9]+\]$" $connection`;
string $short = `substring $connection 1 (size($connection) - size($ending))`;
if ( $short == $right )
{
disconnectAttr $left $connection;
}
}
}
global proc ahogeTools_connect()
{
string $surfaces[] = `ls -sl -dag -type "nurbsSurface"`;
string $ahogeShapes[] = `ls -sl -dag -type "ahogeShape"`;
string $ahogeShape;
for ($ahogeShape in $ahogeShapes)
{
string $inputSurfaces[] = `listConnections -p true ($ahogeShape + ".inputSurfaces")`;
string $inputSurfacesObj[] = `listConnections -p false ($ahogeShape + ".inputSurfaces")`;
$inputSurfacesObj = `ls -dag -type "nurbsSurface" $inputSurfacesObj`;
string $connect;
for ($connect in $inputSurfaces)
{
ahogeTools_disconnect_attr $connect ($ahogeShape + ".inputSurfaces");
}
string $surfacesToAdd[] = {};
string $surface;
for ($surface in $surfaces)
{
if (!stringArrayContains($surface, $inputSurfacesObj))
{
$surfacesToAdd[size($surfacesToAdd)] = $surface;
}
}
string $diffSurfaces[] = stringArrayCatenate($inputSurfacesObj, $surfacesToAdd);
int $i = 0;
for (; $i < size($diffSurfaces); $i++ )
{
connectAttr ($diffSurfaces[$i] + ".worldSpace[0]") ($ahogeShape + ".inputSurfaces[" + $i + "]");
}
}
}
global proc ahogeTools_disconnect()
{
string $surfaces[] = `ls -sl -dag -type "nurbsSurface"`;
string $ahogeShapes[] = `ls -sl -dag -type "ahogeShape"`;
string $ahogeShape;
for ($ahogeShape in $ahogeShapes)
{
string $inputSurfaces[] = `listConnections -p true ($ahogeShape + ".inputSurfaces")`;
string $inputSurfacesObj[] = `listConnections -p false ($ahogeShape + ".inputSurfaces")`;
$inputSurfacesObj = `ls -dag -type "nurbsSurface" $inputSurfacesObj`;
string $connect;
for ($connect in $inputSurfaces)
{
ahogeTools_disconnect_attr $connect ($ahogeShape + ".inputSurfaces");
}
string $diffSurfaces[] = stringArrayRemove($surfaces, $inputSurfacesObj);
int $i = 0;
for (; $i < size($diffSurfaces); $i++ )
{
connectAttr ($diffSurfaces[$i] + ".worldSpace[0]") ($ahogeShape + ".inputSurfaces[" + $i + "]");
}
}
}
global proc ahogeTools_duplicateAhoge()
{
string $ahoges[] = `ls -dag -sl -l -type ahogeShape`;
string $ahoge;
for ($ahoge in $ahoges)
{
string $dup[] = `duplicate -ic $ahoge`;
setAttr ($dup[0] + ".seed") (int(rand(100000)));
}
}
global proc ahogeTools_duplicateAhoge_connect()
{
string $ahoges[] = `ls -dag -sl -l -type ahogeShape`;
string $surfaces[] = `ls -dag -sl -l -type nurbsSurface`;
if (size($ahoges) < 1) error "you haven't selected any ahogeShapes";
if (size($surfaces) < 1) error "you haven't selected any surfaces";
string $ahoge;
for ($ahoge in $ahoges)
{
string $dup[] = `duplicate $ahoge`;
string $multiInstances[] = `listAttr ($dup[0] + ".inputSurfaces[*]")`;
string $multiInstance;
for ($multiInstance in $multiInstances)
{
removeMultiInstance -b true ($dup[0] + "." + $multiInstance);
}
int $i = 0;
for (; $i < size($surfaces); $i++)
{
connectAttr -f ($surfaces[$i] + ".worldSpace[0]") ($dup[0] + ".inputSurfaces[" + $i + "]");
}
setAttr ($dup[0] + ".seed") (int(rand(100000)));
}
}
global proc ahogeTools_select_pmc()
{
menu -e -dai ahogeToolsMenu_select_menu;
string $ahogeShapes[] = `ls -l -type ahogeShape`;
string $ahogeShapesSelected[] = `ls -sl -dag -l -type ahogeShape`;
string $node;
for ($node in $ahogeShapes)
{
string $name[] = `listRelatives -parent $node`;
menuItem -cb (stringArrayContains($node, $ahogeShapesSelected)) -l $name[0] -c ("select " + $node) -p ahogeToolsMenu_select_menu;
}
if (!size($ahogeShapes)) menuItem -l "Nothing" -en false -p ahogeToolsMenu_select_menu;
}
global proc ahogeTools_convertToCurves()
{
string $ahogeShape[] = `ls -l -sl -dag -type "ahogeShape"`;
string $node;
for ($node in $ahogeShape)
{
int $num = `getAttr ($node + ".numSegments")` + 1;
float $cvs[] = `getAttr ($node + ".outputPoints")`;
string $parent[] = `listRelatives -f -parent $node`;
float $m[] = `xform -q -ws -m $parent[0]`;
int $numCurves = size($cvs) / $num / 3;
int $i = 0;
for (; $i < $numCurves; $i++)
{
string $curve = "curve -d 3";
int $j = 0;
for (; $j < $num; $j++)
{
vector $p = << $cvs[$i*$num*3+$j*3], $cvs[$i*$num*3+$j*3 + 1], $cvs[$i*$num*3+$j*3 + 2] >>;
$p = pointMatrixMult($p, $m);
$p += <<$m[12], $m[13], $m[14]>>;
$curve += " -p " + ($p.x) + " " + ($p.y) + " " + ($p.z);
}
eval $curve;
}
}
}
global proc ahogeTools_support()
{
python("import webbrowser;webbrowser.open('https://boosty.to/ahoge')");
}
// Misc
global proc float ahoge_distance(vector $v1, vector $v2)
{
return sqrt(pow(($v1.x) - ($v2.x), 2) + pow(($v1.y) - ($v2.y), 2) + pow(($v1.z) - ($v2.z), 2));
}
global proc ahogeTools_fixSurfaces()
{
string $surfaces[] = `ls -dag -sl -l -type nurbsSurface`;
string $meshes[] = `ls -dag -sl -l -type mesh`;
if (!size($surfaces)) error "No nurbsSurfaces selected";
if (size($meshes) != 1) error "Select a mesh";
string $surface;
for ($surface in $surfaces)
{
// reverse direction
if ((`getAttr ($surface + ".fu")` == 0) &&
((`getAttr ($surface + ".fv")` == 1) ||
(`getAttr ($surface + ".fv")` == 2)))
{
reverseSurface -d 3 -ch 0 -rpo 1 $surface;
reverseSurface -d 0 -ch 0 -rpo 1 $surface;
}
vector $first_point = << 0, 0, 0 >>;
vector $second_point = << 0, 0, 0 >>;
int $i = 0;
for (; $i < 4; $i++)
{
$first_point += `pointOnSurface -top true -u (float($i) / 4) -v 0.0 -position $surface`;
$second_point += `pointOnSurface -top true -u (float($i) / 4) -v 1.0 -position $surface`;
}
$first_point = $first_point / 4;
$second_point = $second_point / 4;
// check for inverted normals first
vector $norm = `pointOnSurface -u 0.0 -v 0.0 -nn $surface`;
vector $origin = `pointOnSurface -u 0.0 -v 0.0 -position $surface`;
if (dot($norm, $first_point - $origin) > 0)
{
reverseSurface -d 0 -ch 0 -rpo 1 $surface;
}
//print($first_point.x + " " + $first_point.y + " " + $first_point.z + "\n");
//print($second_point.x + " " + $second_point.y + " " + $second_point.z + "\n");
vector $first_point_surface = `ahogeCmd -m $meshes[0] -cp ($first_point.x) ($first_point.y) ($first_point.z)`;
vector $second_point_surface = `ahogeCmd -m $meshes[0] -cp ($second_point.x) ($second_point.y) ($second_point.z)`;
float $first_point_distance = ahoge_distance($first_point, $first_point_surface);
float $second_point_distance = ahoge_distance($second_point, $second_point_surface);
if ($first_point_distance < $second_point_distance) // needs to reverse V then
{
reverseSurface -d 1 -ch 0 -rpo 1 $surface;
reverseSurface -d 0 -ch 0 -rpo 1 $surface;
}
}
}
global proc ahogeTools_selectConnectedSurfaces()
{
string $ahogeShapes[] = `ls -sl -dag -type "ahogeShape"`;
string $result[] = {};
string $ahogeShape;
for ($ahogeShape in $ahogeShapes)
{
string $inputSurfacesObj[] = `listConnections -p false ($ahogeShape + ".inputSurfaces")`;
$inputSurfacesObj = `ls -dag -type "nurbsSurface" $inputSurfacesObj`;
string $surface;
for ($surface in $inputSurfacesObj)
{
$result[size($result)] = $surface;
}
}
select $result;
}
global proc ahogeTools_disconnectConnectedSurfaces()
{
string $ahogeShapes[] = `ls -sl -dag -type "ahogeShape"`;
string $ahogeShape;
for ($ahogeShape in $ahogeShapes)
{
string $inputSurfaces[] = `listConnections -p true ($ahogeShape + ".inputSurfaces")`;
string $connect;
for ($connect in $inputSurfaces)
{
ahogeTools_disconnect_attr $connect ($ahogeShape + ".inputSurfaces");
}
}
}
global proc ahogeTools_nurbopus_connect()
{
string $surfaces[] = `ls -sl -dag -type "nurbsSurface"`;
if (size($surfaces) == 0) error "No nurbsSurface selected";
string $history[] = `listHistory $surfaces`;
string $nurbopuses[] = `ls -type "nurbopusNode" $history`;
string $curves[] = `ls -sl -dag -type "nurbsCurve"`;
if (size($nurbopuses) == 0) error "No nurbopusNode selected";
if (size($curves) == 0) error "No nurbsCurve selected";
string $nurbopus;
for ($nurbopus in $nurbopuses)
{
int $size = `getAttr -size ($nurbopus + ".inputCurves")`;
int $i = 0;
for (; $i < size($curves); $i++)
{
connectAttr ($curves[$i] + ".worldSpace[0]") ($nurbopus + ".inputCurves[" + ($size + $i) + "]");
string $surface = `createNode "nurbsSurface"`;
connectAttr ($nurbopus + ".outputSurfaces[" + ($size + $i) + "]") ($surface + ".create");
hyperShade -assign "initialShadingGroup" $surface;
}
}
}
global proc int ahogeTools_extract(string $str)
{
string $str_idx = `match "\[[0-9]+\]$" $str`;
string $array[];
tokenize $str_idx "[]" $array;
return int($array[0]);
}
global proc ahogeTools_nurbopus_detach()
{
string $surfaces[] = `ls -sl -dag -type "nurbsSurface"`;
if (size($surfaces) == 0) error "No nurbsSurface selected";
string $history[] = `listHistory $surfaces`;
string $nurbopuses[] = `ls -type "nurbopusNode" $history`;
if (size($nurbopuses) == 0) error "No nurbopusNode selected";
if (size($nurbopuses) != 1) error "Detach only works with a single nurbopusNode";
string $duplicate[] = `duplicate $nurbopuses[0]`;
int $connectionIndices[] = {};
int $i = 0;
for (; $i < size($surfaces); $i++)
{
string $surfaceCreate[] = `listConnections -c true -p true ($surfaces[$i] + ".create")`;
$connectionIndices[size($connectionIndices)] = ahogeTools_extract($surfaceCreate[1]);
}
string $output_surfaces[] = `listConnections -p false ($nurbopuses[0] + ".outputSurfaces")`;
$output_surfaces = `ls -dag -type "nurbsSurface" $output_surfaces`;
string $inputCurves[] = `listConnections -p true ($nurbopuses[0] + ".inputCurves")`;
string $inputCurvesObj[] = `listConnections -p false ($nurbopuses[0] + ".inputCurves")`;
$inputCurvesObj = `ls -dag -type "nurbsCurve" $inputCurvesObj`;
string $connect;
for ($connect in $inputCurves)
{
ahogeTools_disconnect_attr $connect ($nurbopuses[0] + ".inputCurves");
}
int $first_count = 0;
int $second_count = 0;
for ($i = 0; $i < size($inputCurvesObj); $i++)
{
if (intArrayContains($i, $connectionIndices))
{
connectAttr ($inputCurvesObj[$i] + ".worldSpace[0]") ($duplicate[0] + ".inputCurves[" + $first_count + "]");
connectAttr -f ($duplicate[0] + ".outputSurfaces[" + $first_count + "]") ($output_surfaces[$i] + ".create");
$first_count++;
}
else
{
connectAttr ($inputCurvesObj[$i] + ".worldSpace[0]") ($nurbopuses[0] + ".inputCurves[" + $second_count + "]");
connectAttr -f ($nurbopuses[0] + ".outputSurfaces[" + $second_count + "]") ($output_surfaces[$i] + ".create");
$second_count++;
}
}
}

View File

@@ -0,0 +1,489 @@
import maya.cmds as cmds
if cmds.about(version=True) == "2025":
from PySide6 import QtWidgets, QtGui
import shiboken6 as shiboken
else:
from PySide2 import QtWidgets, QtGui
import shiboken2 as shiboken
import maya.OpenMayaUI as omui
from enum import Enum
import random
import os
import pathlib
from datetime import datetime
import time
def get_scaling_ratio():
screen = QtGui.QGuiApplication.primaryScreen()
return screen.logicalDotsPerInch() / 96.0
scaling_ratio = get_scaling_ratio()
def maya_main_window():
main_window_pointer = omui.MQtUtil.mainWindow()
return shiboken.wrapInstance(int(main_window_pointer), QtWidgets.QWidget)
class OptionType(Enum):
Unknown = 1
Bool = 2
Int = 3
Float = 4
Option = 5
File = 6
class Option:
option_type = OptionType.Unknown
option_name = None
default = None
setting = None
widget = None
def __init__(self, option_name, option_type, default, setting, meta=None):
self.option_name = option_name
self.option_type = option_type
self.default = default
self.setting = setting
self.meta = meta
def make_widget(self, form_layout):
if self.option_type == OptionType.Bool:
self.widget = QtWidgets.QCheckBox()
self.widget.setChecked(self.default)
form_layout.addRow(self.option_name + ":", self.widget)
elif self.option_type == OptionType.Int:
self.widget = QtWidgets.QSpinBox()
self.widget.setFixedWidth(70 * scaling_ratio)
self.widget.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
if self.meta:
if "min" in self.meta:
self.widget.setMinimum(self.meta["min"])
if "max" in self.meta:
self.widget.setMaximum(self.meta["max"])
self.widget.setValue(self.default)
form_layout.addRow(self.option_name + ":", self.widget)
elif self.option_type == OptionType.Float:
self.widget = QtWidgets.QDoubleSpinBox()
self.widget.setDecimals(4)
self.widget.setSingleStep(0.01)
self.widget.setFixedWidth(70 * scaling_ratio)
self.widget.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
if self.meta:
if "min" in self.meta:
self.widget.setMinimum(self.meta["min"])
if "max" in self.meta:
self.widget.setMaximum(self.meta["max"])
self.widget.setValue(self.default)
form_layout.addRow(self.option_name + ":", self.widget)
elif self.option_type == OptionType.Option:
self.widget = QtWidgets.QComboBox()
if self.meta:
if "options" in self.meta:
for option in self.meta["options"]:
self.widget.addItem(option[1], option[0])
form_layout.addRow(self.option_name + ":", self.widget)
index = self.widget.findData(self.default)
self.widget.setCurrentIndex(index)
elif self.option_type == OptionType.File:
self.widget = QtWidgets.QLineEdit()
widget_layout = QtWidgets.QHBoxLayout()
widget_layout.setContentsMargins(0, 0, 0, 0)
browse_button = QtWidgets.QPushButton("Browse")
def browse_action():
path = self.widget.text()
file_filter = ""
if self.meta:
if "fileFilter" in self.meta:
file_filter = self.meta["fileFilter"]
result = cmds.fileDialog2(dir=path, fileFilter=file_filter, dialogStyle=2)
if result:
self.widget.setText(result[0])
browse_button.clicked.connect(browse_action)
widget_layout.addWidget(self.widget)
widget_layout.addWidget(browse_button)
form_layout.addRow(self.option_name + ":", widget_layout)
self.widget.setText(self.default)
def load(self):
if not self.widget:
return
if self.option_type == OptionType.Bool:
if cmds.optionVar(exists=self.setting):
value = bool(cmds.optionVar(q=self.setting))
self.widget.setChecked(value)
elif self.option_type == OptionType.Int:
if cmds.optionVar(exists=self.setting):
value = cmds.optionVar(q=self.setting)
self.widget.setValue(value)
elif self.option_type == OptionType.Float:
if cmds.optionVar(exists=self.setting):
value = cmds.optionVar(q=self.setting)
self.widget.setValue(value)
elif self.option_type == OptionType.Option:
if cmds.optionVar(exists=self.setting):
value = cmds.optionVar(q=self.setting)
index = self.widget.findData(value)
self.widget.setCurrentIndex(index)
elif self.option_type == OptionType.File:
if cmds.optionVar(exists=self.setting):
value = cmds.optionVar(q=self.setting)
self.widget.setText(value)
def save(self):
if not self.widget:
return
if self.option_type == OptionType.Bool:
if self.widget.isChecked():
cmds.optionVar(iv=(self.setting, 1))
else:
cmds.optionVar(iv=(self.setting, 0))
elif self.option_type == OptionType.Int:
cmds.optionVar(iv=(self.setting, self.widget.value()))
elif self.option_type == OptionType.Float:
cmds.optionVar(fv=(self.setting, self.widget.value()))
elif self.option_type == OptionType.Option:
cmds.optionVar(iv=(self.setting, self.widget.currentData()))
elif self.option_type == OptionType.File:
cmds.optionVar(sv=(self.setting, self.widget.text()))
def reset(self):
if not self.widget:
return
if self.option_type == OptionType.Bool:
self.widget.setChecked(self.default)
if self.default:
cmds.optionVar(iv=(self.setting, 1))
else:
cmds.optionVar(iv=(self.setting, 0))
elif self.option_type == OptionType.Int:
self.widget.setValue(self.default)
cmds.optionVar(iv=(self.setting, self.default))
elif self.option_type == OptionType.Float:
self.widget.setValue(self.default)
cmds.optionVar(fv=(self.setting, self.default))
elif self.option_type == OptionType.Option:
index = self.widget.findData(self.default)
self.widget.setCurrentIndex(index)
cmds.optionVar(iv=(self.setting, self.default))
elif self.option_type == OptionType.File:
self.widget.setText(self.default)
cmds.optionVar(sv=(self.setting, self.default))
class OptionsDialogType(Enum):
Create = 1
Export = 2
class OptionsDialog(QtWidgets.QDialog):
def __init__(self, options_dialog_type, title, command, options, parent=None):
super(OptionsDialog, self).__init__(parent)
self.setWindowTitle(title)
self.options_dialog_type = options_dialog_type
self.command = command
self.options = options
layout = QtWidgets.QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
menu_bar = QtWidgets.QMenuBar()
edit_menu = menu_bar.addMenu("Edit")
edit_menu.addAction("Save Settings", self.save)
edit_menu.addAction("Reset Settings", self.reset)
if self.options_dialog_type == OptionsDialogType.Export:
edit_menu.addSeparator()
edit_menu.addAction("Clear Log", self.clear_log)
layout.addWidget(menu_bar)
form_layout = QtWidgets.QFormLayout()
form_layout_margins = 8 * scaling_ratio
form_layout.setContentsMargins(
form_layout_margins, form_layout_margins, form_layout_margins, form_layout_margins)
for option in self.options:
option.make_widget(form_layout)
layout.addLayout(form_layout)
if options_dialog_type == OptionsDialogType.Create:
layout.addStretch()
buttons_layout = QtWidgets.QHBoxLayout()
layout.addLayout(buttons_layout)
buttons_layout_margins = 4 * scaling_ratio
buttons_layout.setContentsMargins(
buttons_layout_margins, buttons_layout_margins, buttons_layout_margins, buttons_layout_margins)
buttons_layout.setSpacing(4)
if options_dialog_type == OptionsDialogType.Create:
create_button = QtWidgets.QPushButton("Create")
apply_button = QtWidgets.QPushButton("Apply")
close_button = QtWidgets.QPushButton("Close")
create_button.clicked.connect(self.create)
apply_button.clicked.connect(self.apply)
close_button.clicked.connect(self.close)
buttons_layout.addWidget(create_button)
buttons_layout.addWidget(apply_button)
buttons_layout.addWidget(close_button)
elif options_dialog_type == OptionsDialogType.Export:
self.log = QtWidgets.QTextEdit()
#self.log.setFixedHeight(80)
self.log.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
self.log.setReadOnly(True)
form_layout.addRow("Log:", self.log)
export_button = QtWidgets.QPushButton("Export")
close_button = QtWidgets.QPushButton("Close")
export_button.clicked.connect(self.apply)
close_button.clicked.connect(self.close)
buttons_layout.addStretch()
buttons_layout.addWidget(export_button)
buttons_layout.addWidget(close_button)
self.load()
self.show()
def load(self):
for option in self.options:
option.load()
def save(self):
for option in self.options:
option.save()
def reset(self):
for option in self.options:
option.reset()
def create(self):
self.save()
self.command()
self.close()
def apply(self):
self.save()
if self.options_dialog_type == OptionsDialogType.Export:
start_time = time.time()
start_date = datetime.now()
self.log.moveCursor(QtGui.QTextCursor.End)
self.log.append("<font color=grey>Export started</font> " + str(start_date))
try:
self.command()
end_time = time.time()
end_date = datetime.now()
self.log.moveCursor(QtGui.QTextCursor.End)
self.log.append("<font color=grey>Export ended</font> " + str(end_date))
self.log.append("<font color=grey>Export took</font> %.4f <font color=grey>seconds</font>" % (end_time - start_time))
self.log.append("<font color=green>Done</font>")
except Exception as e:
self.log.moveCursor(QtGui.QTextCursor.End)
self.log.append("<font color=orange>%s</font>" % e)
self.log.append("<font color=red>Failure</font>")
else:
self.command()
def activate(self):
self.load()
self.show()
self.activateWindow()
def clear_log(self):
self.log.clear()
def get_value(setting):
if cmds.optionVar(exists=setting[1]):
return cmds.optionVar(q=setting[1])
return setting[0]
create_ahoge_window = None
create_ahoge_randomize_seed = [True, "ahoge_randomize_seed"]
create_ahoge_swap_uv = [True, "ahoge_randomize_swap_uv"]
create_ahoge_segments = [16, "ahoge_segments"]
create_ahoge_number_of_curves = [10, "ahoge_number_of_curves"]
create_ahoge_width = [0.01, "ahoge_width"]
def create_ahoge():
cmds.undoInfo(chunkName="create_ahoge", openChunk=True)
try:
randomize_seed = get_value(create_ahoge_randomize_seed)
swap_uv = get_value(create_ahoge_swap_uv)
segments = get_value(create_ahoge_segments)
number_of_curves = get_value(create_ahoge_number_of_curves)
width = get_value(create_ahoge_width)
surfaces = cmds.ls(sl=True, dag=True, type="nurbsSurface")
ahoge_shape = cmds.createNode("ahogeShape")
if randomize_seed:
cmds.setAttr(ahoge_shape + ".seed", random.randint(0, 10000))
cmds.setAttr(ahoge_shape + ".numSegments", segments)
cmds.setAttr(ahoge_shape + ".numCurves", number_of_curves)
cmds.setAttr(ahoge_shape + ".width", width)
for index, surface in enumerate(surfaces):
if swap_uv and cmds.getAttr(surface + ".fu") == 0 and cmds.getAttr(surface + ".fv") == 2:
cmds.warning(surface + " swapping UV")
cmds.reverseSurface(surface, d=3, ch=1, rpo=1)
cmds.reverseSurface(surface, d=0, ch=1, rpo=1)
cmds.connectAttr(surface + ".worldSpace[0]", ahoge_shape + ".inputSurfaces[" + str(index) + "]")
finally:
cmds.undoInfo(closeChunk=True)
def create_ahoge_options():
global create_ahoge_window
if not create_ahoge_window:
title = "Create Ahoge Options"
options = []
options.append(Option("Randomize Seed", OptionType.Bool, *create_ahoge_randomize_seed))
options.append(Option("Swap UV", OptionType.Bool, *create_ahoge_swap_uv))
options.append(Option("Segments", OptionType.Int, *create_ahoge_segments, {"min": 1, "max": 1000000}))
options.append(Option("Number of Curves", OptionType.Int, *create_ahoge_number_of_curves, {"min": 1, "max": 1000000}))
options.append(Option("Width", OptionType.Float, *create_ahoge_width, {"min": 0.0001, "max": 1000000.0}))
create_ahoge_window = OptionsDialog(OptionsDialogType.Create, title, create_ahoge, options, maya_main_window())
else:
create_ahoge_window.activate()
create_nurbopus_window = None
create_nurbopus_method = [1, "ahoge_nurbopus_method"]
create_nurbopus_shape = [0, "ahoge_nurbopus_shape"]
create_nurbopus_useg = [4, "ahoge_nurbopus_useg"]
create_nurbopus_vseg = [8, "ahoge_nurbopus_vseg"]
def create_nurbopus():
cmds.undoInfo(chunkName="create_nurbopus", openChunk=True)
try:
method = get_value(create_nurbopus_method)
shape = get_value(create_nurbopus_shape)
useg = get_value(create_nurbopus_useg)
vseg = get_value(create_nurbopus_vseg)
curves = cmds.ls(sl=True, dag=True, type="nurbsCurve")
if not curves:
cmds.error("No curves selected")
meshes = cmds.ls(sl=True, dag=True, type="mesh")
nurbopus = cmds.createNode("nurbopusNode")
cmds.setAttr(nurbopus + ".method", method)
cmds.setAttr(nurbopus + ".shape", shape)
cmds.setAttr(nurbopus + ".uSegments", useg)
cmds.setAttr(nurbopus + ".vSegments", vseg)
for index, curve in enumerate(curves):
cmds.connectAttr(curve + ".worldSpace[0]", nurbopus + ".inputCurves[" + str(index) + "]")
surface = cmds.createNode("nurbsSurface")
cmds.connectAttr(nurbopus + ".outputSurfaces[" + str(index) + "]", surface + ".create")
cmds.hyperShade(surface, assign="initialShadingGroup")
if meshes:
cmds.connectAttr(meshes[0] + ".worldMesh[0]", nurbopus + ".inputMesh")
cmds.select(nurbopus)
finally:
cmds.undoInfo(closeChunk=True)
def create_nurbopus_options():
global create_nurbopus_window
if not create_nurbopus_window:
title = "Create Nurbopus Options"
options = []
options.append(Option("Method", OptionType.Option, *create_nurbopus_method, {"options": [[0, "Up Vector"], [1, "Untwist"]]}))
options.append(Option("Shape", OptionType.Option, *create_nurbopus_shape, {"options": [[0, "circle"], [1, "line"]]}))
options.append(Option("U Segments", OptionType.Int, *create_nurbopus_useg, {"min": 1, "max": 1000000}))
options.append(Option("V Segments", OptionType.Int, *create_nurbopus_vseg, {"min": 1, "max": 1000000}))
create_nurbopus_window = OptionsDialog(OptionsDialogType.Create, title, create_nurbopus, options, maya_main_window())
else:
create_nurbopus_window.activate()
export_alembic_window = None
abc_path = pathlib.Path(os.environ["MAYA_APP_DIR"])
abc_path = abc_path / "projects" / "default" / "data" / "test.abc"
export_alembic_path = [str(abc_path), "ahoge_export_alembic_path"]
export_alembic_mode = [0, "ahoge_export_alembic_mode"]
export_alembic_time_range = [0, "ahoge_export_alembic_time_range"]
export_alembic_start = [1, "ahoge_export_alembic_start"]
export_alembic_end = [24, "ahoge_export_alembic_end"]
export_alembic_relative_sample = [False, "ahoge_export_alembic_relative_sample"]
export_alembic_low = [-0.2, "ahoge_export_alembic_low"]
export_alembic_high = [0.2, "ahoge_export_alembic_high"]
def export_alembic():
alembic_mode = get_value(export_alembic_mode)
alembic_time_range = get_value(export_alembic_time_range)
alembic_path = get_value(export_alembic_path)
start = get_value(export_alembic_start)
end = get_value(export_alembic_end)
relative_sample = get_value(export_alembic_relative_sample)
low = get_value(export_alembic_low)
high = get_value(export_alembic_high)
export_mode="default"
if alembic_mode == 1:
export_mode = "unreal"
elif alembic_mode == 2:
export_mode = "marmoset"
extra = ""
time_range = "current_frame"
if alembic_time_range == 1:
time_range = "time_slider"
elif alembic_time_range == 2:
time_range = "start_end"
extra += " -startEnd %d %d" % (start, end)
if relative_sample:
extra += " -relativeSample true -lowHigh %f %f" % (low, high)
print("ahogeCmd -e \"%s\" -exportMode \"%s\" -timeRange \"%s\"%s;" %
(alembic_path.replace("\\", "/"), export_mode, time_range, extra))
cmds.ahogeCmd(e=alembic_path,
exportMode=export_mode,
timeRange=time_range,
startEnd=(start, end),
relativeSample=relative_sample,
lowHigh=(low, high))
def export_alembic_options():
global export_alembic_window
if not export_alembic_window:
title = "Ahoge Export: Alembic"
options = []
options.append(Option("Path", OptionType.File, *export_alembic_path, {"fileFilter": "*.abc"}))
options.append(Option("Mode", OptionType.Option, *export_alembic_mode, {"options": [[0, "Default"], [1, "Unreal"], [2, "Marmoset"]]}))
options.append(Option("Time Range", OptionType.Option, *export_alembic_time_range, {"options": [[0, "Current Frame"], [1, "Time Slider"], [2, "Start/End"]]}))
options.append(Option("Start Frame", OptionType.Int, *export_alembic_start, {"min": -1000000, "max": 1000000}))
options.append(Option("End Frame", OptionType.Int, *export_alembic_end, {"min": -1000000, "max": 1000000}))
options.append(Option("Relative Sample", OptionType.Bool, *export_alembic_relative_sample))
options.append(Option("Low", OptionType.Float, *export_alembic_low, {"min": -1.0, "max": 0.0}))
options.append(Option("High", OptionType.Float, *export_alembic_high, {"min": 0.0, "max": 1.0}))
export_alembic_window = OptionsDialog(OptionsDialogType.Export, title, export_alembic, options, maya_main_window())
else:
export_alembic_window.activate()

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,103 @@
global proc AEahogeShapeTemplate(string $nodeName)
{
editorTemplate -beginScrollLayout;
editorTemplate -beginLayout "Seed" -collapse true;
editorTemplate -addControl "seed";
editorTemplate -endLayout;
editorTemplate -beginLayout "Color" -collapse false;
AEaddRampControl($nodeName + ".colorRamp");
editorTemplate -beginLayout "Mutant Color" -collapse true;
editorTemplate -l "Mutant Color" -addControl "mutantColor";
editorTemplate -l "Mutant Percent" -addControl "mutantPercent";
editorTemplate -l "Mutant Fuzziness" -addControl "mutantFuzziness";
editorTemplate -endLayout;
editorTemplate -beginLayout "Randomize Color" -collapse true;
editorTemplate -l "Randomize Color" -addControl "randomizeColor";
editorTemplate -l "Randomize Saturation" -addControl "randomizeSaturation";
editorTemplate -l "Randomize Value" -addControl "randomizeValue";
editorTemplate -endLayout;
editorTemplate -beginLayout "Absolute Length" -collapse true;
editorTemplate -l "Use Absolute Length" -addControl "useAbsoluteLength";
editorTemplate -l "Absolute Length" -addControl "absoluteLength";
editorTemplate -endLayout;
editorTemplate -endLayout;
editorTemplate -beginLayout "General" -collapse false;
editorTemplate -l "Segments" -addControl "numSegments";
editorTemplate -l "Curves" -addControl "numCurves";
editorTemplate -endLayout;
editorTemplate -beginLayout "Width" -collapse false;
editorTemplate -l "Width" -addControl "width";
AEaddRampControl($nodeName + ".widthRamp");
editorTemplate -endLayout;
editorTemplate -beginLayout "Noise" -collapse false;
editorTemplate -l "Random Placement" -addControl "randomPlacement";
editorTemplate -l "Random Placement Type" -addControl "randomPlacementType";
editorTemplate -l "Noise" -addControl "noise";
editorTemplate -l "Frequency" -addControl "frequency";
editorTemplate -l "Octaves" -addControl "octaves";
editorTemplate -l "Persistence" -addControl "persistence";
AEaddRampControl($nodeName + ".noiseRamp");
editorTemplate -beginLayout "Randomize Frequency" -collapse true;
editorTemplate -l "Enable Randomize Frequency" -addControl "enableRandomizeFrequency";
editorTemplate -l "Randomize Frequency Min" -addControl "randomizeFrequencyMin";
editorTemplate -l "Randomize Frequency Max" -addControl "randomizeFrequencyMax";
AEaddRampControl($nodeName + ".randomizeFrequencyDistribution");
editorTemplate -endLayout;
editorTemplate -beginLayout "Randomize Noise" -collapse true;
editorTemplate -l "Randomize Noise" -addControl "randomizeNoise";
AEaddRampControl($nodeName + ".randomizeNoiseDistribution");
editorTemplate -endLayout;
editorTemplate -endLayout;
editorTemplate -beginLayout "Cut" -collapse false;
editorTemplate -l "Cut" -addControl "cut";
editorTemplate -l "Compress Noise Frequency" -addControl "compressNoiseFrequency";
AEaddRampControl($nodeName + ".cutDistribution");
editorTemplate -endLayout;
editorTemplate -beginLayout "Spray" -collapse false;
editorTemplate -l "Fill" -addControl "fill";
editorTemplate -l "Shift" -addControl "shift";
editorTemplate -l "Spray Along Normal" -addControl "sprayAlongNormal";
editorTemplate -l "Spray" -addControl "spray";
AEaddRampControl($nodeName + ".sprayRamp");
AEaddRampControl($nodeName + ".sprayDistribution");
editorTemplate -endLayout;
editorTemplate -beginLayout "Multistrand" -collapse false;
editorTemplate -l "Multistrand" -addControl "multistrand";
editorTemplate -l "Multistrand Percent" -addControl "multistrandPercent";
editorTemplate -l "Multistrand Randomize" -addControl "multistrandRandomize";
editorTemplate -l "Multistrand Randomize Tip" -addControl "multistrandRandomizeTip";
editorTemplate -l "Multistrand Twist" -addControl "multistrandTwist";
editorTemplate -l "Multistrand Twist Randomize" -addControl "multistrandTwistRandomize";
editorTemplate -l "Multistrand Spray" -addControl "multistrandSpray";
editorTemplate -l "Multistrand Randomize Spray" -addControl "multistrandRandomizeSpray";
AEaddRampControl($nodeName + ".multistrandSprayRamp");
editorTemplate -endLayout;
editorTemplate -beginLayout "Arnold" -collapse true;
editorTemplate -l "Mode" -addControl "aiMode";
editorTemplate -l "Min Pixel Width" -addControl "aiMinPixelWidth";
editorTemplate -endLayout;
editorTemplate -beginLayout "Viewport" -collapse true;
editorTemplate -l "Display Mode" -addControl "displayMode";
editorTemplate -l "Preview Percent" -addControl "previewPercent";
editorTemplate -l "Preview Sides" -addControl "previewSides";
editorTemplate -endLayout;
AEsurfaceShapeTemplate $nodeName;
editorTemplate -addExtraControls;
editorTemplate -endScrollLayout;
}

View File

@@ -0,0 +1,32 @@
global proc AEnurbopusNodeTemplate(string $nodeName)
{
editorTemplate -beginScrollLayout;
editorTemplate -beginLayout "General" -collapse false;
editorTemplate -l "Up Vector" -addControl "upVector";
editorTemplate -l "Method" -addControl "method";
editorTemplate -l "Shape" -addControl "shape";
editorTemplate -l "U Segments" -addControl "uSegments";
editorTemplate -l "V Segments" -addControl "vSegments";
editorTemplate -l "Segments Power" -addControl "segmentsPower";
editorTemplate -l "Radius" -addControl "radius";
editorTemplate -l "Scale Y" -addControl "scaleY";
editorTemplate -l "Rotate" -addControl "rotate";
editorTemplate -l "twist" -addControl "twist";
AEaddRampControl($nodeName + ".ramp");
editorTemplate -endLayout;
editorTemplate -beginLayout "Orientation" -collapse false;
editorTemplate -l "Use Mesh Normal" -addControl "useMeshNormal";
editorTemplate -l "Orient Method" -addControl "orientMethod";
editorTemplate -l "Orient" -addControl "orient";
editorTemplate -l "Orient Point" -addControl "orientPoint";
editorTemplate -l "Orient Segment" -addControl "orientSegment";
editorTemplate -endLayout;
AEdependNodeTemplate $nodeName;
editorTemplate -addExtraControls;
editorTemplate -endScrollLayout;
}

View File

@@ -0,0 +1,484 @@
global proc ahogeTools()
{
if (`menu -exists ahogeToolsMenu`)
{
deleteUI ahogeToolsMenu;
}
else
{
menu -l "Ahoge"
-tearOff true
-p "MayaWindow" ahogeToolsMenu;
menuItem -l "Ahoge"
-c "python(\"import ahoge_ui;ahoge_ui.create_ahoge()\")"
-ann "Create an ahogeShape node with a random seed and connect the selected surfaces"
-i "ahogeShape.png"
-p ahogeToolsMenu;
menuItem -optionBox true
-c "python(\"import ahoge_ui;ahoge_ui.create_ahoge_options()\")"
-p ahogeToolsMenu;
menuItem -l "Connect"
-c "ahogeTools_connect"
-ann "Connect the selected nurbs surfaces to the selected ahogeShape nodes"
-i "ahoge_connect.png"
-p ahogeToolsMenu;
menuItem -l "Disconnect"
-c "ahogeTools_disconnect"
-ann "Disconnect the selected nurbs surfaces from the selected ahogeShape nodes"
-i "ahoge_disconnect.png"
-p ahogeToolsMenu;
menuItem -l "Duplicate"
-subMenu true
-ann "Duplicate ahogeShape nodes"
-i "ahoge_duplicate.png"
-p ahogeToolsMenu ahogeToolsMenu_duplicate_menu;
menuItem -l "Ahoge"
-c "ahogeTools_duplicateAhoge"
-ann "Duplicate the selected ahogeShape nodes and set random seeds"
-i "ahogeShape.png"
-p ahogeToolsMenu_duplicate_menu;
menuItem -l "Ahoge and Connect"
-c "ahogeTools_duplicateAhoge_connect"
-ann "Duplicate the selected ahogeShape nodes, connect the selected surfaces to them, and set random seeds"
-i "ahoge_connect.png"
-p ahogeToolsMenu_duplicate_menu;
menuItem -l "Extra"
-subMenu true
-ann "Extra nodes"
-i "ahoge_extra.png"
-p ahogeToolsMenu ahogeToolsMenu_extra_menu;
menuItem -l "Nurbopus"
-c "python(\"import ahoge_ui;ahoge_ui.create_nurbopus()\")"
-ann "Select curves and optionally a mesh to create Nurbopus"
-i "out_nurbopusNode.png"
-p ahogeToolsMenu_extra_menu;
menuItem -optionBox true
-c "python(\"import ahoge_ui;ahoge_ui.create_nurbopus_options()\")"
-p ahogeToolsMenu_extra_menu;
menuItem -l "Connect"
-c "ahogeTools_nurbopus_connect"
-ann "Select surfaces that have Nurbopus and curves to connect the selected curves to the Nurbopus node"
-i "ahoge_connect.png"
-p ahogeToolsMenu_extra_menu;
menuItem -l "Detach"
-c "ahogeTools_nurbopus_detach"
-ann "Disconnect the selected surfaces from their Nurbopus node, duplicate the Nurbopus node, and connect the duplicated Nurbopus node to the curves of the selected surfaces"
-i "ahoge_detach.png"
-p ahogeToolsMenu_extra_menu;
menuItem -l "Miscellaneous"
-subMenu true
-ann "Miscellaneous Tools"
-i "ahoge_misc.png"
-p ahogeToolsMenu ahogeToolsMenu_misc_menu;
menuItem -l "Fix Surfaces"
-c "ahogeTools_fixSurfaces"
-ann "Select Nurbs Surfaces and a Mesh to fix the Surfaces"
-i "ahoge_fix.png"
-p ahogeToolsMenu_misc_menu;
menuItem -l "Select Connected Surfaces"
-c "ahogeTools_selectConnectedSurfaces"
-ann "Select Nurbs Surfaces that are connected to the selected Ahoge Shapes"
-i "aselect.png"
-p ahogeToolsMenu_misc_menu;
menuItem -l "Disconnect Connected Surfaces"
-c "ahogeTools_disconnectConnectedSurfaces"
-ann "Disconnect Nurbs Surfaces that are connected to the selected Ahoge Shapes"
-i "ahoge_disconnect.png"
-p ahogeToolsMenu_misc_menu;
menuItem -l "Select"
-subMenu true
-ann "Select ahogeShape nodes"
-pmc "ahogeTools_select_pmc"
-i "aselect.png"
-p ahogeToolsMenu ahogeToolsMenu_select_menu;
menuItem -l "Convert"
-subMenu true
-ann "Convert ahogeShape nodes"
-i "ahoge_convert.png"
-p ahogeToolsMenu ahogeToolsMenu_convert_menu;
menuItem -l "Convert to Curves"
-c "ahogeTools_convertToCurves"
-ann "Convert the selected ahogeShape nodes to nurbs curves"
-i "curveEP.png"
-p ahogeToolsMenu_convert_menu;
menuItem -l "Export"
-subMenu true
-ann "Export ahogeShape nodes"
-i "ahoge_export.png"
-p ahogeToolsMenu ahogeToolsMenu_export_menu;
menuItem -l "Export Alembic"
-c "python(\"import ahoge_ui;ahoge_ui.export_alembic_options()\")"
-ann "Export ahogeShape nodes to Alembic"
-i "ahoge_abc.png"
-p ahogeToolsMenu_export_menu;
menuItem -d true -p ahogeToolsMenu;
menuItem -l "Support"
-c "ahogeTools_support"
-ann "Get support and updates"
-i "ahoge_info.png"
-p ahogeToolsMenu;
}
}
global proc ahogeTools_disconnect_attr( string $left, string $right )
{
string $connections[] = `listConnections -p true $left`;
string $connection;
for ($connection in $connections)
{
string $ending = `match "\[[0-9]+\]$" $connection`;
string $short = `substring $connection 1 (size($connection) - size($ending))`;
if ( $short == $right )
{
disconnectAttr $left $connection;
}
}
}
global proc ahogeTools_connect()
{
string $surfaces[] = `ls -sl -dag -type "nurbsSurface"`;
string $ahogeShapes[] = `ls -sl -dag -type "ahogeShape"`;
string $ahogeShape;
for ($ahogeShape in $ahogeShapes)
{
string $inputSurfaces[] = `listConnections -p true ($ahogeShape + ".inputSurfaces")`;
string $inputSurfacesObj[] = `listConnections -p false ($ahogeShape + ".inputSurfaces")`;
$inputSurfacesObj = `ls -dag -type "nurbsSurface" $inputSurfacesObj`;
string $connect;
for ($connect in $inputSurfaces)
{
ahogeTools_disconnect_attr $connect ($ahogeShape + ".inputSurfaces");
}
string $surfacesToAdd[] = {};
string $surface;
for ($surface in $surfaces)
{
if (!stringArrayContains($surface, $inputSurfacesObj))
{
$surfacesToAdd[size($surfacesToAdd)] = $surface;
}
}
string $diffSurfaces[] = stringArrayCatenate($inputSurfacesObj, $surfacesToAdd);
int $i = 0;
for (; $i < size($diffSurfaces); $i++ )
{
connectAttr ($diffSurfaces[$i] + ".worldSpace[0]") ($ahogeShape + ".inputSurfaces[" + $i + "]");
}
}
}
global proc ahogeTools_disconnect()
{
string $surfaces[] = `ls -sl -dag -type "nurbsSurface"`;
string $ahogeShapes[] = `ls -sl -dag -type "ahogeShape"`;
string $ahogeShape;
for ($ahogeShape in $ahogeShapes)
{
string $inputSurfaces[] = `listConnections -p true ($ahogeShape + ".inputSurfaces")`;
string $inputSurfacesObj[] = `listConnections -p false ($ahogeShape + ".inputSurfaces")`;
$inputSurfacesObj = `ls -dag -type "nurbsSurface" $inputSurfacesObj`;
string $connect;
for ($connect in $inputSurfaces)
{
ahogeTools_disconnect_attr $connect ($ahogeShape + ".inputSurfaces");
}
string $diffSurfaces[] = stringArrayRemove($surfaces, $inputSurfacesObj);
int $i = 0;
for (; $i < size($diffSurfaces); $i++ )
{
connectAttr ($diffSurfaces[$i] + ".worldSpace[0]") ($ahogeShape + ".inputSurfaces[" + $i + "]");
}
}
}
global proc ahogeTools_duplicateAhoge()
{
string $ahoges[] = `ls -dag -sl -l -type ahogeShape`;
string $ahoge;
for ($ahoge in $ahoges)
{
string $dup[] = `duplicate -ic $ahoge`;
setAttr ($dup[0] + ".seed") (int(rand(100000)));
}
}
global proc ahogeTools_duplicateAhoge_connect()
{
string $ahoges[] = `ls -dag -sl -l -type ahogeShape`;
string $surfaces[] = `ls -dag -sl -l -type nurbsSurface`;
if (size($ahoges) < 1) error "you haven't selected any ahogeShapes";
if (size($surfaces) < 1) error "you haven't selected any surfaces";
string $ahoge;
for ($ahoge in $ahoges)
{
string $dup[] = `duplicate $ahoge`;
string $multiInstances[] = `listAttr ($dup[0] + ".inputSurfaces[*]")`;
string $multiInstance;
for ($multiInstance in $multiInstances)
{
removeMultiInstance -b true ($dup[0] + "." + $multiInstance);
}
int $i = 0;
for (; $i < size($surfaces); $i++)
{
connectAttr -f ($surfaces[$i] + ".worldSpace[0]") ($dup[0] + ".inputSurfaces[" + $i + "]");
}
setAttr ($dup[0] + ".seed") (int(rand(100000)));
}
}
global proc ahogeTools_select_pmc()
{
menu -e -dai ahogeToolsMenu_select_menu;
string $ahogeShapes[] = `ls -l -type ahogeShape`;
string $ahogeShapesSelected[] = `ls -sl -dag -l -type ahogeShape`;
string $node;
for ($node in $ahogeShapes)
{
string $name[] = `listRelatives -parent $node`;
menuItem -cb (stringArrayContains($node, $ahogeShapesSelected)) -l $name[0] -c ("select " + $node) -p ahogeToolsMenu_select_menu;
}
if (!size($ahogeShapes)) menuItem -l "Nothing" -en false -p ahogeToolsMenu_select_menu;
}
global proc ahogeTools_convertToCurves()
{
string $ahogeShape[] = `ls -l -sl -dag -type "ahogeShape"`;
string $node;
for ($node in $ahogeShape)
{
int $num = `getAttr ($node + ".numSegments")` + 1;
float $cvs[] = `getAttr ($node + ".outputPoints")`;
string $parent[] = `listRelatives -f -parent $node`;
float $m[] = `xform -q -ws -m $parent[0]`;
int $numCurves = size($cvs) / $num / 3;
int $i = 0;
for (; $i < $numCurves; $i++)
{
string $curve = "curve -d 3";
int $j = 0;
for (; $j < $num; $j++)
{
vector $p = << $cvs[$i*$num*3+$j*3], $cvs[$i*$num*3+$j*3 + 1], $cvs[$i*$num*3+$j*3 + 2] >>;
$p = pointMatrixMult($p, $m);
$p += <<$m[12], $m[13], $m[14]>>;
$curve += " -p " + ($p.x) + " " + ($p.y) + " " + ($p.z);
}
eval $curve;
}
}
}
global proc ahogeTools_support()
{
python("import webbrowser;webbrowser.open('https://boosty.to/ahoge')");
}
// Misc
global proc float ahoge_distance(vector $v1, vector $v2)
{
return sqrt(pow(($v1.x) - ($v2.x), 2) + pow(($v1.y) - ($v2.y), 2) + pow(($v1.z) - ($v2.z), 2));
}
global proc ahogeTools_fixSurfaces()
{
string $surfaces[] = `ls -dag -sl -l -type nurbsSurface`;
string $meshes[] = `ls -dag -sl -l -type mesh`;
if (!size($surfaces)) error "No nurbsSurfaces selected";
if (size($meshes) != 1) error "Select a mesh";
string $surface;
for ($surface in $surfaces)
{
// reverse direction
if ((`getAttr ($surface + ".fu")` == 0) &&
((`getAttr ($surface + ".fv")` == 1) ||
(`getAttr ($surface + ".fv")` == 2)))
{
reverseSurface -d 3 -ch 0 -rpo 1 $surface;
reverseSurface -d 0 -ch 0 -rpo 1 $surface;
}
vector $first_point = << 0, 0, 0 >>;
vector $second_point = << 0, 0, 0 >>;
int $i = 0;
for (; $i < 4; $i++)
{
$first_point += `pointOnSurface -top true -u (float($i) / 4) -v 0.0 -position $surface`;
$second_point += `pointOnSurface -top true -u (float($i) / 4) -v 1.0 -position $surface`;
}
$first_point = $first_point / 4;
$second_point = $second_point / 4;
// check for inverted normals first
vector $norm = `pointOnSurface -u 0.0 -v 0.0 -nn $surface`;
vector $origin = `pointOnSurface -u 0.0 -v 0.0 -position $surface`;
if (dot($norm, $first_point - $origin) > 0)
{
reverseSurface -d 0 -ch 0 -rpo 1 $surface;
}
//print($first_point.x + " " + $first_point.y + " " + $first_point.z + "\n");
//print($second_point.x + " " + $second_point.y + " " + $second_point.z + "\n");
vector $first_point_surface = `ahogeCmd -m $meshes[0] -cp ($first_point.x) ($first_point.y) ($first_point.z)`;
vector $second_point_surface = `ahogeCmd -m $meshes[0] -cp ($second_point.x) ($second_point.y) ($second_point.z)`;
float $first_point_distance = ahoge_distance($first_point, $first_point_surface);
float $second_point_distance = ahoge_distance($second_point, $second_point_surface);
if ($first_point_distance < $second_point_distance) // needs to reverse V then
{
reverseSurface -d 1 -ch 0 -rpo 1 $surface;
reverseSurface -d 0 -ch 0 -rpo 1 $surface;
}
}
}
global proc ahogeTools_selectConnectedSurfaces()
{
string $ahogeShapes[] = `ls -sl -dag -type "ahogeShape"`;
string $result[] = {};
string $ahogeShape;
for ($ahogeShape in $ahogeShapes)
{
string $inputSurfacesObj[] = `listConnections -p false ($ahogeShape + ".inputSurfaces")`;
$inputSurfacesObj = `ls -dag -type "nurbsSurface" $inputSurfacesObj`;
string $surface;
for ($surface in $inputSurfacesObj)
{
$result[size($result)] = $surface;
}
}
select $result;
}
global proc ahogeTools_disconnectConnectedSurfaces()
{
string $ahogeShapes[] = `ls -sl -dag -type "ahogeShape"`;
string $ahogeShape;
for ($ahogeShape in $ahogeShapes)
{
string $inputSurfaces[] = `listConnections -p true ($ahogeShape + ".inputSurfaces")`;
string $connect;
for ($connect in $inputSurfaces)
{
ahogeTools_disconnect_attr $connect ($ahogeShape + ".inputSurfaces");
}
}
}
global proc ahogeTools_nurbopus_connect()
{
string $surfaces[] = `ls -sl -dag -type "nurbsSurface"`;
if (size($surfaces) == 0) error "No nurbsSurface selected";
string $history[] = `listHistory $surfaces`;
string $nurbopuses[] = `ls -type "nurbopusNode" $history`;
string $curves[] = `ls -sl -dag -type "nurbsCurve"`;
if (size($nurbopuses) == 0) error "No nurbopusNode selected";
if (size($curves) == 0) error "No nurbsCurve selected";
string $nurbopus;
for ($nurbopus in $nurbopuses)
{
int $size = `getAttr -size ($nurbopus + ".inputCurves")`;
int $i = 0;
for (; $i < size($curves); $i++)
{
connectAttr ($curves[$i] + ".worldSpace[0]") ($nurbopus + ".inputCurves[" + ($size + $i) + "]");
string $surface = `createNode "nurbsSurface"`;
connectAttr ($nurbopus + ".outputSurfaces[" + ($size + $i) + "]") ($surface + ".create");
hyperShade -assign "initialShadingGroup" $surface;
}
}
}
global proc int ahogeTools_extract(string $str)
{
string $str_idx = `match "\[[0-9]+\]$" $str`;
string $array[];
tokenize $str_idx "[]" $array;
return int($array[0]);
}
global proc ahogeTools_nurbopus_detach()
{
string $surfaces[] = `ls -sl -dag -type "nurbsSurface"`;
if (size($surfaces) == 0) error "No nurbsSurface selected";
string $history[] = `listHistory $surfaces`;
string $nurbopuses[] = `ls -type "nurbopusNode" $history`;
if (size($nurbopuses) == 0) error "No nurbopusNode selected";
if (size($nurbopuses) != 1) error "Detach only works with a single nurbopusNode";
string $duplicate[] = `duplicate $nurbopuses[0]`;
int $connectionIndices[] = {};
int $i = 0;
for (; $i < size($surfaces); $i++)
{
string $surfaceCreate[] = `listConnections -c true -p true ($surfaces[$i] + ".create")`;
$connectionIndices[size($connectionIndices)] = ahogeTools_extract($surfaceCreate[1]);
}
string $output_surfaces[] = `listConnections -p false ($nurbopuses[0] + ".outputSurfaces")`;
$output_surfaces = `ls -dag -type "nurbsSurface" $output_surfaces`;
string $inputCurves[] = `listConnections -p true ($nurbopuses[0] + ".inputCurves")`;
string $inputCurvesObj[] = `listConnections -p false ($nurbopuses[0] + ".inputCurves")`;
$inputCurvesObj = `ls -dag -type "nurbsCurve" $inputCurvesObj`;
string $connect;
for ($connect in $inputCurves)
{
ahogeTools_disconnect_attr $connect ($nurbopuses[0] + ".inputCurves");
}
int $first_count = 0;
int $second_count = 0;
for ($i = 0; $i < size($inputCurvesObj); $i++)
{
if (intArrayContains($i, $connectionIndices))
{
connectAttr ($inputCurvesObj[$i] + ".worldSpace[0]") ($duplicate[0] + ".inputCurves[" + $first_count + "]");
connectAttr -f ($duplicate[0] + ".outputSurfaces[" + $first_count + "]") ($output_surfaces[$i] + ".create");
$first_count++;
}
else
{
connectAttr ($inputCurvesObj[$i] + ".worldSpace[0]") ($nurbopuses[0] + ".inputCurves[" + $second_count + "]");
connectAttr -f ($nurbopuses[0] + ".outputSurfaces[" + $second_count + "]") ($output_surfaces[$i] + ".create");
$second_count++;
}
}
}

View File

@@ -0,0 +1,489 @@
import maya.cmds as cmds
if cmds.about(version=True) == "2025":
from PySide6 import QtWidgets, QtGui
import shiboken6 as shiboken
else:
from PySide2 import QtWidgets, QtGui
import shiboken2 as shiboken
import maya.OpenMayaUI as omui
from enum import Enum
import random
import os
import pathlib
from datetime import datetime
import time
def get_scaling_ratio():
screen = QtGui.QGuiApplication.primaryScreen()
return screen.logicalDotsPerInch() / 96.0
scaling_ratio = get_scaling_ratio()
def maya_main_window():
main_window_pointer = omui.MQtUtil.mainWindow()
return shiboken.wrapInstance(int(main_window_pointer), QtWidgets.QWidget)
class OptionType(Enum):
Unknown = 1
Bool = 2
Int = 3
Float = 4
Option = 5
File = 6
class Option:
option_type = OptionType.Unknown
option_name = None
default = None
setting = None
widget = None
def __init__(self, option_name, option_type, default, setting, meta=None):
self.option_name = option_name
self.option_type = option_type
self.default = default
self.setting = setting
self.meta = meta
def make_widget(self, form_layout):
if self.option_type == OptionType.Bool:
self.widget = QtWidgets.QCheckBox()
self.widget.setChecked(self.default)
form_layout.addRow(self.option_name + ":", self.widget)
elif self.option_type == OptionType.Int:
self.widget = QtWidgets.QSpinBox()
self.widget.setFixedWidth(70 * scaling_ratio)
self.widget.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
if self.meta:
if "min" in self.meta:
self.widget.setMinimum(self.meta["min"])
if "max" in self.meta:
self.widget.setMaximum(self.meta["max"])
self.widget.setValue(self.default)
form_layout.addRow(self.option_name + ":", self.widget)
elif self.option_type == OptionType.Float:
self.widget = QtWidgets.QDoubleSpinBox()
self.widget.setDecimals(4)
self.widget.setSingleStep(0.01)
self.widget.setFixedWidth(70 * scaling_ratio)
self.widget.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
if self.meta:
if "min" in self.meta:
self.widget.setMinimum(self.meta["min"])
if "max" in self.meta:
self.widget.setMaximum(self.meta["max"])
self.widget.setValue(self.default)
form_layout.addRow(self.option_name + ":", self.widget)
elif self.option_type == OptionType.Option:
self.widget = QtWidgets.QComboBox()
if self.meta:
if "options" in self.meta:
for option in self.meta["options"]:
self.widget.addItem(option[1], option[0])
form_layout.addRow(self.option_name + ":", self.widget)
index = self.widget.findData(self.default)
self.widget.setCurrentIndex(index)
elif self.option_type == OptionType.File:
self.widget = QtWidgets.QLineEdit()
widget_layout = QtWidgets.QHBoxLayout()
widget_layout.setContentsMargins(0, 0, 0, 0)
browse_button = QtWidgets.QPushButton("Browse")
def browse_action():
path = self.widget.text()
file_filter = ""
if self.meta:
if "fileFilter" in self.meta:
file_filter = self.meta["fileFilter"]
result = cmds.fileDialog2(dir=path, fileFilter=file_filter, dialogStyle=2)
if result:
self.widget.setText(result[0])
browse_button.clicked.connect(browse_action)
widget_layout.addWidget(self.widget)
widget_layout.addWidget(browse_button)
form_layout.addRow(self.option_name + ":", widget_layout)
self.widget.setText(self.default)
def load(self):
if not self.widget:
return
if self.option_type == OptionType.Bool:
if cmds.optionVar(exists=self.setting):
value = bool(cmds.optionVar(q=self.setting))
self.widget.setChecked(value)
elif self.option_type == OptionType.Int:
if cmds.optionVar(exists=self.setting):
value = cmds.optionVar(q=self.setting)
self.widget.setValue(value)
elif self.option_type == OptionType.Float:
if cmds.optionVar(exists=self.setting):
value = cmds.optionVar(q=self.setting)
self.widget.setValue(value)
elif self.option_type == OptionType.Option:
if cmds.optionVar(exists=self.setting):
value = cmds.optionVar(q=self.setting)
index = self.widget.findData(value)
self.widget.setCurrentIndex(index)
elif self.option_type == OptionType.File:
if cmds.optionVar(exists=self.setting):
value = cmds.optionVar(q=self.setting)
self.widget.setText(value)
def save(self):
if not self.widget:
return
if self.option_type == OptionType.Bool:
if self.widget.isChecked():
cmds.optionVar(iv=(self.setting, 1))
else:
cmds.optionVar(iv=(self.setting, 0))
elif self.option_type == OptionType.Int:
cmds.optionVar(iv=(self.setting, self.widget.value()))
elif self.option_type == OptionType.Float:
cmds.optionVar(fv=(self.setting, self.widget.value()))
elif self.option_type == OptionType.Option:
cmds.optionVar(iv=(self.setting, self.widget.currentData()))
elif self.option_type == OptionType.File:
cmds.optionVar(sv=(self.setting, self.widget.text()))
def reset(self):
if not self.widget:
return
if self.option_type == OptionType.Bool:
self.widget.setChecked(self.default)
if self.default:
cmds.optionVar(iv=(self.setting, 1))
else:
cmds.optionVar(iv=(self.setting, 0))
elif self.option_type == OptionType.Int:
self.widget.setValue(self.default)
cmds.optionVar(iv=(self.setting, self.default))
elif self.option_type == OptionType.Float:
self.widget.setValue(self.default)
cmds.optionVar(fv=(self.setting, self.default))
elif self.option_type == OptionType.Option:
index = self.widget.findData(self.default)
self.widget.setCurrentIndex(index)
cmds.optionVar(iv=(self.setting, self.default))
elif self.option_type == OptionType.File:
self.widget.setText(self.default)
cmds.optionVar(sv=(self.setting, self.default))
class OptionsDialogType(Enum):
Create = 1
Export = 2
class OptionsDialog(QtWidgets.QDialog):
def __init__(self, options_dialog_type, title, command, options, parent=None):
super(OptionsDialog, self).__init__(parent)
self.setWindowTitle(title)
self.options_dialog_type = options_dialog_type
self.command = command
self.options = options
layout = QtWidgets.QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
menu_bar = QtWidgets.QMenuBar()
edit_menu = menu_bar.addMenu("Edit")
edit_menu.addAction("Save Settings", self.save)
edit_menu.addAction("Reset Settings", self.reset)
if self.options_dialog_type == OptionsDialogType.Export:
edit_menu.addSeparator()
edit_menu.addAction("Clear Log", self.clear_log)
layout.addWidget(menu_bar)
form_layout = QtWidgets.QFormLayout()
form_layout_margins = 8 * scaling_ratio
form_layout.setContentsMargins(
form_layout_margins, form_layout_margins, form_layout_margins, form_layout_margins)
for option in self.options:
option.make_widget(form_layout)
layout.addLayout(form_layout)
if options_dialog_type == OptionsDialogType.Create:
layout.addStretch()
buttons_layout = QtWidgets.QHBoxLayout()
layout.addLayout(buttons_layout)
buttons_layout_margins = 4 * scaling_ratio
buttons_layout.setContentsMargins(
buttons_layout_margins, buttons_layout_margins, buttons_layout_margins, buttons_layout_margins)
buttons_layout.setSpacing(4)
if options_dialog_type == OptionsDialogType.Create:
create_button = QtWidgets.QPushButton("Create")
apply_button = QtWidgets.QPushButton("Apply")
close_button = QtWidgets.QPushButton("Close")
create_button.clicked.connect(self.create)
apply_button.clicked.connect(self.apply)
close_button.clicked.connect(self.close)
buttons_layout.addWidget(create_button)
buttons_layout.addWidget(apply_button)
buttons_layout.addWidget(close_button)
elif options_dialog_type == OptionsDialogType.Export:
self.log = QtWidgets.QTextEdit()
#self.log.setFixedHeight(80)
self.log.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
self.log.setReadOnly(True)
form_layout.addRow("Log:", self.log)
export_button = QtWidgets.QPushButton("Export")
close_button = QtWidgets.QPushButton("Close")
export_button.clicked.connect(self.apply)
close_button.clicked.connect(self.close)
buttons_layout.addStretch()
buttons_layout.addWidget(export_button)
buttons_layout.addWidget(close_button)
self.load()
self.show()
def load(self):
for option in self.options:
option.load()
def save(self):
for option in self.options:
option.save()
def reset(self):
for option in self.options:
option.reset()
def create(self):
self.save()
self.command()
self.close()
def apply(self):
self.save()
if self.options_dialog_type == OptionsDialogType.Export:
start_time = time.time()
start_date = datetime.now()
self.log.moveCursor(QtGui.QTextCursor.End)
self.log.append("<font color=grey>Export started</font> " + str(start_date))
try:
self.command()
end_time = time.time()
end_date = datetime.now()
self.log.moveCursor(QtGui.QTextCursor.End)
self.log.append("<font color=grey>Export ended</font> " + str(end_date))
self.log.append("<font color=grey>Export took</font> %.4f <font color=grey>seconds</font>" % (end_time - start_time))
self.log.append("<font color=green>Done</font>")
except Exception as e:
self.log.moveCursor(QtGui.QTextCursor.End)
self.log.append("<font color=orange>%s</font>" % e)
self.log.append("<font color=red>Failure</font>")
else:
self.command()
def activate(self):
self.load()
self.show()
self.activateWindow()
def clear_log(self):
self.log.clear()
def get_value(setting):
if cmds.optionVar(exists=setting[1]):
return cmds.optionVar(q=setting[1])
return setting[0]
create_ahoge_window = None
create_ahoge_randomize_seed = [True, "ahoge_randomize_seed"]
create_ahoge_swap_uv = [True, "ahoge_randomize_swap_uv"]
create_ahoge_segments = [16, "ahoge_segments"]
create_ahoge_number_of_curves = [10, "ahoge_number_of_curves"]
create_ahoge_width = [0.01, "ahoge_width"]
def create_ahoge():
cmds.undoInfo(chunkName="create_ahoge", openChunk=True)
try:
randomize_seed = get_value(create_ahoge_randomize_seed)
swap_uv = get_value(create_ahoge_swap_uv)
segments = get_value(create_ahoge_segments)
number_of_curves = get_value(create_ahoge_number_of_curves)
width = get_value(create_ahoge_width)
surfaces = cmds.ls(sl=True, dag=True, type="nurbsSurface")
ahoge_shape = cmds.createNode("ahogeShape")
if randomize_seed:
cmds.setAttr(ahoge_shape + ".seed", random.randint(0, 10000))
cmds.setAttr(ahoge_shape + ".numSegments", segments)
cmds.setAttr(ahoge_shape + ".numCurves", number_of_curves)
cmds.setAttr(ahoge_shape + ".width", width)
for index, surface in enumerate(surfaces):
if swap_uv and cmds.getAttr(surface + ".fu") == 0 and cmds.getAttr(surface + ".fv") == 2:
cmds.warning(surface + " swapping UV")
cmds.reverseSurface(surface, d=3, ch=1, rpo=1)
cmds.reverseSurface(surface, d=0, ch=1, rpo=1)
cmds.connectAttr(surface + ".worldSpace[0]", ahoge_shape + ".inputSurfaces[" + str(index) + "]")
finally:
cmds.undoInfo(closeChunk=True)
def create_ahoge_options():
global create_ahoge_window
if not create_ahoge_window:
title = "Create Ahoge Options"
options = []
options.append(Option("Randomize Seed", OptionType.Bool, *create_ahoge_randomize_seed))
options.append(Option("Swap UV", OptionType.Bool, *create_ahoge_swap_uv))
options.append(Option("Segments", OptionType.Int, *create_ahoge_segments, {"min": 1, "max": 1000000}))
options.append(Option("Number of Curves", OptionType.Int, *create_ahoge_number_of_curves, {"min": 1, "max": 1000000}))
options.append(Option("Width", OptionType.Float, *create_ahoge_width, {"min": 0.0001, "max": 1000000.0}))
create_ahoge_window = OptionsDialog(OptionsDialogType.Create, title, create_ahoge, options, maya_main_window())
else:
create_ahoge_window.activate()
create_nurbopus_window = None
create_nurbopus_method = [1, "ahoge_nurbopus_method"]
create_nurbopus_shape = [0, "ahoge_nurbopus_shape"]
create_nurbopus_useg = [4, "ahoge_nurbopus_useg"]
create_nurbopus_vseg = [8, "ahoge_nurbopus_vseg"]
def create_nurbopus():
cmds.undoInfo(chunkName="create_nurbopus", openChunk=True)
try:
method = get_value(create_nurbopus_method)
shape = get_value(create_nurbopus_shape)
useg = get_value(create_nurbopus_useg)
vseg = get_value(create_nurbopus_vseg)
curves = cmds.ls(sl=True, dag=True, type="nurbsCurve")
if not curves:
cmds.error("No curves selected")
meshes = cmds.ls(sl=True, dag=True, type="mesh")
nurbopus = cmds.createNode("nurbopusNode")
cmds.setAttr(nurbopus + ".method", method)
cmds.setAttr(nurbopus + ".shape", shape)
cmds.setAttr(nurbopus + ".uSegments", useg)
cmds.setAttr(nurbopus + ".vSegments", vseg)
for index, curve in enumerate(curves):
cmds.connectAttr(curve + ".worldSpace[0]", nurbopus + ".inputCurves[" + str(index) + "]")
surface = cmds.createNode("nurbsSurface")
cmds.connectAttr(nurbopus + ".outputSurfaces[" + str(index) + "]", surface + ".create")
cmds.hyperShade(surface, assign="initialShadingGroup")
if meshes:
cmds.connectAttr(meshes[0] + ".worldMesh[0]", nurbopus + ".inputMesh")
cmds.select(nurbopus)
finally:
cmds.undoInfo(closeChunk=True)
def create_nurbopus_options():
global create_nurbopus_window
if not create_nurbopus_window:
title = "Create Nurbopus Options"
options = []
options.append(Option("Method", OptionType.Option, *create_nurbopus_method, {"options": [[0, "Up Vector"], [1, "Untwist"]]}))
options.append(Option("Shape", OptionType.Option, *create_nurbopus_shape, {"options": [[0, "circle"], [1, "line"]]}))
options.append(Option("U Segments", OptionType.Int, *create_nurbopus_useg, {"min": 1, "max": 1000000}))
options.append(Option("V Segments", OptionType.Int, *create_nurbopus_vseg, {"min": 1, "max": 1000000}))
create_nurbopus_window = OptionsDialog(OptionsDialogType.Create, title, create_nurbopus, options, maya_main_window())
else:
create_nurbopus_window.activate()
export_alembic_window = None
abc_path = pathlib.Path(os.environ["MAYA_APP_DIR"])
abc_path = abc_path / "projects" / "default" / "data" / "test.abc"
export_alembic_path = [str(abc_path), "ahoge_export_alembic_path"]
export_alembic_mode = [0, "ahoge_export_alembic_mode"]
export_alembic_time_range = [0, "ahoge_export_alembic_time_range"]
export_alembic_start = [1, "ahoge_export_alembic_start"]
export_alembic_end = [24, "ahoge_export_alembic_end"]
export_alembic_relative_sample = [False, "ahoge_export_alembic_relative_sample"]
export_alembic_low = [-0.2, "ahoge_export_alembic_low"]
export_alembic_high = [0.2, "ahoge_export_alembic_high"]
def export_alembic():
alembic_mode = get_value(export_alembic_mode)
alembic_time_range = get_value(export_alembic_time_range)
alembic_path = get_value(export_alembic_path)
start = get_value(export_alembic_start)
end = get_value(export_alembic_end)
relative_sample = get_value(export_alembic_relative_sample)
low = get_value(export_alembic_low)
high = get_value(export_alembic_high)
export_mode="default"
if alembic_mode == 1:
export_mode = "unreal"
elif alembic_mode == 2:
export_mode = "marmoset"
extra = ""
time_range = "current_frame"
if alembic_time_range == 1:
time_range = "time_slider"
elif alembic_time_range == 2:
time_range = "start_end"
extra += " -startEnd %d %d" % (start, end)
if relative_sample:
extra += " -relativeSample true -lowHigh %f %f" % (low, high)
print("ahogeCmd -e \"%s\" -exportMode \"%s\" -timeRange \"%s\"%s;" %
(alembic_path.replace("\\", "/"), export_mode, time_range, extra))
cmds.ahogeCmd(e=alembic_path,
exportMode=export_mode,
timeRange=time_range,
startEnd=(start, end),
relativeSample=relative_sample,
lowHigh=(low, high))
def export_alembic_options():
global export_alembic_window
if not export_alembic_window:
title = "Ahoge Export: Alembic"
options = []
options.append(Option("Path", OptionType.File, *export_alembic_path, {"fileFilter": "*.abc"}))
options.append(Option("Mode", OptionType.Option, *export_alembic_mode, {"options": [[0, "Default"], [1, "Unreal"], [2, "Marmoset"]]}))
options.append(Option("Time Range", OptionType.Option, *export_alembic_time_range, {"options": [[0, "Current Frame"], [1, "Time Slider"], [2, "Start/End"]]}))
options.append(Option("Start Frame", OptionType.Int, *export_alembic_start, {"min": -1000000, "max": 1000000}))
options.append(Option("End Frame", OptionType.Int, *export_alembic_end, {"min": -1000000, "max": 1000000}))
options.append(Option("Relative Sample", OptionType.Bool, *export_alembic_relative_sample))
options.append(Option("Low", OptionType.Float, *export_alembic_low, {"min": -1.0, "max": 0.0}))
options.append(Option("High", OptionType.Float, *export_alembic_high, {"min": 0.0, "max": 1.0}))
export_alembic_window = OptionsDialog(OptionsDialogType.Export, title, export_alembic, options, maya_main_window())
else:
export_alembic_window.activate()