////////////
//
//  Script: senReuseTriangles 0.1.4
//  Updated: 17 May 2008
//  Compatibility: Maya 8 and higher
//  Probably works with earlier versions, too.
//
//
//  Written by Sven-Erik Neve
//  Website and contact info: www.seneve.de
//  Bugs, comments, questions or suggestions? Get in touch!
//
//
//  Usage:
//  Use the senReuseTriangles command to start the script.
//  Select at least one for example polygon object, choose
//  whether to enable or to disable reuseTriangles and
//  confirm your choice.
//
//
//  Installation:
//  Copy this source code within a MEL file to one of your
//  scripts folders, for example on Windows XP 32-bit to the
//  folder \My Documents\maya\<version>\scripts. Start Maya
//  or (if it is running) use the rehash command to make Maya
//  aware of the newly copied script. Execute the script with
//  the senReuseTriangles command. In the script's ZIP archive
//  you'll also find an XPM icon that you can copy for example
//  to \My Documents\maya\<version>\prefs\icons.
//
//
//  Purpose:
//  By default Maya reevaluates triangles on the fly which
//  may cause textures to flicker when you animate an object.
//  The reuseTriangles attribute controls this. All mesh nodes
//  have it. This script allows you to enable reuseTriangles
//  so that Maya literally reuses the triangle positions from
//  your object's bind pose instead of recalculating them
//  on the fly. This in turn stops textures from flickering.
//
////////////

// Set version and date of last modification
proc string[] versionInfo() {
	string $version = "0.1.4";
	string $modDate = "17 May 2008";
	string $scriptInfo[] = {$version, $modDate};
	return $scriptInfo;
}

// Run this when the window is about to be closed, clean up
global proc senReuseTrianglesCloseWindow(string $window) {
	deleteUI $window;
	// If user wants to reset settings, do it
	if (`optionVar -ex senReuseTrianglesReset`) {
		if (`windowPref -ex $window`) windowPref -r $window;
		optionVar -rm senReuseTrianglesReset;
		if (`optionVar -ex senReuseTrianglesCurrentValue`) {
			optionVar -rm senReuseTrianglesCurrentValue;
		}
		if (`optionVar -ex senReuseTrianglesSavedValue`) {
			optionVar -rm senReuseTrianglesSavedValue;
		}
	}
}

// Count selected objects in total and mesh nodes in selection
proc int[] countObjs() {
	string $meshes[] = sort(`ls -sl -dag -lf -typ mesh`);
	int $counter[] = {(size(`ls -sl`)), (size($meshes))};
	return $counter;
}

// On window creation, determine which radio button shall be selected
proc int getSavedValue() {
	int $rtriState = 1;
	if (`optionVar -ex senReuseTrianglesSavedValue`) {
		$rtriState = `optionVar -q senReuseTrianglesSavedValue`;
	}
	optionVar -iv senReuseTrianglesCurrentValue $rtriState;
	return $rtriState;
}

// On selection change, determine which radio button is _now_ selected
global proc int senReuseTrianglesGetCurrentValue() {
	int $rtriState = 1;
	if (`optionVar -ex senReuseTrianglesCurrentValue`) {
		$rtriState = `optionVar -q senReuseTrianglesCurrentValue`;
	}
	return $rtriState;
}

// When another radio button is selected save which one it is
global proc senReuseTrianglesSetRadioBtnState(string $rtriRadioBtns) {
	int $rtriState = (2 - `radioButtonGrp -q -sl $rtriRadioBtns`);
	optionVar -iv senReuseTrianglesCurrentValue $rtriState;
}

