'Hard Edges' in the Bake texture maps thingy is giving me unexpected results.
The edges in the render are offset, and doesn't match the UVs...also, the lowest thickness (1) is way too fat, and my model is to scale (if that matters, it's a tank)
I use this script all the time and it's amazing! But you know, I can never get "Rectify" to work. It looks like I should be able to select UV islands made up of quads and have them get straightened into rectangles but it never does anything when I left click the button. Is this a known thing or is there a hidden 'gotcha' that I'm not aware of?
ya i have seen that too with rectify. I'll select a element that is fairly close to rectangular in the first place. click rectify and it will usually ball it all up and make a huge mess. Crtl-z
Also can't get the linear align to work now in 2011. It never quite straightens it, always have to use the old scaling method again to get lines straight.
Still an amazing tool overall and can't live without it.
'Hard Edges' in the Bake texture maps thingy is giving me unexpected results.
The edges in the render are offset, and doesn't match the UVs...also, the lowest thickness (1) is way too fat, and my model is to scale (if that matters, it's a tank)
I've been wondering myself how this works, any tips would be great!
maybe you can implement something from this stuff.. I'd like to see transfer of UV from hipoly to lowpoly for example.. missing this
-- UV Layout
-- This program was split off from the Surface Toolkit.... Thanks to the guy who coded the TV drawing routine I'm using.
-- please email me at vajuras@planetunreal.com so I can give ya credit. www.cyberkreations.com/kreationsedge
-- Updated May 9, 2001 to work in Max 4. I think my interest in this was rekindled so that it could be used to help Chilliskinner advance.
-- On jan. 23 the unwrap algorithm was vastly improved to handle unwraps on the right
-- and left side. Also, added Match UVW function/utility.
-- 2/7
-- Made the Camera Projection Logic.
-- 2/14
-- Improved "Update Map" routine which would have an error.
-- Render_map will now convert object to mesh if not an Editable Object.
-- Added ability to separately render TVFaces without splitting a mesh object. This
-- method seems to work much better and return more accurate results...
-- 2/20
-- Update_Texture now works with Multi-materials...
-- 2/23
-- started working on the Skin Composer routine.
-- 3/02
-- Actually put in the AI for Blender.
-- Upgraded the UV Manager to create an alpha channel for uv maps.
-- Blender uses advanced algorithm to compute across any range [n, n] instead of [0, 100].
-- This is the code that does the math:
-- dist = abs(sort_gy - sort_ly)
-- pnt = 1/dist
-- p_dist = abs(pix.y - sort_ly)
-- blend_pnt = p_dist*pnt
-- 3/12
-- Added Attachments Utility
-- 4/17
-- Fixed a bug where the VertexSelection did not work for SurfUnwrap.
-- v1.2
-- 4-21
-- Added Edge Colors & Surface Glue.
-- Extended the range of the size of an image.
-- The Script used to crash if the restore 0r Apply under Project UVW button was pressed.
-- You can now enter float values for the Width & Length of a bitmap (UV Manager)
-- A lot of easy crashes were fixed that may be caused if a user clicks the wrong button.
-- v1.2.2
-- Fixed a crash that may occur during a 'render map' when the color comes up undefined...
-- Default Material checkbox will now go & load the Material's diffusemap. Changes a BitmapTexture to Bitmap.
-- Increased User Feedback
-- v1.2.3 -> v1.2.4
-- Fixed the bug in which the edge color array would crash the utility.
-- The utility displays the expiration date.
-- v1.3
-- Added UV Mesher Tool.
-- Improved Glue Tool Performance.
-- v1.3.3
-- UV Mesher grabs the dimension of the Diffuse Channel Bitmap if available.
-- WARP feature for the UV Mesher was fixed.
-- v1.4
-- UpdateMap feature now reloads all the mapping channels instead of just the diffuse channel.
utility surfHelp "UV Layout"
(
local sort_y, morph_state = false
-- stores the selection of cross objects
local b_cross = #()
local b_crossNum = 0
local s_width = 190
local s_height = 345
-- For the 3D Paint Options
local default_secs = 3600
local map_type = 0 --default mapping: planar
local uvw_axis = 0
-- Emergency ShutDown
local shutDown = false
-- Determines if this script is registed, if so, all features are enabled.
local register = true
label display_global ""
--stores color for each edge (UV Layout & Edge)
local color_mat = #()
-- global user_color
local global_color = red
-- selection set data
local sel_set =#(), sel_index = 1
-- Variables for GLUE
local glue_set = #()
local glue_names = #()
local glue_objA = #()
local glue_objB = #()
local glue_pos = #(#())
local previous_b = #() -- Stores the original OBJECT B
-- Variables for UV Mesher
local face_set = #() -- Stores the origin for the TVFace.
fn grab_sel =
(
selection as array
)
-- Selects all the faces in a mesh.
fn setFaceArray tar numF =
(
tar = #()
for i = 1 to numF do
(
tar[i] = i
)
return tar
)
-- Retrieves the date from a string and returns it in a 3-element array. The string must conform to localTime String Conventions
-- meaning a space character must be included like "11/23/98 8:23PM". This function can also tokenize a regular string.
-- This routine automatically looks for / and \\ (backslash) but, an extra delimeter can be searched.
-- By default, you should send a space character.
fn get_all_tokens str_in delimeter =
(
tokens = #()
str = str_in as string
len = str.count
count = 1 -- Count the # of tokens
elmo = 0 -- Count valid charcters
for a = 1 to len do
(
if str[a] == "/" or str[a] == delimeter or str[a] == "\\" then
(
this_token = substring str count elmo
append tokens this_token
-- Set the pointer to the beginning of the next slot.
count = a + 1
elmo = 0
)
else
(
-- Count the valid characters
elmo = elmo + 1
)
)
if shutDown == true then
(
shutDown == true
return #()
)
-- Return the last token also.
this_token = substring str count elmo
append tokens this_token
tokens
)
-- Replace all occurances of a character with another.
fn replace_char str delimeter new_char =
(
len = str.count
for a = 1 to len do
(
if str[a] == delimeter then str[a] = new_char
)
str
)
-- Opt 1: Encrypt
-- 2: Not Encrypted
fn read_data file_name opt =
(
count = 1
j_name = #()
if opt == 2 then file = openFile (file_name)
else
file = openEncryptedFile (file_name) 252525
if file != undefined then
(
while (not eof file) do
(
str = readline file
j_name[count] = str
count = count + 1
)
close file
) -- if
j_name
)
-- Opt 1: encrypt
-- 2: not encrypt
fn save_data file_name path_string opt =
(
if file_name != undefined then
(
if opt == 1 then file = createFile(file_name+".tmp")
else
file = createFile(file_name)
format "%\n" path_string to:file
close file
) -- if
if opt == 1 then (
encryptFile (file_name+".tmp") file_name 299525
deleteFile (file_name+".tmp")
)
)
-- Use the .ini file to determine where the MAX ROOT is.
fn get_root =
(
f = read_data "uv_max/layout.ini" 2
if f.count < 1 then (
messagebox "Please press the Online Help (.chm) button first to install the .ini file before continuing."
return #()
)
tokens = get_all_tokens f[1] "-"
tokens
) -- warez
-- This function will return another point that lies in the same spline. This func is called by the unwrap_spline
-- func which in turn uses this AI to help determine which xAxis to assign to a spline knot. The Spline Ends Algorithm
-- is applied which states that the very next vertex in the spline order can be used to determine the direction of the
-- knot.
fn findOtherKnot obj spl vert =
(
local pnt
numK = numKnots obj spl
old_pnt = getKnotPoint obj spl vert
next_vert = vert - 1
if vert >1 then next_vert = vert - 1
else
next_vert = vert + 1
pnt = getKnotPoint obj spl next_vert
gw = "NEXT:"+next_vert as string+" SENT:"+vert as string
-- Return the same point back if no vert exists on a different xAxis in the same spline.
pnt
)
-- This function will return another point that lies in the same spline. This func is called by the radialSolver
-- func which in turn uses this AI to help determine which xAxis to assign to a spline knot.
fn simpleFindOtherKnot obj spl vert =
(
local pnt
numK = numKnots obj spl
old_pnt = getKnotPoint obj spl vert
for i = 1 to numK do
(
pnt = getKnotPoint obj spl i
if old_pnt.x != pnt.x then return pnt
)
-- Return the same point back if no vert exists on a different xAxis in the same spline.
pnt
)
-- This function makes any knot that equal the deformed knot move also similar to the Global Transform Func.
-- Since the new position is along the yAxis, it will not be deformed again.
-- Var:
-- new_pos - new position where this vert should move
fn makeAllKnotsEqual obj spl vert new_pos thres =
(
nums = numSplines obj
old = getKnotPoint obj spl vert -- current position of the before the new move.
for i = 1 to nums do
(
numk = numKnots obj i
for j = 1 to numk do
(
pnt = getKnotPoint obj i j
-- Exclude the spline where the original knot came from. Spline Ends Algorithm.
pntxUp = old.x + thres
pntxDown = old.x - thres
pntyUp = old.y + thres
pntyDown = old.y - thres
pntzUp = old.z + thres
pntzDown = old.z - thres
if i != spl and (pnt.x <= pntxUp and pnt.x >= pntxDown) and (pnt.y <= pntyUp and pnt.y >= pntyDown) and (pnt.z <= pntzUp and pnt.z >= pntzDown) then
(
pnt = new_pos
setKnotPoint obj spl vert pnt
)
)
)
)
-- This function will solve for a radial b-spline since the Spline Ends Algor. fails if the points lie within the
-- threshold.
fn radialSolver obj spl vert =
(
numS = numSplines obj
new_spline = spl - 1
-- limit checks
if new_spline < 1 then new_spline = spl + 1
if new_spline > numS then new_spline = spl
pnt = simpleFindOtherKnot obj new_spline vert
-- Return another point on another spline that can be used to determine the direction.
pnt
)
-- This function unwraps a spline object. If the surf is cylindrical/spherical, the knots along the mid spline behind the base axis
-- will be pulled apart. Spline Ends Algorithm examines a spline and will assign to the middle knot automatically the direction
-- the knot should go which is naturally, determined by the Order of the spline.
-- b_a - Y axis
-- x_a - X axis
fn unwrap_spline obj b_a x_a thres output =
(
local num_s, num_k, val, pnt, gw
dist = 0.0 -- distance pnt from x_a
try (
num_s = numSplines obj
) catch (
messagebox "Please choose a valid object."
return 0
)
for i = 1 to num_s do
(
num_k = numKnots obj i
calcy = (i as float / num_s as float) * 100
calcy = calcy as integer
lc = calcy as string + "%"
output.text = lc
for j = 1 to num_k do
(
pnt = getKnotPoint obj i j
gw = i as string + ":" + j as string + " "+pnt as string
-- If the point is below the base axis, adjust the val variable.
if pnt.y > b_a then val = pnt.y - b_a
else
val = 0
ny = pnt.y
nx = pnt.x
dist = (abs(x_a - pnt.x))/100
-- New Y coordinate will be at base axis. If Y coordinate is less than base axis, then let it keep its position.
if pnt.y > b_a then
(
ny = b_a
--nx = pnt.x - val
--gw = "Behind base "+i as string+":"+j as string+" "+pnt.x as string
--print gw
-- If the point is along the middle spline behind the base axis.... Determine which direction to move.
midUp = (x_a as float + thres as float)
midDown = (x_a as float - thres as float)
if pnt.x <= midUp and pnt.x >= midDown then
(
otherKnot = findOtherKnot obj i j
--gw = "Mid "+i as string+":"+j as string
--print gw
-- If the Spline Ends Algorithm has failed in case of radial b-splines then, use the radial b-solver algorithm
-- instead.
if otherKnot.x == pnt.x then otherKnot = radialSolver obj i j
est = otherKnot.x
if est < (x_a) then nx = pnt.x - (val * dist)
else
nx = pnt.x + (val * dist)
-- Now, deform any other colliding vertices.... The deformed verts will not ever be deformed again because
-- they will equal the b_a.
new_pnt = [nx, ny, pnt.z]
makeAllKnotsEqual obj i j new_pnt thres
)
else
(
if pnt.x < x_a then nx = pnt.x - (val * dist)
else
(
if pnt.x > x_a then
(
nx = pnt.x + (val * dist)
gw = gw + "RIGHT "
new_pnt = [nx, ny, pnt.z]
--makeAllKnotsEqual obj i j new_pnt thres
) -- if
) -- if
) -- if
) -- if
setKnotPoint obj i j [nx, ny, pnt.z]
updateShape obj
--gw = gw + " "+nx as string + ":" + ny as string + " " + val as string
--print gw
)
)
try (
) catch (
messagebox "Please select a valid object"
return 0
)
output.text = "->"
)
-- This is a general func designed to work with any type of surface. It
-- takes the object and computes the highest or lowest x value.
-- option 1: largest, opt 2: least
fn compute_percent obj opt =
(
local sort = 0, diff_x = 0.0, sort_x = 0
convertToMesh obj
numS = getnumverts obj
for i = 1 to numS do
(
pnt = getvert obj i
if i == 1 then (
diff_x = pnt.x
sort_x = i
)
else
(
if opt == 1 and pnt.x > diff_X then
(
sort_x = i
diff_x = pnt.x
)
if opt != 1 and pnt.x < diff_X then
(
sort_x = i
diff_x = pnt.x
)
)
)
sort_x
)
-- This function unwraps a mesh object. The val is computed to determine the total
-- distance a point should be moved along the X axis. The dist is computed as the
-- distance the point is from the X axis which gives a percentage value.
-- b_a - Y axis
-- x_a - X axis
fn unwrap_mesh obj b_a x_a x_width use_stack disp =
(
local num_s, num_k, val, pnt, gw, target = #(), i, sort_x
dist = 0.0 -- distance pnt.x is from x_a divided by 100 to get
-- a percentage. This computation will then be used
-- to determine how far from the X axis the points
-- should be deformed.
count = 1
select_i = 0 -- turns on if stack is present...
num_verts = 0
try (
dummy = getnumfaces obj
) catch (
convertToMesh obj
)
--Had to take out unwrap support for a vertex selection. It was a useless feature anyway...
num_verts = getnumverts obj
if select_i == 0 or use_stack == false then
(
for i = 1 to num_verts do
(
target[i] = i
)
) -- if
disp.text = "Analyzing Topology...."
sort_x = compute_percent obj 1
far_vert = getvert obj sort_x
sort_neg = compute_percent obj 2
least_vert = getvert obj sort_neg
-- Get the percentage from the farthest vert. Then, this value will be used
-- to equate the values to a range [low, 100]
percent = 100 / (abs(x_a - far_vert.x))
percent_neg = 100 / (abs(x_a - least_vert.x))
progressStart "Unwrapping..."
cond = true
count = 1
for i in target do
(
calcy = (i as float / num_verts as float) * 100
calcy = calcy as integer
lc = calcy as string + "%"
if select_i == 1 then disp.text = "Using Stack Selection...."
else
cond = progressUpdate calcy
if cond == false then return 0
try (
pnt = getvert obj i
) catch (
pnt = getvert obj count
)
-- If the point is below the base axis, adjust the val variable.
if pnt.y > b_a then val = pnt.y - b_a
else
val = 0
ny = pnt.y
nx = pnt.x
if pnt.x < x_a then dist = (abs(pnt.x - x_a)) * percent_neg
else
if pnt.x > x_a then dist = (abs( pnt.x - x_a)) * percent
dist = dist / 100
-- If the user wants to morph the mesh, then let dist always eq. 1 so
-- that the verts may be deformed.
--if morph_state == true then dist = 1
-- New Y coordinate will be at base axis. If Y coordinate is less than base axis, then let it keep its position.
if pnt.y > b_a then
(
ny = b_a
--nx = pnt.x - val
-- Include the middle spline as well
-- If midpoint is from LEFT TO RIGHT then mid = x_a + 1
--mid = x_a + 1
if pnt.x < x_a then
nx = pnt.x - (val * dist)
else
(
if pnt.x > x_a then (
nx = pnt.x + (val * dist)
)
total = val * dist
--gw = "Dist:"+dist as string+" Val:"+val as string+" Total:"+total as string
--print gw
)
) -- if
try (
setvert obj i [nx, ny, pnt.z]
) catch (
setvert obj count [nx, ny, pnt.z]
)
--gw = gw + " X:Y "+nx as string + ":" + ny as string + " V:" + val as string
--print gw
count = count + 1
)
update obj
disp.text = ""
progressEnd()
-- Return target array.
target
)
-- This function uses the array (spl) to restore the original target.
fn restore_spline obj spl output =
(
local token = #()
local count = 1
if classof obj != editable_mesh then return
try (
lengt = spl.count
for i = 1 to lengt do
(
calcy = (i as float / lengt as float) * 100
calcy = calcy as integer
lc = calcy as string + "%"
output.text = lc
token = get_token spl[i] " "
setKnotPoint obj (token[1] as Number) (token[2] as Number) [token[3] as float, token[4] as float, token[5] as float]
)
) catch (
messagebox "Cannot restore shape."
return 0
)
output.text = "->"
updateShape obj
)
fn restore_mesh obj target spl output =
(
leng = target.count -- Get the Vertex Selection
real_num = getnumverts obj -- Get # of verts in the mesh object
count = 0
collapseStack obj
if leng < 1 then
(
-- Fill target array
for i = 1 to real_num do
(
count = count + 1
target[count] = getvert obj i
)
)
count = 0
progressStart "Restoring..."
for i in target do
(
count = count + 1
calcy = (count as float / leng as float) * 100
calcy = calcy as integer
progressUpdate calcy
-- An empty target array means No Vertex Selection was made.
if leng == real_num or leng < 1 then setvert obj count spl[count]
else
setvert obj i spl[i]
--gw = "Restore:"+spl[count] as string
)
try (
--output.text = "->"
progressEnd()
) catch ()
update obj
)
-- This func draws the pixels in-between the 2 points.
fn draw_line x1 y1 x2 y2 uvBMP u_color =
(
pnt = #()
-- Compute the pixels between 2 points. First, derive the distance.
dist_x = abs(x2 - x1)
dist_y = abs(y2 - y1)
if x1 > x2 then l_x = x2
else
l_x = x1
if y1 > y2 then l_y = y2
else
l_y = y1
-- Let i take the value of y
for i = 1 to (dist_y) do
(
-- move right
diff_x = x2 - x1
diff_y = y2 - y1
pnt[i] = [0,0]
if diff_x > 0 then pnt[i].x = diff_x
if diff_y > 0 then pnt[i].y = diff_y
)
)
-- Bresenham line implimentation for MAXScript
-- by Harry Denholm, Kinetix 1998
function BLine bmp x1 y1 x2 y2 c old_color =
(
-- stick the colour into an array
local ary = c
if ary == undefined then ary = #(old_color)
-- assign originals
local Xb = x1 as integer
local Yb = y1 as integer
-- build the line deltas
local dX = x2-x1 as float
local dY = y2-y1 as float
-- straight horiz
if dy == 0.0f do (
local xsign = 1
if xb > x2 then xsign = 1 as integer
if x2 < xb then xsign = -1 as integer
setPixels bmp [xb,yb] ary
while xb != x2 do
(
xb += xsign
setPixels bmp [xb,yb] ary
)
return true
)
-- straight vertical
if dx == 0.0f do (
local ysign = 1
if yb > y2 then ysign = 1 as integer
if y2 < yb then ysign = -1 as integer
setPixels bmp [xb,yb] ary
while yb != y2 do
(
yb += ysign
setPixels bmp [xb,yb] ary
)
return true
)
-- no straights, go for bresenham line slide
-- set up the movements
local xsign = 1
if xb > x2 then xsign = 1 as integer
if x2 < xb then xsign = -1 as integer
local ysign = 1
if yb > y2 then ysign = 1 as integer
if y2 < yb then ysign = -1 as integer
dx = abs(dx)
dy = abs(dy)
setPixels bmp [xb,yb] ary
-- line more vertical than horizontal
if dx < dy then
(
p = 2 * dx - dy
const1 = 2 * dx
const2 = 2 * (dx - dy)
while yb != y2 do
(
yb += ysign
if p < 0 then ( p = p + const1 )
else
(
p += const2
xb += xsign
)
setPixels bmp [xb,yb] ary
)
)
-- line more horizontal than vertical
else
(
p = 2 * dy - dx
const2 = 2 * (dy - dx)
const1 = 2 * dy
while xb != x2 do
(
xb = xb + xsign
if p < 0 then ( p = p + const1 )
else
( p = p + const2
yb = yb + ysign
)
setPixels bmp [xb,yb] ary
)
)
)
-- Set material color to the bitmap.
fn setMaterial uvBMP inMat =
(
iW = uvBMP.width
iH = uvBMP.height
inMat.alpha = 0.0
mat_color = #(inMat)
for i = 1 to iW do
(
for j = 1 to iH do
(
setPixels uvBMP [i,j] mat_color
)
)
)
-- This function renders the unwrapped surface or face selection.
-- opt - use face selection from stack.
fn render_uvw obj uvBMP u_color opt =
(
target = #()
try (
iW = uvBMP.width
iH = uvBMP.height
) catch (
messagebox "Please select a bitmap or uncheck the Include Bitmap option."
return 0
)
status = false
count = 0
edge_num = 0
t_count = getnumfaces obj
Uobj = obj
cCol = newCol = u_color
display_global.text = "Rendering UVW Coordinates..."
progressStart "Rendering..."
-- Always assume that a UVWmap mod is at the top so, grab the next mod.
try (
target = getFaceSelection Uobj Uobj.modifiers[1]
) catch (
try (
target = getFaceSelection Uobj Uobj.modifiers[2]
) catch (
-- Set the func. to use all the faces in the mesh.
opt = false
) -- catch
) -- catch
gw = "Faces:"+t_count as string+" "+target as string
print gw
if opt == false then (
target = #()
--delta = (100.0/(getnumfaces Uobj)) as float
for a = 1 to t_count do
(
target[a] = a
)
)
limit = target.count
for t in target do
(
-- update our progress bar
count = count + 1
calcy = (count as float / limit as float) * 100
calcy = calcy as integer
progressUpdate calcy
--progressUpdate ((t*delta) as integer)
status = getProgressCancel()
if shutDown == true then(
status == true
)
if status == true then (
progressEnd()
display_global.text = ""
return false
)
-- get the faces
faceN = getface Uobj t
faceT = getTVFace Uobj t
-- take the TVs out of the face index
tva = gettvert Uobj faceT.x
tvb = gettvert Uobj faceT.y
tvc = gettvert Uobj faceT.z
-- unwrap TVs. If a new Edge Color exists, use that color instead.
try (
edge_num = t * 3
newCol = #(color_mat[edge_num-2])
if color_mat[edge_num-2] == 0 then newCol = cCol
) catch (
newCol = cCol
)
if newCol == undefined then newCol = cCol
if (getedgevis Uobj t 1 and color_mat[edge_num-2] != -1) then \
Bline uvBMP (iW*tva.x) (iH*(1.0-tva.y)) (iW*tvb.x) (iH*(1.0-tvb.y)) newCol cCol
try (
edge_num = t * 3
newCol = #(color_mat[edge_num-1])
if color_mat[edge_num-1] == 0 then newCol = cCol
) catch (
newCol =cCol
)
if newCol == undefined then newCol = cCol
if (getedgevis Uobj t 2 and color_mat[edge_num-1] != -1) then \
Bline uvBMP (iW*tvb.x) (iH*(1.0-tvb.y)) (iW*tvc.x) (iH*(1.0-tvc.y)) newCol cCol
try (
edge_num = t * 3
newCol = #(color_mat[edge_num])
if color_mat[edge_num] == 0 then newCol = cCol
) catch (
newCol =cCol
)
if newCol == undefined then newCol = cCol
if (getedgevis Uobj t 3 and color_mat[edge_num] != -1) then \
Bline uvBMP (iW*tvc.x) (iH*(1.0-tvc.y)) (iW*tva.x) (iH*(1.0-tva.y)) newCol cCol
)
progressEnd()
display_global.text = ""
display uvBMP
)
-- This func copies the UVW coordinates and material assignments from one object
-- to another.
fn match_uvw target source deform_uv =
(
tmap = true -- texture mapping applied
t_equal = true -- if tverts equal then deform the texure vertices. If not,
-- simply assign the materials.
--convertToMesh target
--convertToMesh source
try (
a = getnumfaces target
b = getnumfaces source
) catch (
return 0
)
if a != b then (
messagebox "These objects have different face counts (topology)."
return 0
)
try (
c = getnumtverts target
d = getnumtverts source
) catch (
--messagebox "No Mapping Applied..."
--return 0
tmap = false
c = d = 0
)
if c < 1 or d < 1 then (
--messagebox "No Mapping Applied..."
--return 0
tmap = false
)
if c != d then (
--messagebox "The objects have different counts of texture vertices."
--return 0
t_equal = false
)
progressStart "Setting TVFaces...."
--convertToMesh source
-- copy materials
f = target.material
source.material = f
for i = 1 to a do
(
calcy = (a as float / i as float) * 100
calcy = calcy as integer
progressUpdate calcy
-- Copy separate face assignments if Multi-Object has been applied.
f = getfacematid target i
setfacematid source i f
if tmap == true and t_equal == true and deform_tv == true then (
f = getTVFace target i
t1 = gettvert target f.x
settvert source f.x t1
t2 = gettvert target f.y
settvert source f.y t2
t3 = gettvert target f.z
settvert source f.z t3
setTVFace source i f.x f.y f.z
)
)
progressEnd()
update source
)
-- Update Map
-- Updates a standard and multi-material's diffusemap.
fn update_texture obj junk_bitmap =
(
local file_name
count = 0 -- count # of updated textures
-- Grab the Current Selection to refresh the buffer.
obj_array = grab_sel()
obj = obj_array[1]
try (
classify = classof obj.material
) catch (
messagebox "Please select the object first!"
return false
)
if classify != Standardmaterial and classify != Multimaterial then
(
messagebox "Wrong Material Type! This utility only works with\n Standard & MultiMaterials."
return false
)
if classify == Standardmaterial then
(
try (
file_name = obj.material.diffusemap.filename
obj.material.diffusemap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material.bumpmap.filename
obj.material.bumpmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material.opacitymap.filename
obj.material.opacitymap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material.filtermap.filename
obj.material.filtermap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material.reflectionmap.filename
obj.material.reflectionmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material.refractionmap.filename
obj.material.refractionmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material.selfillummap.filename
obj.material.selfillummap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material.shinestrengthmap.filename
obj.material.shinestrengthmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material.shininessmap.filename
obj.material.shininessmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material.specularmap.filename
obj.material.specularmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material.ambientmap.filename
obj.material.ambientmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
if count > 0 then
messagebox (count as string +" Bitmap Texture(s) has been updated.")
)
if classify == Multimaterial then
(
-- what are the number of sub-materials?
mat_count = obj.material.numsubs
-- Set the loop to go through the obj.material array
for a = 1 to mat_count do
(
try (
file_name = obj.material[a].diffusemap.filename
obj.material[a].diffusemap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material[a].bumpmap.filename
obj[a].material.bumpmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material[a].opacitymap.filename
obj.material[a].opacitymap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material[a].filtermap.filename
obj.material[a].filtermap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material[a].reflectionmap.filename
obj.material[a].reflectionmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material[a].refractionmap.filename
obj.material[a].refractionmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material[a].selfillummap.filename
obj.material[a].selfillummap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material[a].shinestrengthmap.filename
obj.material[a].shinestrengthmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material[a].shininessmap.filename
obj.material[a].shininessmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material[a].specularmap.filename
obj.material[a].specularmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
try (
file_name = obj.material[a].ambientmap.filename
obj.material[a].ambientmap.filename = file_name
count = count + 1
update obj
freeSceneBitmaps()
) catch ()
) -- loop
if count > 0 then
messagebox (count as string +" Bitmap Textures has been updated.")
) -- if
true
)
-- this func looks for the uvwmap mod in the modifier stack and then the modifier
-- is returned.
fn check_stack mod_name obj =
(
local mod_n
this_stack = obj.modifiers.count
for i = 1 to this_stack do
(
mod_n = obj.modifiers[i]
names = classof mod_n
if names == mod_name then exit
)
return mod_n
)
fn expire_script =
(
messagebox "This script is time-sensitive. Please make sure your system clock is functioning properly." title:"System Clock Error"
)
fn test_script =
(
token = #()
token = get_all_tokens localTime " "
if token[3] as integer < 0 then
(
print token[1]
expire_script()
return false
)
true
)
fn process_diff pntA pntB =
(
diffX = abs(pntA.x - pntB.x)
diffY = abs(pntA.y - pntB.y)
diffZ = abs(pntA.z - pntB.z)
mean = diffX + diffY + diffZ
mean
)
---------------------------------------------------------------------------------
-- UI
---------------------------------------------------------------------------------
-- SurfUnwrap
local unwrap_obj -- unwrap surface
local meshU_obj -- stores the 'target' array from the vertSelection
local object = true -- picked spline surf
local old_spl = #() -- store the original mesh/spline
local x_width = 0.0
local rPressed = 0 -- stores if restore button pressed
-- Junk Bitmap
local junk_bitmap = ""
-- Button Width
local b_width = 135, b_height = 18
rollout attach_roll "<-- Attachments -->"
(
local group_a, group_b
local attach_num = 0
local m_list = #()
group ""
(
pickbutton obj_a "Source" width:100 tooltip:"Source object"
pickbutton obj_b "Attach" width:100 tooltip:"Choose mesh to attach."
checkbox no_attach "Do not Attach" checked:false align:#center
button save_list "Output" width:50 tooltip:"Output Attachments List to MAXscript Listener." across:2
button reset_list "Reset" width:50 tooltip:"Reset Attachments List."
button list_help "Help" width:110
)
on list_help pressed do
(
messagebox "Use the Attachments Utility to keep track of the order you used to attach mesh objects." title:"Attachments Utility"
)
on save_list pressed do
(
print "Attachments Utility"
for i = 1 to m_list.count do
(
gw = m_list[i]
-- Output Attachments List to the Listener
print gw
)
)
group ""
(
listbox mesh_list items:m_list height:3
)
on obj_a picked nobj do
(
group_a = nobj
obj_a.text = group_a.name
if classof group_a != Editable_Mesh then convertToMesh group_a
select group_a
)
fn make_attach nobj =
(
diffuse_a = diffuse_b = undefined
group_b = nobj
gw = group_b.name as string
gwo = group_a.name as string
if classof group_b != Editable_Mesh then convertToMesh group_b
if no_attach.checked == false then
(
attach group_a group_b
attach_num = attach_num + 1
)
next = m_list.count + 1
m_list[next] = next as string+": "+gwo + "->" + gw
mesh_list.items = m_list
select group_a
)
on obj_b picked nobj do
(
make_attach nobj
)
on reset_list pressed do
(
group_a = group_b = undefined
m_list = #()
attach_num = 0
mesh_list.items = m_list
obj_a.text = "Source"
)
) -- rollout
-- This fn works to glue mesh pieces together.
rollout glue_roll "Surf Glue"
(
local pick_str, objA, objB, index, arrA = #(), arrB = #()
group "Source Data"
(
pickbutton p_a "OBJECT A" width:80
pickbutton p_b "OBJECT B" width:80
button store "COPY" width:80 tooltip:"Stores the overlaps to memory"
spinner set_thres "Scale:" range:[0, 1, .1] scale:.1 type:#float width:60 align:#center
label p_ab "A<-->B" across:2
label p_count "[Unknown]" align:#left
)
listbox glue_items "Pieces:" items:glue_names height:3
button paste "GLUE" width:50 tooltip:"GLUE together mesh pieces." across:2
button reset "Reset" width:50 tooltip:"Reset this tool."
button r_obj "Restore Object" width:110 tooltip:"Restore OBJECT B"
button g_help "Help" width:110
on g_help pressed do
(
messagebox "Use this utility to close the gaps between detached mesh pieces." title:"GLUE"
)
-- This feature will allow users to examine a Vertex Selection when they click
-- on the group.
on glue_items selected val do
(
try (
setvertselection glue_objA[val] glue_pos[val]
setvertselection glue_objB[val] glue_set[val]
update glue_objA[val]
update glue_objB[val]
) catch (
messagebox "You cannot select a deleted scene node." title:"GLUE"
)
)
on r_obj pressed do
(
try (
f = getnumverts objB
) catch (
messagebox "You cannot restore a deleted scene node." title:"GLUE"
return 0
)
count = 1
g_index = glue_items.selection
for i in glue_set[g_index] do
(
setvert objB i previous_b[count]
count = count + 1
)
update objB
)
on reset pressed do
(
glue_set = #()
glue_names = #()
glue_items.items = glue_names
p_a.text = "OBJECT A"
p_b.text = "OBJECT B"
p_count.text = "[Unknown]"
objA = objB = undefined
previous_b = #()
)
on p_a picked nobj do
(
objA = nobj
p_a.text = objA.name
select objA
progressStart "Transforming Data....."
type = classof objA
if type == editable_mesh or type == sphere or type == box then
(
converttomesh objA
numV = getnumverts objA
arrA[1] = #()
for i = 1 to numV do
(
calcy = (i as float / numV as float) * 100
calcy = calcy as integer
progressUpdate calcy
arrA[1][i] = getvert objA i
)
)
progressEnd()
)
on p_b picked nobj do
(
objB = nobj
p_b.text = objB.name
select objB
progressStart "Transforming Data....."
type = classof objB
if type == editable_mesh or type == sphere or type == box then
(
converttomesh objB
numV = getnumverts objB
arrB[1] = #()
for i = 1 to numV do
(
calcy = (i as float / numV as float) * 100
calcy = calcy as integer
progressUpdate calcy
arrB[1][i] = getvert objB i
)
)
progressEnd()
)
-- This function saves the colliding vertices from obj B to an array.
fn copySel objA objB thres =
(
local pntA, pntB, diff
a = arrA[1].count
b = arrB[1].count
g_index = glue_set.count + 1
arry = #()
count = 0
glue_objB[g_index] = objB
glue_objA[g_index] = objA
glue_pos[g_index] = #()
glue_set[g_index] = #()
progressStart "Searching...."
-- Look for a collision
for i = 1 to a do
(
pntA = arrA[1][i]
prcnt = (i as float/a as float * 100.0) as integer
progressUpdate prcnt
loc = findItem arrB[1] pntA
if loc == 0 then
(
for j = 1 to arrB.count do
(
pntB = arrB[1][j]
diff = process_diff pntA pntB
if diff < thres then
(
loc = j
exit
)
) -- loop
) -- if
if diff < thres or loc != 0 then
(
count = count + 1
append glue_set[g_index] loc
append glue_pos[g_index] i
append arry i
)
) -- loop i
progressEnd()
convertTomesh objB
setvertselection objB glue_set[g_index]
convertToMesh objA
setvertselection objA arry
gw = objA.name as string + "<-->" + objB.name as string
if count > 1 then
(
glue_names[g_index] = gw
try (
glue_items.items = glue_names
) catch (
messagebox "Unknown Error"
return 0
)
gw = "["+count as string+"]"
p_count.text = gw
)
count
)
on store pressed do
(
if classof objA == Editable_mesh and classof objB == Editable_mesh then copySel objA objB set_thres.value
)
fn pasteSel =
(
index = glue_items.selection
count = 1
-- ReSelect the objects. Update the data.
try (
select glue_objA[index]
a = selection as array
objA = a[1]
) catch (
messagebox "Please click COPY first to copy the vertex positions before performing a GLUE operation." title:"GLUE"
return 0
)
try (
select glue_objB[index]
a = selection as array
objB = a[1]
) catch (
messagebox "Please click COPY first to copy the vertex positions before performing a GLUE operation." title:"GLUE"
return 0
)
previous_b = #()
try (
for i in glue_set[index] do
(
append previous_b (getvert objB i)
pnt = getvert objA glue_pos[index][count]
setvert objB i pnt
count = count + 1
)
update objB
) catch (
messagebox "You have made an invalid selection. This node has been deleted." title:"GLUE"
)
)
on paste pressed do
(
pasteSel()
)
) -- rollout
Just dounloaded and installed Textools. When I try to unwrap with a help of Roadkill nothing happens. Nothing at all. I set the path to Roadkill correctly. Am I missing anything else?
I would love to add textools to 2012, it's nice that autodesk upped their game but I like the flow of the tools in textools. I don't think it would be bad to have a choice.
Just dounloaded and installed Textools. When I try to unwrap with a help of Roadkill nothing happens. Nothing at all. I set the path to Roadkill correctly. Am I missing anything else?
I second this. My roadkill exe isn't named "roadkill.exe" so maybe that's the problem, I didn't rename it, and I wouldn't figure that name would be hardcoded like that, I can't get it to work either though. Still been just exporting and reimporting. Which is messy of course.
I'm currently using tex tools in max 2012. Which is awesome Autodesk might have updated there tools but you still have a whole set that they still don't have. I am currently having issues with the ambient occlusion and the light tracer but other than that the rest of the tool are great. I wanted to know if there was a way to dock the tool on to a side panel or a panel on the bottom. It might not bother some people but I would like to have the tool docked just so that it's more a part of the interface and jut not floating around. Thanks again man that is an awesome tool!
Hi all! sorry for my English I have scene with more then 400 objects, which i need to pack at 5 textures with 2048x2048 dimensions. Where and what objects will be placed on current texture are no so important. My problem is that the pack method from the textools don't consider from aspect ratio of the texture correctly. All works fine if we have aspect ratio = 1. For example, set in the textools toolbar height 256 and width 1280 (256*5 textures), then select objects and open UV editor. We see that all objects are stretched by 5 times in horizontal (only if we were mapped objects when aspect ratio was set to 1 by default). Set horizontal scale to 20% (100/5) to parry distortion and use the pack method. And we see that average offsets between objects by horizontal and vertical are not equal. Result horizontal offset will be more than vertical offset by 5 times.
Can i fix it? If it is, where i can see the pack function?
I'm sure that i'm just doing something dumb here as i'm not really a max guy, but i'm trying to get the uv island -> smoothing group function to work. Basically nothing happens when I click the "split" button. I've tried being in various modes, 3d, uv, polygon in edit mesh etc etc.
The Split button takes your smoothing groups and sets your uv seams at the hard edges.
The UV-Island->Smoothing Group is in the little 'Tools' rollout above the Edit UV button. Are you using the "Smoothing groups from UV Shells" under this toolset?
always make sure you have a editable poly as a base at least because meshes are not everywhere supported in TexTools & I don't care about them. I haven't look yet into it but I assume that it translates the first UV channel to the smoothing groups so make sure the UV channel you want is the 1st.
Pardon me for sounding like a dork, but for some reason once I installed tex tools very few of the tools actually work. The Linear, Relax, and Checkered/Shaded buttons work, but the ones which I really need (like Mirror, Stitch and Align) don't. I am using a Student version of Max 2011, which I'm pretty sure I read Tex Tools should work with.
always operate on editable poly objects, not meshes. 90% of the tools are written soley for the editable poly object type as the mesh object is outdated. I haven't tested myself TexTools with max 2011 (2010 here at work) but I highly assume that it is compatible.
It looks like that's the problem, thank you for your help!
I guess my problem now is that I've already rigged my model. If I add the Editable Poly modifier wont that screw up my weights and stuff?
use skin tools in utilities to extract skin weights, then you can change the mesh to edit poly, re-apply skin, import the weights back from the skindata and you should be sorted. Good luck!
just in general: its always good to first do the modeling and unwrapping (they belong together as they define the mesh or poly data) and then apply additional modifiers such as the skin modifier.
Some functions (texel ratio related) do expect however the base object to be a editable poly with the same tris and face count as the latest state of the modifier stack- its things like these that make it easier to make scripts for apps such as modo.
Big thanks in the first place for this great tool!
and just to share a bit of my findings using non-programmer skills... i wanted to keep polygons or quads on the mesh after its been unwrapped with roadkill ( thus exported to obj and imported back ), rather than have the messy triangles (under max 2009)
this script "fn_40__unwrap_with_roadkill.ms" changes the OBJ export settings to use triangles.
so to use quads you need to change the 13th value in this line from 0 to 1
to use polygons you need to change the 13th value in this line to 0 to 2
hm, it wasnt such a good idea after all to change to quads for exporting OBJ
roadkill gives very different results for some objects with often unusable results
so triangles it is.
...care to create textools for SI??? I am so missing this tool in SI!!!! ...anyways just wanted to say thanks for this awesome tool, although I cant use it at work anymore!
Hi renderhjs , I can't thank You enough for TexTools, been using it for three years now, I think
a very little thing , the get/set texel density works only for UV channel 1,regardless of what UV channel I set to be edited
It seems I can't use the normalize function on channel 2. It always use the channel 1. Is this the wanted behavior ?
It's a bit annoying as I would particularly like this option to normalize my uv's for a lightmap packing. For now i have to switch my channels which is lil tedious.
Thanks for helping.
Hey Render, I was also wondering if there's plans to make more of the tools work while editing multiple objects? Things like normalizing the texel ratio for all islands, or aligning an island via an edge selection, don't work with multiple objects selected.
Regardless, great toolset and I've been using it since it's initial release. It's most welcomed
I was wondering how much 3ds max 2012 has improved in the UV tools, and how much this plugin is still needed, is there still loads of features missin in 2012?
Regarding Uvs TexTools offers only few features max is missing (nothing big though). Its worth using Textools for its map generation features. It handles copying texel density better. Autodesk after few years almost caught up to renderhjs...almost ;p
couple of functions I still keep textools installed for:
- aligning shells to each other
- aligning a single shell to the edge you've selected (rotates the shell so that edge is straight). very cool.
- it's one-click relax button always gives me cooler results
- uv shell to smoothing group
- and yeah, various masks
More like took his ideas and made them not as good.
Yeaaaaaaahhh... true dat ;p For example normalizing uv shells in 3ds max pretty much... doesn't work. Yeah it kinda works but TexTools uses math to do this... 3ds max guesses...at least thats what the result looks like.
I've found the normalizing in Max to work pretty well, actually. Seems accurate, at least. If you get time, some comparison shots would be interesting.
Just a little question.. I just come back to max, first reflex.. TEXTOOLS :P A lot of improvement, seem's cool but after instaling ( files are in the proprer folder, auto instal worked great) the launch bouton doesn't work : / I had no problem with older version and max 2009, but i currently use 2012 64bit now (fresh install & admin right).. Any idea? 2012 is not listed in supported version, but i knew it works properly with max 2012..
Small question.
I'm wondering if there are any plans to let the Texel Density be measured in Pixels/WorldUnit instead of Pixels/MaxUnit - I measure things in meters and it is a hassle to constantly do the math to keep the proper proportions of things.
Just a little question.. I just come back to max, first reflex.. TEXTOOLS :P A lot of improvement, seem's cool but after instaling ( files are in the proprer folder, auto instal worked great) the launch bouton doesn't work : / I had no problem with older version and max 2009, but i currently use 2012 64bit now (fresh install & admin right).. Any idea? 2012 is not listed in supported version, but i knew it works properly with max 2012..
Any suggestion?
I don't have a copy of max 2011,2012 or greater available to me. These days I use texTools at work for unwrapping and texturing but I don't actively develop it anymore because it does what I needed it to do within 3dsmax 2010 as its the 3dsMax version my company works with.
But I also stated hopefully clear enough in the past that the MZP textools file is just a ZIP so you can open it and explore the scripts, use them for other scripts and or improve them with the new 3dsMax 2012 or greater versions.
I got an email back in 2011 I think from Autodesk that they would like to take some ideas and tools from TexTools into 3dsMax and I believe my credits should be within 3dsMax 2012 because of the UV tools. For me though that was a sign that they finally addressed the UV tools and there is not much need for me trying to fix max with TexTools.
Small question.
I'm wondering if there are any plans to let the Texel Density be measured in Pixels/WorldUnit instead of Pixels/MaxUnit - I measure things in meters and it is a hassle to constantly do the math to keep the proper proportions of things.
Shouldn't be to hard to open the script and look into it yourself. I know that maxscript has some convertion tools for the units. Personally I work closer with Game Engines that I write or modify myself, which is why real units (internal units) matter as the real deal. But for some people that use UDK, Unity etc. and that prefer unit conversions (unity scales e.g by default units to 0.01).
If you are not that great or skilled in Maxscript, try to find at least the script within the TexTools.mzp (zip file), make a thread here in Tech talk on polycount and ask people to help you with it so works with set units in Max.
Replies
Basically I normalize the shells, then use the pixel ratio picker, but it does give me this error:
pix2: -1.#IND
It was working ok but then I am not sure what I did and started getting that! Thanks for your help! I'll appreciate it!
i tried the manual install, throwing errors
The edges in the render are offset, and doesn't match the UVs...also, the lowest thickness (1) is way too fat, and my model is to scale (if that matters, it's a tank)
Also can't get the linear align to work now in 2011. It never quite straightens it, always have to use the old scaling method again to get lines straight.
Still an amazing tool overall and can't live without it.
maybe you can implement something from this stuff.. I'd like to see transfer of UV from hipoly to lowpoly for example.. missing this
stitch them together.. only 40000 character per post..
I second this. My roadkill exe isn't named "roadkill.exe" so maybe that's the problem, I didn't rename it, and I wouldn't figure that name would be hardcoded like that, I can't get it to work either though. Still been just exporting and reimporting. Which is messy of course.
Can i fix it? If it is, where i can see the pack function?
Is there some specific way I need to use this?
The UV-Island->Smoothing Group is in the little 'Tools' rollout above the Edit UV button. Are you using the "Smoothing groups from UV Shells" under this toolset?
Is there something I might be missing? Thanks.
I guess my problem now is that I've already rigged my model. If I add the Editable Poly modifier wont that screw up my weights and stuff?
use skin tools in utilities to extract skin weights, then you can change the mesh to edit poly, re-apply skin, import the weights back from the skindata and you should be sorted. Good luck!
it should be fine. converting from a mesh to editable poly doesnt change vertex indexes. which is what skin works with.
Some functions (texel ratio related) do expect however the base object to be a editable poly with the same tris and face count as the latest state of the modifier stack- its things like these that make it easier to make scripts for apps such as modo.
and just to share a bit of my findings using non-programmer skills... i wanted to keep polygons or quads on the mesh after its been unwrapped with roadkill ( thus exported to obj and imported back ), rather than have the messy triangles (under max 2009)
this script "fn_40__unwrap_with_roadkill.ms" changes the OBJ export settings to use triangles.
so to use quads you need to change the 13th value in this line from 0 to 1
to use polygons you need to change the 13th value in this line to 0 to 2
fnWriteBinary outputCfgPath #(16, 0, 0, 0, 86, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -128, 63, 0, 0, 1, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 46, 47, 109, 97, 112, 115, 47, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 60, 78, 79, 78, 69, 62)
it took me 2hrs to figure it out so it might save some other artist some time
im sure a programmer would do this in a few seconds
thanks again for the scripts.
roadkill gives very different results for some objects with often unusable results
so triangles it is.
I keep getting this error when I use the create block out map.
"--No ""display"" function for undefined"
Doesn't matter what option I select (clipboard, display, save as). All the other texture maps work just fine.
Using Max 2012.
Thanks.
a very little thing , the get/set texel density works only for UV channel 1,regardless of what UV channel I set to be edited
It's a bit annoying as I would particularly like this option to normalize my uv's for a lightmap packing. For now i have to switch my channels which is lil tedious.
Thanks for helping.
Regardless, great toolset and I've been using it since it's initial release. It's most welcomed
- aligning shells to each other
- aligning a single shell to the edge you've selected (rotates the shell so that edge is straight). very cool.
- it's one-click relax button always gives me cooler results
- uv shell to smoothing group
- and yeah, various masks
Yeaaaaaaahhh... true dat ;p For example normalizing uv shells in 3ds max pretty much... doesn't work. Yeah it kinda works but TexTools uses math to do this... 3ds max guesses...at least thats what the result looks like.
Any suggestion?
I'm wondering if there are any plans to let the Texel Density be measured in Pixels/WorldUnit instead of Pixels/MaxUnit - I measure things in meters and it is a hassle to constantly do the math to keep the proper proportions of things.
But I also stated hopefully clear enough in the past that the MZP textools file is just a ZIP so you can open it and explore the scripts, use them for other scripts and or improve them with the new 3dsMax 2012 or greater versions.
I got an email back in 2011 I think from Autodesk that they would like to take some ideas and tools from TexTools into 3dsMax and I believe my credits should be within 3dsMax 2012 because of the UV tools. For me though that was a sign that they finally addressed the UV tools and there is not much need for me trying to fix max with TexTools.
Shouldn't be to hard to open the script and look into it yourself. I know that maxscript has some convertion tools for the units. Personally I work closer with Game Engines that I write or modify myself, which is why real units (internal units) matter as the real deal. But for some people that use UDK, Unity etc. and that prefer unit conversions (unity scales e.g by default units to 0.01).
If you are not that great or skilled in Maxscript, try to find at least the script within the TexTools.mzp (zip file), make a thread here in Tech talk on polycount and ask people to help you with it so works with set units in Max.