ola!!! hey, i have a quick question about floating geo for normal maps. i understand how it works technically. i'm just wondering how you guys go about setting the floaty bits up. i mean how exactly do you specify the orientation of the floaty bits for the normals to read right?
oh and i'm using max 8. the main reason i'm wondering is for multiple small parts. like rivets and stuff.
thanks...sorry for all the questions. i looked it up but get lots of links to "floating point calculations". haha.
cheers!!!
Replies
cheers!!!
<font class="small">Code:</font><hr /><pre> offsetY = 20
globalZero = Point3 0 0 0
globalFirstHit = TRUE
globalDistNode = #(undefined,undefined,undefined)
globalDistNodeMirror = #(undefined,undefined,undefined)
globalHairCopy = #(undefined,undefined,undefined)
globalHairCopyMirror = #(undefined,undefined,undefined)
globalLastNode = #(undefined,undefined,undefined)
globalLastNodeMirror = #(undefined,undefined,undefined)
globalLastPos = #(undefined,undefined,undefined)
globalLastNormal = #(undefined,undefined,undefined)
globalLastPosMirror = #(undefined,undefined,undefined)
globalLastNormalMirror = #(undefined,undefined,undefined)
globalLastStr = 1
globalLastRadius = 1
globalUseDist = #(FALSE,FALSE,FALSE)
globalHairPos = #(globalZero,globalZero,globalZero )
globalHairNormal = #(globalZero,globalZero,globalZero)
globalHairPosMirror = #(globalZero,globalZero,globalZero )
globalHairNormalMirror = #(globalZero,globalZero,globalZero)
globalAlignNormal = 3
globalAlignStroke = 1
globalScaleOption = 1
globalScaleNormal = TRUE
globalScaleStroke = TRUE
globalScaleStrength = TRUE
globalScaleX = 1.0
globalScaleY = 1.0
globalScaleZ = 1.0
globalSourceNode = #()
globalInstance = FALSE
matrix3 fn GetMatrix hairPos mousePos normal str radius =
(
tm = matrix3 1
strNormal = 1
normalBase = 1
strengthBase = 1
strokeBase = 1
strStroke = 1
strStrength = 1
xvec = Point3 1 0 0
yvec = Point3 0 1 0
zvec = Point3 0 0 1
mouseVec = Point3 1 0 0
zvec = normalize normal
mouseVec = mousePos - hairPos
mouseVec = normalize mouseVec
xvec = cross mouseVec zvec
xvec = Normalize xvec
yvec = cross zvec xvec
yvec = normalize yvec
if (globalScaleOption == 1) then
(
)
else if (globalScaleOption == 2) then
(
str = globalScaleX
if (globalScaleY > str) then str = globalScaleY
if (globalScaleZ > str) then str = globalScaleZ
str = Length(mousePos - hairPos)/str
xvec = xvec * str
yvec = yvec * str
zvec = zvec * str
)
else if (globalScaleOption == 3) then
(
if (globalScaleNormal) then
(
strNormal = str*thePainterInterface.normalScale
if (globalAlignNormal == 1) then
normalBase = globalScaleX
else if (globalAlignNormal == 2) then
normalBase = globalScaleY
else if (globalAlignNormal == 3) then
normalBase = globalScaleZ
strNormal = strNormal/normalBase
zvec = zvec * strNormal
)
if (globalScaleStroke) then
(
strStroke = Length(mousePos - hairPos)
if (globalAlignStroke == 1) then
strokeBase = globalScaleX
else if (globalAlignStroke == 2) then
strokeBase = globalScaleY
else if (globalAlignStroke == 3) then
strokeBase = globalScaleZ
strStroke = strStroke/strokeBase
yvec = yvec * strStroke
)
if (globalScaleStrength) then
(
strStrength = radius
if (globalAlignStroke == 1)then
(
if (globalAlignNormal == 2)then
strengthBase = globalScaleZ
else if (globalAlignNormal == 3)then
strengthBase = globalScaleY
)
else if (globalAlignStroke == 2)then
(
if (globalAlignNormal == 1)then
strengthBase = globalScaleZ
else if (globalAlignNormal == 3)then
strengthBase = globalScaleX
)
if (globalAlignStroke == 3)then
(
if (globalAlignNormal == 1)then
strengthBase = globalScaleY
else if (globalAlignNormal == 2)then
strengthBase = globalScaleX
)
strStrength = strStrength/strengthBase
xvec = xvec * strStrength
)
)
if (globalAlignNormal == 1) then
(
tm.row3 = xvec
if (globalAlignStroke == 2) then
(
tm.row1 = yvec
tm.row2 = zvec
)
else
(
tm.row1 = zvec
tm.row2 = yvec
)
)
else if (globalAlignNormal == 2) then
(
tm.row3 = yvec
if (globalAlignStroke == 1) then
(
tm.row1 = xvec
tm.row2 = zvec
)
else
(
tm.row1 = zvec
tm.row2 = xvec
)
)
else
(
tm.row3 = zvec
if (globalAlignStroke == 1) then
(
tm.row1 = yvec
tm.row2 = xvec
)
else
(
tm.row1 = xvec
tm.row2 = yvec
)
)
tm.row4 = hairPos
return tm
)
fn StartStroke =
(
globalFirstHit = TRUE
thePainterInterface.undoStart()
)
fn PlaceStroke =
(
localHit = Point3 0 0 0
localNormal = Point3 0 0 0
worldHit = Point3 0 0 0
worldNormal = Point3 0 0 0
str = 0.0f
radius = 0.0f
if (globalFirstHit == TRUE) then
(
globalFirstHit = FALSE
undo on
(
for i = 1 to 3 do
(
if (globalUseDist) then
(
if (globalInstance) then globalHairCopy = instance globalDistNode
else globalHairCopy = copy globalDistNode
thePainterInterface.getHitPointData &localHit &localNormal &worldHit &worldNormal &radius &str 0
globalHairPos = worldHit
globalHairNormal = worldNormal
if (thePainterInterface.mirrorEnable == TRUE) then
(
if (globalInstance) then globalHairCopyMirror = instance globalDistNode
else globalHairCopyMirror = copy globalDistNode
thePainterInterface.getMirrorHitPointData &localHit &localNormal &worldHit &worldNormal 0
globalHairPosMirror = worldHit
globalHairNormalMirror = worldNormal
)
)
)
)
)
--retrieves the last hit point
thePainterInterface.getHitPointData &localHit &localNormal &worldHit &worldNormal &radius &str 0
--This gets whether the stroke point actually hit the mesh
--Since the user can paint off the mesh
--Right now we ignore this and create a cylinder regardless if they are painting on the mesh or not
hit = thePainterInterface.getIsHit -1
thePainterInterface.offMeshHitPos = globalHairPos[1]
for i = 1 to 3 do
(
if (globalUseDist) then
(
globalScaleX = abs (globalDistNode.max[1] - globalDistNode.pos[1])
globalScaleY = abs (globalDistNode.max[2] - globalDistNode.pos[2])
globalScaleZ = abs (globalDistNode.max[3] - globalDistNode.pos[3])
minScaleX = abs (globalDistNode.min[1] - globalDistNode.pos[1])
minScaleY = abs (globalDistNode.min[2] - globalDistNode.pos[2])
minScaleZ = abs (globalDistNode.min[3] - globalDistNode.pos[3])
if (minScaleX > globalScaleX) then globalScaleX = minScaleX
if (minScaleY > globalScaleY) then globalScaleY = minScaleY
if (minScaleZ > globalScaleZ) then globalScaleZ = minScaleZ
tm = matrix3 1
globalHairCopy.transform = GetMatrix globalHairPos worldHit globalHairNormal str radius
--checks if the mirror is on, if so make sure to get that point and proces it also
if (thePainterInterface.mirrorEnable == TRUE) then
(
-- Put mirror stuff here
thePainterInterface.getMirrorHitPointData &localHit &localNormal &worldHit &worldNormal 0
globalHairCopyMirror.transform = GetMatrix globalHairPosMirror worldHit globalHairNormalMirror str radius
)
)
)
)
fn PaintStroke =
(
localHit = Point3 0 0 0
localNormal = Point3 0 0 0
worldHit = Point3 0 0 0
mirrorWorldHit = Point3 0 0 0
worldNormal = Point3 0 0 0
str = 0.0f
radius = 0.0f
for i = 1 to 3 do
(
if (globalUseDist) then
(
if (globalInstance) then globalHairCopy = instance globalDistNode
else globalHairCopy = copy globalDistNode
thePainterInterface.getHitPointData &localHit &localNormal &worldHit &worldNormal &radius &str 0
globalHairPos = worldHit
globalHairNormal = worldNormal
if (thePainterInterface.mirrorEnable == TRUE) then
(
if (globalInstance) then globalHairCopyMirror = instance globalDistNode
else globalHairCopyMirror = copy globalDistNode
thePainterInterface.getMirrorHitPointData &localHit &localNormal &worldHit &worldNormal 0
globalHairPosMirror = worldHit
globalHairNormalMirror = worldNormal
)
)
)
--retrieves the last hit point
thePainterInterface.getHitPointData &localHit &localNormal &worldHit &worldNormal &radius &str 0
--This gets whether the stroke point actually hit the mesh
--Since the user can paint off the mesh
--Right now we ignore this and create a cylinder regardless if they are painting on the mesh or not
hit = thePainterInterface.getIsHit -1
thePainterInterface.offMeshHitPos = globalHairPos[1]
for i = 1 to 3 do
(
if (globalUseDist) then
(
globalScaleX = abs (globalDistNode.max[1] - globalDistNode.pos[1])
globalScaleY = abs (globalDistNode.max[2] - globalDistNode.pos[2])
globalScaleZ = abs (globalDistNode.max[3] - globalDistNode.pos[3])
minScaleX = abs (globalDistNode.min[1] - globalDistNode.pos[1])
minScaleY = abs (globalDistNode.min[2] - globalDistNode.pos[2])
minScaleZ = abs (globalDistNode.min[3] - globalDistNode.pos[3])
if (minScaleX > globalScaleX) then globalScaleX = minScaleX
if (minScaleY > globalScaleY) then globalScaleY = minScaleY
if (minScaleZ > globalScaleZ) then globalScaleZ = minScaleZ
tm = matrix3 1
projVec = Point3 0 0 1
if (thePainterInterface.getHitCount() > 1) then projVec = worldHit + (worldHit - globalLastPos)
else projVec = worldHit
globalHairCopy.transform = GetMatrix globalHairPos projVec globalHairNormal str radius
--checks if the mirror is on, if so make sure to get that point and proces it also
if (thePainterInterface.mirrorEnable == TRUE) then
(
-- Put mirror stuff here
thePainterInterface.getMirrorHitPointData &localHit &localNormal &mirrorWorldHit &worldNormal 0
if (thePainterInterface.getHitCount() > 1) then projVec = mirrorWorldHit + (mirrorWorldHit - globalLastPosMirror)
else projVec = mirrorWorldHit
globalHairCopyMirror.transform = GetMatrix globalHairPosMirror projVec globalHairNormalMirror str radius
)
)
)
if (thePainterInterface.getHitCount() > 1) then
(
for i = 1 to 3 do
(
if (globalUseDist) then
(
globalLastNode.transform = GetMatrix globalLastPos worldHit globalLastNormal globalLastStr globalLastRadius
if (thePainterInterface.mirrorEnable == TRUE) then
(
globalLastNodeMirror.transform = GetMatrix globalLastPosMirror mirrorWorldHit globalLastNormalMirror globalLastStr globalLastRadius
)
)
)
)
for i = 1 to 3 do
(
if (globalUseDist) then
(
globalLastNode = globalHairCopy
globalLastNodeMirror = globalHairCopyMirror
globalLastPos = globalHairPos
globalLastNormal = globalHairNormal
globalLastPosMirror = globalHairPosMirror
globalLastNormalMirror = globalHairNormalMirror
globalLastStr = str
globalLastRadius = radius
)
)
)
fn CancelStroke =
(
thePainterInterface.undoCancel()
)
fn EndStroke =
(
thePainterInterface.undoAccept()
)
fn systemEnd =
(
PaintHairRollout.PaintButton.checked = off
PaintHairRollout.PlaceButton.checked = off
)
rollout PaintHairRollout "Paremeters" width:211 height:300
(
Button SourceButton "Set Sel. As Source" pos:[86,10] width:101 height:24
label SourceObject "Source Object" pos:[11,16] width:72 height:15
pickButton Dist1Button "Pick Distribution 1" pos:[86,41] width:101 height:24
pickButton Dist2Button "Pick Distribution 2" pos:[86,70] width:101 height:24
pickButton Dist3Button "Pick Distribution 3" pos:[86,101] width:101 height:24
checkbox UseDist1 "Use As Dist" pos:[7,45] width:76 height:15
checkbox UseDist2 "Use As Dist" pos:[7,74] width:76 height:15
checkbox UseDist3 "Use As Dist" pos:[7,104] width:76 height:15
checkButton PlaceButton "Place" pos:[7,135] width:104 height:24
checkButton PaintButton "Paint" pos:[7,163] width:104 height:24
button Options "..." pos:[113,135] width:41 height:24
checkbox UseInstance "Instance Copies" pos:[7,193] width:120 height:15
label Align "Align Objects " pos:[2,198+offsetY] width:66 height:15
label Align2 " Axis To Normal " pos:[108,198+offsetY] width:92 height:15
dropDownList AlignNormal "" pos:[72,198+offsetY] width:37 height:21 items:#("X", "Y", "Z") selection:3
label Align3 "Align Objects " pos:[2,222+offsetY] width:66 height:15
label Align4 " Axis To Stroke " pos:[108,222+offsetY] width:92 height:15
dropDownList AlignStroke "" pos:[72,222+offsetY] width:37 height:21 items:#("X", "Y", "Z") selection:1
label Align5 "Scale Options " pos:[2,246+offsetY] width:66 height:15
dropDownList ScaleOptions "" pos:[72,246+offsetY] width:100 height:21 items:#("None", "Uniform Scale", "Custom Scale") selection:1
checkbox chkScaleNormal "Scale Based On Normal" pos:[28,272+offsetY] width:145 height:22 checked:true
checkbox chkScaleStroke "Scale Based On Stroke" pos:[28,292+offsetY] width:145 height:22 checked:true
checkbox chkScaleStrength "Scale Based On Strength" pos:[28,312+offsetY] width:145 height:22 checked:true
on SourceButton pressed do
(
globalSourceNode = $
)
on Dist1Button picked obj do
(
globalDistNode[1] = obj
Dist1Button.text = obj.name
UseDist1.checked = TRUE
globalUseDist[1] = TRUE
)
on Dist2Button picked obj do
(
globalDistNode[2] = obj
Dist2Button.text = obj.name
UseDist2.checked = TRUE
globalUseDist[2] = TRUE
)
on Dist3Button picked obj do
(
globalDistNode[3] = obj
Dist3Button.text = obj.name
UseDist3.checked = TRUE
globalUseDist[3] = TRUE
)
on UseDist1 changed state do
globalUseDist[1] = state
on UseDist2 changed state do
globalUseDist[2] = state
on UseDist3 changed state do
globalUseDist[3] = state
on UseInstance changed state do
globalInstance = state
on PlaceButton changed state do
(
if (PaintButton.checked) then
(
PaintButton.checked = FALSE
thePainterInterface.EndPaintSession()
)
if thePainterInterface.InPaintMode() then
(
PlaceButton.checked = FALSE
thePainterInterface.EndPaintSession()
)
else
(
PaintButton.checked = FALSE
PlaceButton.checked = TRUE
thePainterInterface.initializeNodes 0 globalSourceNode
thePainterInterface.pointGatherEnable = FALSE
thePainterInterface.buildNormals = TRUE
thePainterInterface.offMeshHitType = 2
thePainterInterface.drawTrace = FALSE
thePainterInterface.ScriptFunctions startStroke placeStroke endStroke cancelStroke systemEnd
thePainterInterface.startPaintSession()
)
)
on PaintButton changed state do
(
if (PlaceButton.checked) then
(
PlaceButton.checked = FALSE
thePainterInterface.EndPaintSession()
)
if thePainterInterface.InPaintMode() then
(
PaintButton.checked = FALSE
thePainterInterface.EndPaintSession()
)
else
(
PaintButton.checked = TRUE
thePainterInterface.initializeNodes 0 globalSourceNode
thePainterInterface.pointGatherEnable = FALSE
thePainterInterface.buildNormals = TRUE
thePainterInterface.offMeshHitType = 2
thePainterInterface.drawTrace = FALSE
thePainterInterface.ScriptFunctions startStroke paintStroke endStroke cancelStroke systemEnd
thePainterInterface.startPaintSession()
)
)
On Options pressed do
(
thePainterInterface.paintOptions()
)
on AlignNormal selected sel do
(
globalAlignNormal = sel
)
on AlignStroke selected sel do
(
globalAlignStroke = sel
)
on ScaleOptions selected sel do
(
globalScaleOption = sel
)
on chkScaleNormal changed state do
globalScaleNormal = state
on chkScaleStrength changed state do
globalScaleStrength = state
on chkScaleStroke changed state do
globalScaleStroke = state
on PaintHairRollout oktoclose do
(
thePainterInterface.endPaintSession()
)
)
-- create the rollout window and add the rollout
if FloaterExampleFloater != undefined do
(
closerolloutfloater FloaterExampleFloater
)
Floater = newRolloutFloater "Paint Hair Floater" 220 425
addRollout PaintHairRollout Floater
</pre><hr />
i'm trying the normal align tool in max...but i can't seem to get anything to "align" the normal.
[/ QUOTE ]
Normal align works by aligning one normal on one object to the normal on another object.
To use it you:
- Select the object to be aligned
- then click on the normal align tool
- then click on a face on the object you want to align. This will display a small stick which shows you what the 1st normal is. You can hold down your mouse button to change the sample position of this normal interactively.
- Now click on a face that you want to align the 1st normal to. Again this will show you a small stick that is the 2nd normal and you can move it around by holding down your mouse.
- when this happens you'll get a dialog that asks if you want to do further transforms to your object (you can rotate it for example or use the reverse of the 1st normal)
So for example you could align a cylinder to a sphere by clicking on the bottom of the cylinder with the normal align tool and then clicking on the surface of the sphere and selecting 'invert normals'.
And that's how it works