// Create info texts to inform user of script status
proc string[] createTexts(int $counter[]) {
	string $report;
	string $instruct;
	float $statusColor[];
	string $texts[];

	if (!$counter[0]) {
		$report = "Nothing selected.\n";
		$instruct = "Select at least one for example polygon object.";
		$statusColor = {0.9, 0.15, 0.0};
	}
 	else if ($counter[0] && !$counter[1]) {
 		$report = "No mesh nodes in selection.\n";
 		$instruct = "Select at least one for example polygon object.";
		$statusColor = {1.0, 0.7, 0.1};
 	}
 	else {
 		$report = "You're good to go.\n";
 		$instruct = "Enable reuseTriangles to make sure " +
 			"textures don't flicker.";
		$statusColor = {0.27, 0.8, 0.0};
	}
 	$texts = {$report, $instruct, $statusColor[0], $statusColor[1], $statusColor[2]};
 	return $texts;
}

// Save settings
global proc senReuseTrianglesSaveSettings(string $rtriRadioBtns) {
	int $rtriState = (2 - `radioButtonGrp -q -sl $rtriRadioBtns`);
	optionVar -iv senReuseTrianglesCurrentValue $rtriState;
	optionVar -iv senReuseTrianglesSavedValue $rtriState;
}

// Reset settings; actual reset occurs when window closes
global proc senReuseTrianglesResetSettings(string $rtriRadioBtns) {
	optionVar -iv senReuseTrianglesSavedValue 1;
	radioButtonGrp -e -sl 1 $rtriRadioBtns;
	optionVar -iv senReuseTrianglesReset 1;
}

// Get length of Help window just before the user changes something
global proc int senReuseTrianglesGetHelpMenuLen(string $helpMenu) {
	int $helpMenuLen = `window -q -h $helpMenu`;
	return $helpMenuLen;
}

// Change length of Help window when user opens and closes frameLayouts
global proc senReuseTrianglesHelpMenuChangeLen(int $frame, int $incLen, int $helpMenuLen, string $helpMenu) {
	if ($incLen) {
		if ($frame) window -e -h ($helpMenuLen + 110) $helpMenu;
		else window -e -h ($helpMenuLen + 200) $helpMenu;
	}
	else {
		if ($frame) window -e -h ($helpMenuLen - 110) $helpMenu;
		else window -e -h ($helpMenuLen - 200) $helpMenu;
	}
}

