[Closed] Faces <-> vertices + angles between faces
I want to figure out
- Which faces of the selected object are being formed by which vertices
- What are the angles between faces of the selected object
Please share a maxscript snippet.
– I want to figure out:
1. Which faces of the selected object are being formed by which vertices
2. What are the angles between faces of the selected object
Verstanden?
- Jawohl, mein lieber Freund!
- See GetFace or GetVertsUsingFace to get a set of verts making the face;
- It’s a arc-cosine of dot product of two face normals. See GetFaceNormal and dot…
Capiche?
- See GetFace or GetVertsUsingFace to get a set of verts making the face;
- It’s a arc-cosine of dot product of two face normals. See GetFaceNormal and Dot…
Nice.
Capiche?
No ;(
Verstanden? Jawohl!
Are you nazi?
If you’re the same guy that asked this:
http://stackoverflow.com/questions/8784168/which-points-in-3d-space-form-which-face-angle-between-faces
Then I’ve answered your question there.
IIRC one issue with the normal method it won’t tell you if the angle between faces is obtuse or reflex
my methodology is therefore
convert to or create a copy as a trimesh
create a list of all internal edges
remove all the duplicate reverse edges from the list
for all edges in the list
get the 2 faces that share this edge
create a coordinate system based on face1
transform the spare vert in face2 into this system
if the spare vert z is +ve the angle is obtuse else its reflex
compute the angle as above
Unfortunately I am not as experienced in coding as you are. Can you share this as code I could use, please? All I know is that I am using an editable poly right now.
heres a script i wrote a long time ago that uses the method I described above, it renders edges to a bitmap dependent on edge angles, though you should try and work it out for yourself you will learn more that way.
macroScript Edge_O_Sketch
category: "Claudes_Utils"
buttontext: "EdgeOSketch"
Icon: #("Surface_tools",1)
(
local bitmapX = bitmapY = 1024
local bitmapx_1 = bitmapx-1
local bitmapy_1 = bitmapy-1
local temp_bitmap_filename = (getDir #image + "/Edge_0_Sketch_temp.bmp")
local currentPos = lastPos = [0,0]
local theChannel = 1
local minAngle = 0.0
local lineWidth = 1
local lineColour = white
local lineType = 1
local renderPeaks = true
local renderAllOpenEdges = false
local SettingsRollout
local theWindow
local noise = false
local noiseValue = 1.0
local constrainToMatID = false
local matID = 1
local theObjToRender = undefined
local x_sel = 7
local y_sel = 7
local bmapSizeList = #("32","64","128","256","512","768","1024","2048")
local bmapSizes = #(32,64,128,256,512,768,1024,2048)
local renderTypeList = #("Hollows","Hills","Borders","All")
local render_Sel = 1
--*************************************************************
-- returns the position in a face of a particular vert or zero
fn GetVertFaceIndex theMesh theFace theVert =
(
faceVerts = getface theMesh theFace
if faceVerts.x == theVert then return 1
if faceVerts.y == theVert then return 2
if faceVerts.z == theVert then return 3
return 0
)
--**********************************************************
fn GetTVertFromFaceIndex theMesh theFace FaceIndex =
(
tfaceVerts = getTVFace theMesh theFace
if FaceIndex == 1 then return GetTVert theMesh tfaceVerts.x
if FaceIndex == 2 then return GetTVert theMesh tfaceVerts.y
if FaceIndex == 3 then return GetTVert theMesh tfaceVerts.z
)
--**********************************************************
fn paintBrush theBitMap pos col = (setPixels theBitMap pos #(col))
--**********************************************************
fn drawStroke theBitMap lastPos pos BrushSize col=
(
currentPos = lastPos
deltaX = pos.x - lastPos.x
deltaY = pos.y - lastPos.y
maxSteps = amax #(abs(deltaX),abs(deltaY))
deltaStepX = deltaX / maxSteps
deltaStepY = deltaY / maxSteps
for i = 0 to maxSteps do
(
if noise then
(
for b = 1 to (BrushSize / noiseValue) do
(
paintBrush theBitMap (currentPos + (random [-BrushSize/2,-BrushSize/2] [BrushSize/2,BrushSize/2] )) col
)
)
else
(
for b = -BrushSize/2 to BrushSize/2 do
(
for c = -BrushSize/2 to BrushSize/2 do
(
paintBrush theBitMap (currentPos + [c,b]) col
)
)
)
currentPos += [deltaStepX, deltaStepY]
)
)
--**********************************************************
-- returns only those edges that have 2 faces
fn GetInternalEdges theMesh =
(
theMesh.edges as bitarray - meshop.getOpenEdges theMesh
)
--*************************************************************
fn IsEdgeVisible theMesh theEdge =
(
local theFace = ((theEdge-1)/3)+1
local edgeIndex = theEdge - (theFace-1)*3
getEdgeVis theMesh theFace edgeIndex
)
--*************************************************************
-- returns the 2 faces sharing an edge
fn GetEdgedFaces theMesh theEdge =
(
meshop.getFacesUsingEdge theMesh (#(theEdge) + meshop.getEdgesReverseEdge theMesh theEdge) as array
)
--**********************************************************
-- returns the vert not used by an edge of a face
fn GetSpareFaceVert theMesh theFace theEdge =
(
getvert themesh ((meshop.getVertsUsingFace theMesh theFace - meshop.getVertsUsingEdge theMesh theEdge) as array)[1]
)
--*************************************************************
fn GetEdgeCreasing theMesh theEdge =
(
-- get the two faces adjoining the edge
theFaces = GetEdgedFaces theMesh theEdge
-- create a coordinate transform matrix based on the first
faceNormal = getFaceNormal theMesh theFaces[1]
faceMat = matrixFromNormal faceNormal
-- offset it to the center of the first face
faceCenter = meshop.getFaceCenter theMesh theFaces[1]
faceMat.translation = faceCenter
-- get the vert from face 2 not used on the edge
spare = GetSpareFaceVert theMesh theFaces[2] theEdge
-- transform it into the coordinate system of the first face
spare = spare * (inverse faceMat)
-- we only need the z value
if spare.z >= 0 then return true else return false
)
--*************************************************************
fn GetEdgeAngle theMesh theEdge =
(
-- get the two faces adjoining the edge
theFaces = GetEdgedFaces theMesh theEdge
-- get our face normals
v1 = getFaceNormal theMesh theFaces[1]
v2 = getFaceNormal theMesh theFaces[2]
-- calculate the angle
theAngle = acos(dot (normalize v1) (normalize v2))
)
--**********************************************************
fn GetEdgeSmG theMesh theEdge =
(
-- get the two faces adjoining the edge
theFaces = GetEdgedFaces theMesh theEdge
sg1=getFaceSmoothGroup theMesh theFaces[1]
sg2=getFaceSmoothGroup theMesh theFaces[2]
if sg1+sg2 == 0 then return false
return sg1 == sg2
)
--**********************************************************
-- removes the partnered edge from a list of edges, useful because i know
-- all my edges are shared :]
fn RemoveReverseEdges theMesh edgeList=
(
theEdges = edgeList as array
reqEdges = #()
for i in theEdges do
(
if i != 0 then
(
reverseEdge = (meshop.getEdgesReverseEdge theMesh i as array)[1]
if (index = finditem theEdges reverseEdge) != 0 then
(
theEdges[index] = 0
)
)
)
j=1
for i in theEdges do
(
if i != 0 then
(
reqEdges[j] = i
j=j+1
)
)
return reqEdges
)
--*************************************************************
fn RenderEdges theObj BrushSize col =
(
local theBitmap = bitmap bitmapX bitmapY color:backgroundColor filename:temp_bitmap_filename
-- clear our bitmap
--copy theBackgroundBitmap theCanvasBitmap
-- get a snapshot of the mesh
theMesh = snapshotAsMesh theObj
meshop.deleteIsoMapVertsAll theMesh
internalEdges = GetInternalEdges theMesh
internalEdges = RemoveReverseEdges theMesh internalEdges
for i in internalEdges do
(
if IsEdgeVisible theMesh i then
(
if GetEdgeCreasing theMesh i == renderPeaks then
(
if GetEdgeAngle theMesh i > minAngle and not GetEdgeSmG theMesh i then
(
-- get edge verts and faces
theVerts = meshop.getVertsUsingEdge theMesh i as array
theFaces = GetEdgedFaces theMesh i
if constrainToMatID == false then
(
-- get the UV verts
vindex1 = GetVertFaceIndex theMesh theFaces[1] theVerts[1]
uvVert1 = GetTVertFromFaceIndex theMesh theFaces[1] vindex1
vindex2 = GetVertFaceIndex theMesh theFaces[1] theVerts[2]
uvVert2 = GetTVertFromFaceIndex theMesh theFaces[1] vindex2
-- draw on the bitmap
drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
-- get the UV verts
vindex1 = GetVertFaceIndex theMesh theFaces[2] theVerts[1]
uvVert1 = GetTVertFromFaceIndex theMesh theFaces[2] vindex1
vindex2 = GetVertFaceIndex theMesh theFaces[2] theVerts[2]
uvVert2 = GetTVertFromFaceIndex theMesh theFaces[2] vindex2
-- draw on the bitmap
drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
)
else
(
if getFaceMatID theMesh theFaces[1] == matID then
(
-- get the UV verts
vindex1 = GetVertFaceIndex theMesh theFaces[1] theVerts[1]
uvVert1 = GetTVertFromFaceIndex theMesh theFaces[1] vindex1
vindex2 = GetVertFaceIndex theMesh theFaces[1] theVerts[2]
uvVert2 = GetTVertFromFaceIndex theMesh theFaces[1] vindex2
-- draw on the bitmap
drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
)
if getFaceMatID theMesh theFaces[2] == matID then
(
-- get the UV verts
vindex1 = GetVertFaceIndex theMesh theFaces[2] theVerts[1]
uvVert1 = GetTVertFromFaceIndex theMesh theFaces[2] vindex1
vindex2 = GetVertFaceIndex theMesh theFaces[2] theVerts[2]
uvVert2 = GetTVertFromFaceIndex theMesh theFaces[2] vindex2
-- draw on the bitmap
drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
)
)
)
)
)
)
-- save the bitmap in temp bmp
save theBitmap
-- dispay our bitmap
display theBitmap
-- delete our snapshot
delete theMesh
)
--****************************************************************
fn RenderOpenEdges theObj BrushSize col =
(
local theBitmap = bitmap bitmapX bitmapY color:backgroundColor filename:temp_bitmap_filename
-- get a snapshot of the mesh
theMesh = snapshotAsMesh theObj
theEdges = (meshop.getOpenEdges theMesh) as array
for i in theEdges do
(
if IsEdgeVisible theMesh i then
(
-- get edge verts and faces
theVerts = meshop.getVertsUsingEdge theMesh i as array
theFaces = GetEdgedFaces theMesh i
if constrainToMatID == false then
(
-- get the UV verts
vindex1 = GetVertFaceIndex theMesh theFaces[1] theVerts[1]
uvVert1 = GetTVertFromFaceIndex theMesh theFaces[1] vindex1
vindex2 = GetVertFaceIndex theMesh theFaces[1] theVerts[2]
uvVert2 = GetTVertFromFaceIndex theMesh theFaces[1] vindex2
-- draw on the bitmap
drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
)
else
(
if getFaceMatID theMesh theFaces[1] == matID then
(
-- get the UV verts
vindex1 = GetVertFaceIndex theMesh theFaces[1] theVerts[1]
uvVert1 = GetTVertFromFaceIndex theMesh theFaces[1] vindex1
vindex2 = GetVertFaceIndex theMesh theFaces[1] theVerts[2]
uvVert2 = GetTVertFromFaceIndex theMesh theFaces[1] vindex2
-- draw on the bitmap
drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
)
)
)
)
-- save the bitmap in temp bmp
save theBitmap
-- dispay our bitmap
display theBitmap
-- delete our snapshot
delete theMesh
)
--****************************************************************
fn RenderAll theObj BrushSize col =
(
local theBitmap = bitmap bitmapX bitmapY color:backgroundColor filename:temp_bitmap_filename
-- get a snapshot of the mesh
theMesh = snapshotAsMesh theObj
theEdges = theMesh.Edges
for i in theEdges do
(
if IsEdgeVisible theMesh i then
(
-- get edge verts and faces
theVerts = meshop.getVertsUsingEdge theMesh i as array
theFaces = GetEdgedFaces theMesh i
-- get the UV verts
vindex1 = GetVertFaceIndex theMesh theFaces[1] theVerts[1]
uvVert1 = GetTVertFromFaceIndex theMesh theFaces[1] vindex1
vindex2 = GetVertFaceIndex theMesh theFaces[1] theVerts[2]
uvVert2 = GetTVertFromFaceIndex theMesh theFaces[1] vindex2
-- draw on the bitmap
drawStroke theBitmap [uvVert1.x * bitmapx_1,bitmapy_1 - uvVert1.y * bitmapy_1] \
[uvVert2.x * bitmapx_1,bitmapy_1 - uvVert2.y * bitmapy_1] BrushSize col
)
)
-- save the bitmap in temp bmp
save theBitmap
-- dispay our bitmap
display theBitmap
-- delete our snapshot
delete theMesh
)
--*************************************************************
fn pbMeshFilterFunc theObj =
(
classof theObj == Editable_Mesh or classof theObj == Editable_Poly
)
--*************************************************************
rollout SettingsRollout "Settings"
(
-- render size
label lab1 "Render Size" align:#left offset:[0,4]
dropdownlist bmXSizeddlist items:bmapSizeList selection:x_sel width:52 offset:[64,-22]
label lab2 "x" offset:[16,-23]
dropdownlist bmYSizeddlist items:bmapSizeList selection:y_sel width:52 offset:[130,-22]
-- render type and cutoff angle
label lab3 "Render..." align:#left offset:[0,4]
dropdownlist renderTypeddlist items:renderTypeList selection:render_Sel width:72 offset:[64,-22]
spinner cutoffangleSpn "Angle:" range:[0,90.0,minAngle ] type:#float fieldWidth:32 align:#left offset:[140,-24]
-- line width and colour
spinner lineWidthSpn "Line Width: " range:[1,100,lineWidth] type:#integer fieldWidth:32 align:#left offset:[0,4]
colorpicker lineColourCP "Line Colour:" color:lineColour fieldWidth:32 height:16 offset:[114,-22]
-- noise setup
checkbox usenoiseCbx "Noise " checked:noise offset:[0,4]
spinner noiseAmountSpn "Noise Level: " range:[0,10,noiseValue] type:#float fieldWidth:32 align:#left offset:[78,-19]
-- matID setup
checkbox constrainMatIDCbx "Constrain Mat ID" checked:constrainToMatID offset:[0,4]
spinner MatIDSpn "Mat ID:" range:[1,999,matID] type:#integer fieldWidth:32 align:#left offset:[110,-19]
-- object picker
pickbutton pRenderObj "Render Obj" filter:pbMeshFilterFunc align:#center offset:[0,4]
-- event handlers
on bmXSizeddlist selected item do
(
bitmapX = bmapSizes[item]
bitmapx_1 = bitmapX-1
x_sel = item
)
on bmYSizeddlist selected item do
(
bitmapY = bmapSizes[item]
bitmapy_1 = bitmapY-1
y_sel = item
)
on renderTypeddlist selected item do
(
if item == 1 then
renderPeaks = true
if item == 2 then
renderPeaks = false
render_Sel = item
)
on cutoffangleSpn changed val do (minAngle = val)
on lineWidthSpn changed val do (lineWidth = val)
on lineColourCP changed colour do (lineColour = colour)
on usenoiseCbx changed state do (noise = state)
on noiseAmountSpn changed val do (noiseValue= val)
on constrainMatIDCbx changed state do (constrainToMatID = state)
on noiseAmountSpn changed val do (matID = val)
on pRenderObj picked item do
(
theObjToRender = item
pRenderObj.text = item.name
case render_Sel of
(
1:
(
RenderEdges theObjToRender lineWidth lineColour
)
2:
(
RenderEdges theObjToRender lineWidth lineColour
)
3:
(
RenderOpenEdges theObjToRender lineWidth lineColour
)
4:
(
RenderAll theObjToRender lineWidth lineColour
)
)
)
)
on execute do
(
try(CloseRolloutFloater theWindow) catch()
theWindow = newRolloutFloater "Edge '0' Sketch" 250 195 8 100
Addrollout SettingsRollout theWindow
)
)
So acos(dot (normalize face1) (normalize face2)) seems to be the line here.
Unfortunately normalize is not recognized by max and you did not define it.
Also I need to know the difference between those two cases A & B as attached.
that line is correct but face1 & face2 are nothing to do with me
Normalize Vector
[left]normalize <point3>
[/left]
[left]Returns the point3 value normalized such that the vector length equals 1.
[/left]
[left]For example:
[/left]
[left]b = [100,30.5,41.3] – take some Point3 value
[/left]
[left][100,30.5,41.3]
[/left]
[left]normalB1 =normalize b – get the normalized vector
[/left]
[left][0.889603,0.271329,0.367406]
[/left]
[left]length normalB1 – check the length, should be 1.0
[/left]
[left]1.0 – It is!
[/left]
[left]normalB2 = b / (length b) – Do-It-Yourself Normalize…
[/left]
[left][0.889603,0.271329,0.367406] – same value
[/left]
[left]length normalB2 – of course, the length is also 1.0
[/left]
[left]1.0
[/left]
[left]
[/left]