// Create Help menu
global proc senReuseTrianglesHelpMenu(string $script) {
	int $helpMenuLen = 350;
	string $helpMenu = ($script + "HelpWindow");
	string $versionInfo[] = versionInfo();

	// If Help window already exists delete it
	if (`window -ex $helpMenu`) deleteUI $helpMenu;
	if (`windowPref -ex $helpMenu`) windowPref -r $helpMenu;
	window -t ($script + " Help") -mb true -wh 400 $helpMenuLen $helpMenu;

	showWindow $helpMenu;

	// Create formLayout to accommodate four frames
	string $helpMenuFrame = `formLayout "helpMenuFrame"`;

		// "About" frame
		string $helpAbout = `frameLayout
			-l ("About " + $script + "\n") -bs "etchedIn"
			-la center -li 5 -mw 10 -mh 10 "helpAboutHeadlineFrame"`;
			string $helpAboutText = `text -l ("Version: " + $versionInfo[0] + "\n" +
				"Updated: " + $versionInfo[1] + "\n" +
				"Compatibility: Maya 8 and higher\n" +
				"Probably works with earlier versions, too.\n\n" +
				"Written by Sven-Erik Neve\n" +
				"Website and contact info: www.seneve.de\n" +
				"Bugs, comments, questions or suggestions? Get in touch!") "helpAboutText"`;
		setParent ..;

		// "Usage (summary)" frame
		string $helpUsageShort = `frameLayout
			-l ("Usage (summary)") -bs "etchedIn"
			-la center -li 5 -mw 10 -mh 10 "helpUsageShortFrame"`;
			string $helpUsageShortText = `text -l ("Select at least one for example polygon object, choose whether\n" +
				"to enable or to disable reuseTriangles and confirm your choice.") "helpUsageShortText"`;
		setParent ..;

		// "Usage (in-depth)" frame
		string $helpUsageLong = `frameLayout
			-l ("Usage (in-depth)") -bs "etchedIn" -cll true -cl true
			-pec ("senReuseTrianglesHelpMenuChangeLen(0, 1, senReuseTrianglesGetHelpMenuLen(\"" + $helpMenu + "\"), \"" + $helpMenu + "\")")
			-pcc ("senReuseTrianglesHelpMenuChangeLen(0, 0, senReuseTrianglesGetHelpMenuLen(\"" + $helpMenu + "\"), \"" + $helpMenu + "\")")
			-la center -li 5 -mw 10 -mh 10 "helpUsageLongFrame"`;
			string $helpUsageLongText = `text -l ("Select an object that contains a mesh node, for example select a\n" +
				"polygon object. The script's Status will inform you at all times whether\n" +
				"your selection contains a mesh node or not. Once you have something\n" +
				"selected that contains at least one mesh node the script is ready to go.\n\n" +
				"Select whether you want to enable or disable reuseTriangles for the mesh\n" +
				"nodes in your selection. The default setting is Enable. Confirm your choice\n" +
				"with either the Set button (runs the script and closes the window) or with\n" +
				"the Apply button (runs the script, leaves the windw open).\n\n" +
				"The main window also has a menu to save and reset the settings.\n" +
				"Save Settings saves the settings even if you don't run the script.\n" +
				"Reset Settings resets the settings and - contrary to regular Maya\n" +
				"windows - also resets the window position.") "helpUsageLongText"`;
		setParent ..;

		// "Purpose" frame
		string $helpPurpose = `frameLayout
			-l ("Purpose") -bs "etchedIn" -cll true -cl true
			-pec ("senReuseTrianglesHelpMenuChangeLen(1, 1, senReuseTrianglesGetHelpMenuLen(\"" + $helpMenu + "\"), \"" + $helpMenu + "\")")
			-pcc ("senReuseTrianglesHelpMenuChangeLen(1, 0, senReuseTrianglesGetHelpMenuLen(\"" + $helpMenu + "\"), \"" + $helpMenu + "\")")
			-la center -li 5 -mw 10 -mh 10 "helpPurposeFrame"`;
			string $helpPurposeText = `text -l ("By default Maya reevaluates triangles on the fly which may cause\n" +
				"textures to flicker when you animate an object. The reuseTriangles\n" +
				"attribute controls this. All mesh nodes have it.\n\n" +
				"This script allows you to enable reuseTriangles so that Maya literally\n" +
				"reuses the triangle positions from your object's bind pose instead of\n" +
				"recalculating them on the fly. This in turn stops textures from flickering.") "helpPurposeText"`;
		setParent ..;

		// Create Close button and correctly align all elements
		string $closeButton = `button -l "Close" -h 25 -c ("deleteUI(\"" + $helpMenu + "\")") "helpMenuCloseButton"`;
		formLayout -e
			-af $helpAbout top 5
			-af $helpAbout left 5
			-af $helpAbout right 5

			-af $helpUsageShort left 5
			-af $helpUsageShort right 5
			-ac $helpUsageShort top 5 $helpAbout

			-af $helpUsageLong left 5
			-af $helpUsageLong right 5
			-ac $helpUsageLong top 5 $helpUsageShort

			-af $helpPurpose left 5
			-af $helpPurpose right 5
			-ac $helpPurpose top 5 $helpUsageLong

			-af $closeButton bottom 5
			-ap $closeButton left 0 33
			-ap $closeButton right 0 66
		$helpMenuFrame;
	setParent ..;
}

// Set the selected meshes' reuseTriangles attributes and print a report
global proc senReuseTrianglesRtriSwitcher(int $rtriState, int $closeWindow, string $window, string $rtriRadioBtns) {
	string $meshes[] = sort(`ls -sl -dag -lf -typ mesh`);
	string $list;
	string $listShort[];
	string $resultOff = "reuseTriangles is now disabled for";
	string $resultOn = "reuseTriangles is now enabled for";
	string $result;
	int $counter[] = {(size(`ls -sl`)), (size($meshes))};

	if ($rtriState) $result = $resultOn;
	else $result = $resultOff;

	for ($element in $meshes) setAttr ($element + ".rtri") $rtriState;

	if ($counter[1] >= 2) {
		appendStringArray($listShort, $meshes, ($counter[1] - 1));
		$list = (stringArrayToString($listShort, ", "));
		$list = ($list + " and " + $meshes[$counter[1] - 1] + ".\n");
		print ($result + " the " + $counter[1] + " mesh nodes " + $list);
	}
	else print ($result + " the mesh node " + $meshes[0] + ".\n");
	senReuseTrianglesSaveSettings($rtriRadioBtns);
	if ($closeWindow) senReuseTrianglesCloseWindow($window);
}

// Create layout with Status frame and radio button group
proc string layoutTopAndBottom(int $rtriState, int $counter[], string $window, string $layAll) {
	string $rtriText = "reuseTriangles:";
	string $texts[] = createTexts($counter);
	string $annStatus = ("Script status: " + (match ("[^\n]*", $texts[0])) + " " + $texts[1]);
	string $annSettings = $rtriText + " Enable " +
		"to stop textures from flickering.";

	// Create frame for Status and Settings
	string $topFrame = `columnLayout -adj true -rs 5 -co both 5 "topFrame"`;

		// Frame for status text and traffic light icon
		string $statusFrame = `frameLayout
			-l "Status" -bs "etchedIn"
			-la center -li 5 -mw 5 -mh 5 "statusFrame"`;
			string $statusForm = `formLayout -nd 100 "statusForm"`;
				string $statusIcon = `formLayout
					-w 15 -h 15
					-bgc (float($texts[2])) (float($texts[3])) (float($texts[4])) "statusIcon"`;
				setParent ..;
				string $textColumn = `columnLayout
					-adj true
					-cal center "textColumn"`;
					string $statusText = `text -ann $annStatus -l ($texts[0] + $texts[1]) "statusText"`;
				setParent ..;
				formLayout -e
					-af $statusIcon left 5
					-af $statusIcon top 5

					-af $textColumn left 30
					-af $textColumn right 0
				$statusForm;
			setParent ..;
		setParent ..;

		// Frame for radio button group
		string $settingsFrame = `frameLayout
			-l "Settings" -bs "etchedIn"
			-la center -li 5 -mw 5 -mh 5 "settingsFrame"`;
			string $radioColumn = `columnLayout
				-adj true
				-cal center "radioColumn"`;
				string $rtriRadioBtns = `radioButtonGrp
					-nrb 2 -vr -l $rtriText
					-la2 "Enable" "Disable"
					-ann $annSettings
					-sl (2 - $rtriState) "rtriRadioBtns"`;
			radioButtonGrp -e -cc ("senReuseTrianglesSetRadioBtnState(\"" + $rtriRadioBtns + "\")") $rtriRadioBtns;
			setParent ..;
		setParent ..;

	setParent ..;

	// Frame for the Set, Apply and Close buttons
	string $bottomFrame = `formLayout -nd 20 "bottomFrame"`;
		string $b1 = `button -l "Set" -h 25 -c ("senReuseTrianglesRtriSwitcher((senReuseTrianglesGetCurrentValue()), 1, \"" + $window + "\", \"" + $rtriRadioBtns + "\")") "setButton"`;
		string $b2 = `button -l "Apply" -h 25 -c ("senReuseTrianglesRtriSwitcher((senReuseTrianglesGetCurrentValue()), 0, \"" + $window + "\", \"" + $rtriRadioBtns + "\")") "applyButton"`;
		string $b3 = `button -l "Close" -h 25 -c ("senReuseTrianglesCloseWindow(\"" + $window + "\")") "closeButton"`;

		if (!$counter[1]) {
			button -e -en false $b1;
			button -e -en false $b2;
		}

		// Correctly align the buttons
		formLayout -e
			-af $b1 bottom 5
			-af $b1 left 5
			-ap $b1 right 5 7
			-an $b1 top

			-af $b2 bottom 5
			-ac $b2 left 5 $b1
			-ac $b2 right 5 $b3
			-an $b2 top

			-af $b3 bottom 5
			-af $b3 right 5
			-ap $b3 left 5 13
			-an $b3 top
		$bottomFrame;
	setParent;

	// Correctly align the two frames
	formLayout -e
		-af $topFrame right 0
		-af $topFrame left 0
		-af $bottomFrame bottom 0
		-af $bottomFrame right 0
		-af $bottomFrame left 0
	$layAll;
	return $rtriRadioBtns;
}

// Either create formLayout or just update its content
global proc string senReuseTrianglesCreateLayout(int $rtriState, string $window, string $layout) {
	windowPref -sa;
	if (`formLayout -ex $layout`) {
		deleteUI -lay $layout;
		$rtriState = senReuseTrianglesGetCurrentValue();
	}

	int $counter[] = countObjs();

	string $layAll = `formLayout -p $window $layout`;
	string $rtriRadioBtns = (layoutTopAndBottom($rtriState, $counter, $window, $layAll));
	setParent ..;
	return $rtriRadioBtns;
}

// Create main window and fill in content
proc createWindow() {
	string $script = "senReuseTriangles";
	string $window = ($script + "Window");
	string $layout = ($script + "Layout");

	if (`window -ex $window`) deleteUI $window;
	window -t $script -mb true -wh 400 250 $window;

	int $rtriState = getSavedValue();

	string $rtriRadioBtns = (senReuseTrianglesCreateLayout($rtriState, $window, $layout));

	// Create Edit and Help menus
	string $mainEditMenu = `menu -l "Edit" "editMenu"`;
		string $mainEdit1 = `menuItem -l "Save Settings" -c ("senReuseTrianglesSaveSettings(\"" + $rtriRadioBtns + "\")") "editMenuSave"`;
		string $mainEdit2 = `menuItem -l "Reset Settings" -c ("senReuseTrianglesResetSettings(\"" + $rtriRadioBtns + "\")") "editMenuReset"`;
	string $mainHelpMenu = `menu -l "Help" -hm true "helpMenu"`;
		string $mainHelp1 = `menuItem -l ("Help on " + $script) -c ("senReuseTrianglesHelpMenu(\"" + $script + "\")") "helpMenuHelp"`;

	showWindow $window;

	// Start a scriptJob to run as long as the window exists
	int $jobNum = `scriptJob -e "SelectionChanged" ("senReuseTrianglesCreateLayout(\"" + $rtriState + "\", \"" + $window + "\", \"" + $layout + "\")") -p $window`;
}

// Procedure to start the script
global proc senReuseTriangles() {
	createWindow();
}

senReuseTriangles MEL-Skript. Dieses Skript steuert das reuseTriangles-Attribut und somit das Texturflackern animierter Objekte. Zunächst überprüft es, ob die aktuelle Auswahl mindestens ein Meshnode enthält. Da ohnehin nur Meshnodes das reuseTriangles-Attribut (kurz rtri) haben, lässt sich das Skript nur ausführen, wenn mindestens eines in der Auswahl ist. Ist das der Fall, setzt das Skript rtri auf 0 oder 1 – je nachdem, was der Benutzer eingestellt hat. Zum Schluss meldet es, welche Nodes von der Änderung betroffen waren.

Dieses Skript herunterladen (6,79 KiByte)
Maya 8 oder höher, funktioniert vermutlich auch mit früheren Versionen.