|
PR:BF2 Community Modding Making or wanting help making your own asset? Check in here |
|
Thread Tools | Display Modes |
2017-08-11, 08:31 | #31 |
PR:BF2 Lead Designer
Join Date: Jan 2012
Posts: 8,514
Belgium
|
General rule for destroyables is to have geom0 terrain shadows unless it's a small prop like a cone or sign or something. But those should be removed by the mapper anyway from the on scene
|
|
|
2017-08-11, 08:41 | #32 | |
Retired PR Developer
|
Re: Experimental updated 3dsMax Tools. Newer Max versions support and more.
Quote:
If it is for custom LM UVs which would be really nice, there are no options for each LOD are there? | |
|
||
2017-08-11, 11:23 | #33 |
Join Date: Oct 2012
Posts: 1,280
Yugoslavia
|
Re: Experimental updated 3dsMax Tools. Newer Max versions support and more.
And now we can get 1.5 in a matter of days!
|
2017-08-11, 16:35 | #34 | |
PR:BF2 Contributor
Join Date: Jun 2017
Posts: 44
Germany
|
Re: Experimental updated 3dsMax Tools. Newer Max versions support and more.
Quote:
Alright we're getting closer. What I've done now is include a "User" option in the dropdown list. I assume that if one wants custom sizes for each lod, they sort of know what they're doing. Well, enough to trust them to rename lod nodes themselves. So in case "User" selected, one can add the requested size to each lod node (including lods under possible different geoms, e.g. if we're talking destroyableObjects) such: Can either be single values (-> square textures) or two values separated by * This applies for both automatic and custom LM UVs. One caveat I found is that different nodes underneath the same lod cannot differ regarding the LM UV channel, as in if one node has custom UVs, all other nodes need custom UVs as well. However I think that's a fairly rare case, considering StaticMeshes are mostly just a single node, and that somebody who makes custom UVs probably does them for all nodes anyway. | |
2017-08-11, 17:23 | #36 | |||
Join Date: Jun 2016
Posts: 15
China
|
Re: Experimental updated 3dsMax Tools. Newer Max versions support and more.
Quote:
Quote:
Quote:
Code:
-- bf2mesh.ms g_bf2doInclude "animation/skeImport.ms" -- helper functions fn BF2ReadString fp=( local length = ReadLong fp #unsigned result = "" for i=1 to length do( local char = bit.intaschar (ReadByte fp #unsigned) append result char ) return result --return ReadString fp ) fn BF2AddVertsToChannel obj mapChannel vertsList=( if meshop.getMapSupport obj mapChannel != true then meshop.setMapSupport obj mapChannel true if obj.numverts != vertsList.count then format "ERROR in BF2AddVertsToChannel: numverts!=numtverts" for i=1 to vertsList.count do ( meshop.setMapVert obj mapChannel i vertsList[i] ) ) fn BF2CreateBoneFromFile fname boneObjs s=( local f = fopen fname "rb" if (f != undefined) then ( if s == undefined then s = 1.0 / BF2_GetUnitMultiplier() local version = readlong f format "version: %\n" version local numBones = readlong f local parentIDs = #() local rightHandID = -2 for i=1 to numBones do ( local tmpName = bf2ske.readName f local tmpNameLC = lowercase tmpName if tmpName == "right_ullna" then rightHandID = i - 1 if tmpName == "torus" then rightHandID = i - 1 local motherInx = readShort f local tmpQuat = #() for j=1 to 4 do append tmpQuat (readFloat f) local tmpPos = [0,0,0] tmpPos.x = (readFloat f) * s tmpPos.z = (readFloat f) * s tmpPos.y = (readFloat f) * s local motherObj = undefined if motherInx != -1 then ( -- format " % %\n" motherInx boneObjs[motherInx+1] if isValidNode boneObjs[motherInx+1] then ( motherObj = boneObjs[motherInx+1] parentIDs[i] = motherInx + 1 ) ) if (partialCompareStr tmpName "mesh") then ( if rightHandID == motherInx then ( local newBone = Box name:tmpName length:(0.25) width:(0.25) height:(0.25) newBone.parent = boneObjs[motherInx+1] newBone.transform = newBone.parent.transform continue ) ) local newBone = bf2ske.makeBone tmpName tmpQuat tmpPos motherObj boneObjs[i] = newBone format "%_% (%) \t% %\n" i tmpName (motherInx+1) tmpQuat tmpPos ) fclose f local boneSz = 0.15 local rtNode = Dummy name:("root_skeleton_" + (getFilenamefile fname)) size:(0.4*s) for i=1 to numBones do ( if isValidNode boneObjs[i] then ( if parentIDs[i] != undefined then ( -- boneObjs[i].parent = boneObjs[parentIDs[i]] ) else ( boneObjs[i].parent = rtNode ) ) ) return rtNode ) return false ) -- bounding box -- 24 bytes struct aabb ( bbmin, --Point3 bbmax, --Point3 -- functions fn Read fp=( local vx = (ReadFloat fp) local vy = (ReadFloat fp) local vz = (ReadFloat fp) bbmin = [vx,vz,vy] local vx = (ReadFloat fp) local vy = (ReadFloat fp) local vz = (ReadFloat fp) bbmax = [vx,vz,vy] ) ) -- 4x4 transformation matrix struct matrix4 -- 64 bytes ( m, --BigMatrix 4*4 -- functions fn Read fp=( m = BigMatrix 4 4 for i=1 to 4 do ( for j=1 to 4 do m[i][j]=(ReadFloat fp) ) ), fn convertTransform s inverseTrans:false=( if m==undefined then return m else( local mat = matrix3 [m[1][1],m[1][3],m[1][2]] [m[3][1],m[3][3],m[3][2]] [m[2][1],m[2][3],m[2][2]] ([m[4][1],m[4][3],m[4][2]]*s) if inverseTrans then return mat else return (inverse mat) ) ) ) --bf2 vertex structure struct bf2vertex ( position, --0 blendweight, --1 blendindices, --2 normal, --3 texcoord, --5 tangent, --6 uv2, --261 uv3, --517 uv4, --773 uv5, --1029 --fnList includes all functions the Read function should use fn Read fp version attribList=( for i=1 to attribList.count do( --check flag if attribList[i].flag != 0 then continue --read data local ret = case attribList[i].vartype of( --D3DDECLTYPE_FLOAT1 0: ReadFloat fp --D3DDECLTYPE_FLOAT2 1: [(ReadFloat fp),1-(ReadFloat fp),0] --this is used as UV, V is inverted, and we insert a 0 as W --D3DDECLTYPE_FLOAT3 2: [(ReadFloat fp),(ReadFloat fp),(ReadFloat fp)] --D3DDECLTYPE_D3DCOLOR(4 ubytes) 4: #((ReadByte fp #unsigned),(ReadByte fp #unsigned),(ReadByte fp #unsigned),(ReadByte fp #unsigned)) default: format "vartype % not supported" attribList[i].vartype ) if ret==undefined then continue --store data case attribList[i].usage of( --D3DDECLUSAGE_POSITION 0: position = [ret.x, ret.z, ret.y]--ret --D3DDECLUSAGE_BLENDWEIGHT 1: blendweight = ret --D3DDECLUSAGE_BLENDINDICES 2: blendindices = ret --D3DDECLUSAGE_NORMAL 3: normal = ret --D3DDECLUSAGE_TEXCOORD 5: texcoord = ret --D3DDECLUSAGE_TANGENT 6: tangent = ret --uv2 261: uv2 = ret --uv3 517: uv3 = ret --uv4 773: uv4 = ret --uv5 1029: uv5 = ret default: format "usage % not supported" attribList[i].usage ) ) ) ) -- bf2 mesh file header struct bf2head -- 20 bytes ( u1, -- (uint)0 version, -- (uint)10 for most bundledmesh, 6 for some bundledmesh, 11 for staticmesh u3, -- (uint)0 u4, -- (uint)0 u5, -- (uint)0 -- functions fn Read fp=( u1 = ReadLong fp #unsigned version = ReadLong fp #unsigned u3 = ReadLong fp #unsigned u4 = ReadLong fp #unsigned u5 = ReadLong fp #unsigned ) ) -- vertex attribute table entry struct bf2attrib -- 8 bytes ( flag, -- (ushort)some sort of boolean flag (if true the below field are to be ignored?) offset, -- (ushort)offset from vertex data start vartype, -- (ushort)attribute type (vec2, vec3 etc) usage, -- (ushort)usage ID (vertex, texcoord etc) -- functions fn Read fp=( flag = ReadShort fp #unsigned offset = ReadShort fp #unsigned vartype = ReadShort fp #unsigned usage = ReadShort fp #unsigned ) -- Note: "usage" field correspond to the definition in DX SDK "Include\d3d9types.h" -- Looks like DICE extended these for additional UV channels, these constants -- are much larger to avoid conflict with core DX enums. ) -- bone structure struct bf2bone -- 68 bytes ( id, -- (uint)4 bytes transform, -- (matrix4)64 bytes fn Read fp version=( id = ReadLong fp #unsigned transform = matrix4() transform.Read fp ) ) -- rig structure struct bf2rig ( bonenum, -- (int) bone, -- #(bf2bone) -- constructor/destrutor -- functions fn Read fp version= ( bonenum = ReadLong fp #signed format " bonenum: %\n" bonenum bone = #() for i = 1 to bonenum do( local tmpbone = bf2bone() tmpbone.Read fp version append bone tmpbone format " boneid[%]: %\n" i tmpbone.id ) ) ) -- material (aka drawcall) struct bf2mat ( alphamode, -- (uint)0=opaque, 1=blend, 2=alphatest fxfile, -- (string)shader filename string technique, -- (string)technique name -- texture map filenames mapnum, -- (uint)number of texture map filenames map, -- #(string)map filename array -- geometry info vstart, -- (uint)vertex start offset istart, -- (uint)index start offset inum, -- (uint)number of indices vnum, -- (uint)number of vertices -- misc u4, -- (uint)always 1? u5, -- (ushort)always 0x34E9? u6, -- (ushort)most often 18/19 bounds, -- (aabb)per-material bounding box (StaticMesh only) -- constructor/destructor -- functions fn Read fp version isSkn=( -- alpha flag (4 bytes) if not isSkn do ( alphamode = ReadLong fp #unsigned format " alphamode: %\n" alphamode ) -- fx filename fxfile = BF2ReadString fp format " fxfile: %\n" fxfile -- material name technique = BF2ReadString fp format " matname: %\n" technique -- mapnum (4 bytes) mapnum = ReadLong fp #unsigned format " mapnum: %\n" mapnum map = #() for i= 1 to mapnum do( tmpstr = (BF2ReadString fp) append map tmpstr format " map %: %\n" i tmpstr ) --geometry info vstart = ReadLong fp #unsigned istart = ReadLong fp #unsigned inum = ReadLong fp #unsigned vnum = ReadLong fp #unsigned format " vstart: %\n" vstart format " istart: %\n" istart format " inum: %\n" inum format " vnum: %\n" vnum --unknown u4 = ReadLong fp #unsigned u5 = ReadShort fp #unsigned u6 = ReadShort fp #unsigned --bounds if not isSkn do ( if version == 11 do( bounds = aabb() bounds.Read fp ) ) return true ) ) -- lod, holds mainly a collection of materials struct bf2lod ( -- bounding box bbmin, -- (Point3) bbmax, -- (Point3) pivot, -- (Point3)not sure this is really a pivot (only on version<=6) -- skinning matrices (SkinnedMesh only) rignum, -- (int)this usually corresponds to meshnum (but what was meshnum again??) rig, -- #(bf2rig)array of rigs -- nodes (staticmesh and bundledmesh only) nodenum, --(int) node, --#(matrix4) -- material/drawcalls matnum, -- (int)number of materials mat, -- #(bf2mat)material array -- constructor/destructor -- functions fn ReadNodeData fp version isSkn isBn isBFP4F=(--return bool --bounds (24 bytes) vx = (ReadFloat fp) vy = (ReadFloat fp) vz = (ReadFloat fp) bbmin = [vx,vz,vy] vx = (ReadFloat fp) vy = (ReadFloat fp) vz = (ReadFloat fp) bbmax = [vx,vz,vy] --unknown (12 bytes) if version <= 6 do( --version 4 and 6 vx = (ReadFloat fp) vy = (ReadFloat fp) vz = (ReadFloat fp) pivot = [vx,vz,vy] ) --skinnedmesh has different rigs if isSkn then( rignum = ReadLong fp #signed format " rignum: %\n" rignum rig = #() for i=1 to rignum do( format " rig block % start at %\n" i (ftell fp) local tmprig = bf2rig() tmprig.Read fp version append rig tmprig --format " bone: %\n" tmprig.bone format " rig block % end at %\n" i (ftell fp) ) ) else( nodenum = ReadLong fp #signed format " nodenum: %\n" nodenum if not isBn do( format " node data\n" node = #() for i=1 to nodenum do( local tmpnode = matrix4() tmpnode.Read fp format " node transform: %\n" tmpnode append node tmpnode ) ) --node matrices (BFP4F variant) if isBn and isBFP4F then( format " node data\n" node = #() for i=1 to nodenum do( local tmpnode = matrix4() tmpnode.Read fp format " node transform: %\n" tmpnode append node tmpnode local tmpname = BF2ReadString fp --just discard it.. format "node matrix string: %\n" tmpname ) ) ) return true ), fn ReadMatData fp version isSkn=(--return bool matnum = ReadLong fp #signed format " matnum: %\n" matnum mat = #() for i=1 to matnum do( format " mat block % start at %\n" i (ftell fp) local tmpmat = bf2mat() if not tmpmat.Read fp version isSkn then return false append mat tmpmat format " mat block % end at %\n" i (ftell fp) ) return true ) ) -- geom, holds a collection of LODs struct bf2geom ( lodnum, -- (int)number of LODs lod, -- #(bf2lod)array of LODs -- constructor/destructor -- functions fn Read fp version= ( -- return bool lodnum = ReadLong fp #signed format " lodnum: %\n" lodnum lod = #() for i=1 to lodnum do( local tmplod = bf2lod() append lod tmplod ) ) ) -- BF2 mesh file structure struct bf2mesh ( -- header head, --(bf2head) -- unknown u1, -- (ubyte)always 0? -- geoms geomnum, -- (int)numer of geoms geom, -- #(bf2geom)geom array -- vertex attribute table vertattribnum, -- (int)number of vertex attribute table entries vertattrib, -- #(bf2attrib)array of vertex attribute table entries -- vertices vertformat, -- (int)always 4? (e.g. GL_FLOAT) vertstride, -- (int)vertex stride vertnum, -- (int)number of vertices in buffer vert, -- #(bf2vertex)vertex array -- indices indexnum, -- (int)number of indices index, -- #(ushort)index array -- unknown u2, -- (int)always 8? -- constructor/destructor -- internal/hacks isSkinnedMesh=false, --bool isBundledMesh=false, --bool isBFP4F=false, --bool -- functions fn Load filename= ( local fp = fopen filename "rb" if fp == undefined then( format "File \"%\" not found.\n" filename return 1 ) --header head = bf2head() format "head start at %\n" (ftell fp) head.Read fp format " version: %\n" head.version format "head end at %\n" (ftell fp) format "\n" --unknown (1 byte) u1 = ReadByte fp #unsigned --for BFP4F, the value is "1", so perhaps this is a version number as well if u1 == 1 do isBFP4F = true --- geom table --------------------------------------------------------------------------- format "geom table start at %\n" (ftell fp) --geomnum (4 bytes) geomnum = ReadLong fp #signed format " geomnum: %\n" geomnum geom = #() for i=1 to geomnum do( tmpgeom = bf2geom() tmpgeom.Read fp head.version append geom tmpgeom ) format "geom table end at %\n" (ftell fp) format "\n" --- vertex attribute table ------------------------------------------------------------------------------- format "attrib block at %\n" (ftell fp) --vertattribnum (4 bytes) vertattribnum = ReadLong fp #signed format "vertattribnum: %\n" vertattribnum vertattrib = #() for i=1 to vertattribnum do( tmpvertattrib = bf2attrib() tmpvertattrib.Read fp append vertattrib tmpvertattrib format " attrib[%]: % % % %\n" i tmpvertattrib.flag \ tmpvertattrib.offset \ tmpvertattrib.vartype \ tmpvertattrib.usage ) format "attrib block end at %\n" (ftell fp) format "\n" --- vertices ----------------------------------------------------------------------------- format "vertex block start at %\n" (ftell fp) vertformat = ReadLong fp #signed vertstride = ReadLong fp #signed vertnum = ReadLong fp #signed format " vertformat: %\n" vertformat format " vertstride: %\n" vertstride format " vertnum: %\n" vertnum if vertformat!=4 then ( format "vertformat not supported!" return 1 ) vert = #() for i=1 to vertnum do( tmpvert = bf2vertex() tmpvert.Read fp version vertattrib append vert tmpvert ) format "vertex block end at %\n" (ftell fp) --- indices ------------------------------------------------------------------------------ format "index block start at %\n" (ftell fp) indexnum = ReadLong fp #signed format " indexnum: %\n" indexnum index = #() for i=1 to indexnum do( append index (ReadShort fp #unsigned) ) format "index block end at %\n" (ftell fp) format "\n" --- rigs ------------------------------------------------------------------------------- --unknown (4 bytes) if not isSkinnedMesh then( u2 = ReadLong fp #signed ) --rigs/nodes format "nodes chunk start at %\n" (ftell fp) for i=1 to geomnum do( format " geom % start\n" (i-1) for j=1 to geom[i].lodnum do( format " lod % start\n" (j-1) geom[i].lod[j].ReadNodeData fp head.version isSkinnedMesh isBundledMesh isBFP4F format " lod % end\n" (j-1) ) format " geom % end\n" (i-1) ) format "nodes chunk end at %\n" (ftell fp) format "\n" --- geoms ------------------------------------------------------------------------------ format "geoms chunk start at %\n" (ftell fp) for i=1 to geomnum do( format " geom % start\n" (i-1) for j=1 to geom[i].lodnum do( format " lod % start\n" (j-1) geom[i].lod[j].ReadMatData fp head.version isSkinnedMesh format " lod % end\n" (j-1) ) format " geom % end\n" (i-1) ) format "geoms chunk end at %\n" (ftell fp) format "\n" --end of file format "done reading %\n" (ftell fp) fseek fp 0 #seek_end format "file size is %\n" (ftell fp) format "\n" --close file fclose fp --success return 0 ), fn createInstance forLightmap s=( --add map search path mapPaths.add (bf2GetSetting "outModPath") if head == undefined then return() --not Loaded format "%" Point() --help latter objects successfully create local rootDummy = Point() rootDummy.name = "root" if isSkinnedMesh then append rootDummy.name "_skinnedmesh" else if isBundledMesh then append rootDummy.name "_bundledmesh" else append rootDummy.name "_staticmesh" for i=1 to geomnum do( format " geom % start\n" (i-1) local geomDummy = Dummy name:("geom"+((i-1) as string)) position:[0,0,0] append rootDummy.children geomDummy --preload skeleton for skinnedmesh local skeRoot = undefined local boneObjs = #() if isSkinnedMesh then( --import skeleton local skeName = getOpenFileName caption:("Import .ske for geom"+((i-1) as string)) types:"Skeleton .ske|*.ske|All|*.*|" -- If the user did not cancel the file open dialog if skeName != undefined then( skeRoot = BF2CreateBoneFromFile skeName boneObjs s --adjust bone positions local boneTransforms = #() local tmpIDs = #() for j=1 to geom[i].lodnum do( for k=1 to geom[i].lod[j].rignum do( local tmprig = geom[i].lod[j].rig[k] for l=1 to tmprig.bonenum do( local tmpbone = tmprig.bone[l] if boneTransforms[tmpbone.id+1] == undefined then( --local boneObj = boneObjs[tmpbone.id+1] append tmpIDs (tmpbone.id+1) boneTransforms[tmpbone.id+1] = tmpbone.transform.convertTransform s ) ) ) ) --maxid = amax tmpIDs --start from 0 --for j=1 to (maxid+1) do( /*for j in tmpIDs do( --if (findItem tmpIDs j) != 0 then( local boneObj = boneObjs[j] if boneTransforms[j]!=undefined then ( if boneObj.parent == skeRoot then ( boneObj.transform = boneTransforms[j] ) else( --get parent transform local parentIndex = findItem boneObjs boneObj.parent if boneTransforms[parentIndex] != undefined then boneObj.transform = (inverse boneObj.parent.transform)*boneTransforms[j]--boneTransforms[parentIndex]) --boneObj.transform = inverse ((inverse boneTransforms[j])*boneObj.parent.transform) else format "ERROR! bone % parent not found in rig transforms!\n" (j-1) ) ) --) )*/ --renew transform from top to bottom fn renewTrans nodes boneObjs boneTransforms=( while nodes.count > 0 do( local childrens = #() for node in nodes do( local nodeID = findItem boneObjs node if classof node == Pyramid and nodeID>0 and boneTransforms[nodeID]!=undefined then node.transform = boneTransforms[nodeID] join childrens node.children ) nodes = childrens ) ) renewTrans skeRoot.children boneObjs boneTransforms ) else( skeRoot = Dummy name:"root_skeleton_debug" --create debug bones local tmpChildren = #() local tmpIDs = #() for j=1 to geom[i].lodnum do( for k=1 to geom[i].lod[j].rignum do( local tmprig = geom[i].lod[j].rig[k] for l=1 to tmprig.bonenum do( local tmpbone = tmprig.bone[l] if boneObjs[tmpbone.id+1] == undefined then( local bonename = (tmpbone.id as string) if bonename.count==1 then bonename = "0"+bonename --bone id cannot exceed 99 local boneObj = Pyramid name:bonename transform:(tmpbone.transform.convertTransform s) width:(0.01*s) depth:(0.01*s) height:(0.05*s) append tmpChildren boneObj append tmpIDs tmpbone.id boneObjs[tmpbone.id+1] = boneObj ) ) ) ) --add missed id bones maxid = amax tmpIDs for j=0 to maxid do( --id start from 0 if (findItem tmpIDs j) == 0 then( local bonename = (j as string) if bonename.count==1 then bonename = "0"+bonename local boneObj = Pyramid name:bonename width:(0.03*s) depth:(0.03*s) height:(0.1*s) append tmpChildren boneObj boneObjs[j+1] = boneObj ) ) --sort names fn sortByName obj1 obj2=( if obj1.name>obj2.name then return 1 else return -1 ) qsort tmpChildren sortByName format " debug bones: %\n" tmpChildren for j=1 to tmpChildren.count do( append skeRoot.children tmpChildren[j] ) ) append geomDummy.children skeRoot --adjust bone length for b in boneObjs do ( if classof b == Pyramid then ( if b.children.count == 1 then ( local distFromObjs = distance b b.children[1] local dirPointing = pointingSameDir b.transform b.children[1].pos if dirPointing == 1 then ( b.height = distFromObjs ) else ( if dirPointing == -1 then ( b.height = -distFromObjs ) else ( -- not pointing directly at only child! ) ) ) ) ) ) for j=1 to geom[i].lodnum do( format " lod % start\n" (j-1) local lodDummy = Dummy name:("lod"+((j-1) as string)) position:[0,0,0] append geomDummy.children lodDummy if isSkinnedMesh then( --use rig info of geom[i].lod[j] --check bone info if skeRoot.name != "root_skeleton_debug" then( --TODO: check bone number ) --local mat = MultiSubMaterial numsubs:geom[i].lod[j].matnum name:"BF2Object" -- read vert and face from bf2mat for k=1 to geom[i].lod[j].matnum do( local nodesInfo=#(#(),#(),#(),#(),#(),#()) -- #(#(verts),#(faces),#(blendweight),#(uvws),#(normals),#(boneIDs#(x,y))) local tmpmat = geom[i].lod[j].mat[k] --material(TODO: use bf2 bundledmesh material) local stdmat = StandardMaterial name:"BF2Object" stdmat.showInViewport = true --mat.MaterialList[k] = stdmat --mat.MaterialList[k].name = tmpname for l=1 to tmpmat.mapnum do( if (lowercase tmpmat.map[l]) == "common\\textures\\specularlut_pow36.dds" then continue -- do not include Specular_LUT local tmpTex = BitmapTexture() tmpTex.filename = tmpmat.map[l] --stdmat.maps[l+1] = tmpTex if classof stdmat.diffuseMap != BitmapTexture then( stdmat.diffuseMap = tmpTex ) else if classof stdmat.BumpMap != BitmapTexture then( stdmat.BumpMap = tmpTex ) else stdmat.SelfIllumMap = tmpTex ) -- vertices/uv/normal/blendweight/boneid for l=(tmpmat.vstart+1) to (tmpmat.vstart+tmpmat.vnum) do( --local nodeIndex = vert[l].blendindices[1]+1 append nodesInfo[1] (vert[l].position*s) --scale append nodesInfo[3] vert[l].blendweight append nodesInfo[4] vert[l].texcoord append nodesInfo[5] vert[l].normal append nodesInfo[6] #(vert[l].blendindices[1]+1, vert[l].blendindices[2]+1) ) -- faces local tmpindex = #() for l=(tmpmat.istart+1) to (tmpmat.istart+tmpmat.inum) do( --format "index: % face: %\n" index[l] (index[l]-tmpmat.vstart) append tmpindex (index[l]+1) if tmpindex.count==3 then( --triangle -- faces append nodesInfo[2] [tmpindex[3],tmpindex[2],tmpindex[1]] -- inverted tmpindex = #() ) ) format " vertices: %\n faces: %\n blendweights: %\n UVs: %\n normals: %\n boneIDs: %\n" nodesInfo[1] nodesInfo[2] nodesInfo[3] nodesInfo[4] nodesInfo[5] nodesInfo[6] local obj = mesh vertices:nodesInfo[1] faces:nodesInfo[2] tverts:nodesInfo[4] obj.wirecolor = (random [0,0,0] [1,1,1]) as color obj.name = (k-1) as string if obj.name.count<2 then obj.name = "0"+obj.name -- normals for l=1 to obj.numverts do( setNormal obj l nodesInfo[5][l] ) -- uv mapping --format "% %" obj.numverts obj.numtverts buildTVFaces obj for l=1 to obj.numfaces do( setTVFace obj l (getFace obj l) ) --skin modifier addModifier obj (Skin()) local skinMod = obj.modifiers[#skin] -- necessary for skinOps to work max modify mode select obj skinMod.bone_Limit = 2 -- only 2 bones affect one vert currently in game local tmprig = geom[i].lod[j].rig[k] --add bones for l=1 to tmprig.bonenum do( local updateInt = 0 if l==tmprig.bonenum then updateInt=-1 --update modifier at the last add skinOps.addbone skinMod boneObjs[tmprig.bone[l].id+1] updateInt ) --add weight for l=1 to obj.numverts do( local boneInfo = nodesInfo[6][l] local weightInfo if boneInfo[1]==boneInfo[2] then( boneInfo = boneInfo[1] weightInfo = 1.0 ) else weightInfo = #(nodesInfo[3][l],1-nodesInfo[3][l]) skinOps.SetVertexWeights skinMod l boneInfo weightInfo ) -- end append lodDummy.children obj obj.material = stdmat ) ) else( --use node info if isBundledMesh then( --use no-transform node local nodesInfo=#(#(),#(),#(),#(),#(),#(),#(),#(),#()) -- #(#(verts),#(faces),#(matIDs),#(uvws),#(nodeIndex(for face)),#(normals),#(blendindices[1]),#(uv2),#(blendindices[4](uvtranslate))) local indoffset = 0 local multimat = MultiSubMaterial numsubs:geom[i].lod[j].matnum name:"BF2Object" -- read vert and face from bf2mat for k=1 to geom[i].lod[j].matnum do( local tmpmat = geom[i].lod[j].mat[k] --material(TODO: use bf2 bundledmesh material) local tmpname = tmpmat.technique local isAnimatedUV = ((subString tmpname 1 10)=="AnimatedUV") /*if tmpmat.alphamode!=0 then( append tmpname ("|| alphamode=" + (tmpmat.alphamode as string)) )*/ local stdmat = StandardMaterial name:tmpname stdmat.showInViewport = true multimat.MaterialList[k] = stdmat --mat.MaterialList[k].name = tmpname for l=1 to tmpmat.mapnum do( if (lowercase tmpmat.map[l]) == "common\\textures\\specularlut_pow36.dds" then continue -- do not include Specular_LUT local tmpTex = BitmapTexture() tmpTex.filename = tmpmat.map[l] --stdmat.maps[l+1] = tmpTex if classof stdmat.diffuseMap != BitmapTexture then( stdmat.diffuseMap = tmpTex ) else if classof stdmat.BumpMap != BitmapTexture then( stdmat.BumpMap = tmpTex ) else stdmat.SelfIllumMap = tmpTex ) local aspectRatio if isAnimatedUV and stdmat.diffuseMap!=undefined then( local tmpbitmap = stdmat.diffuseMap.bitmap if stdmat.diffuseMap.bitmap!=undefined then aspectRatio = (tmpbitmap.height as Float)/tmpbitmap.width else messagebox ("Texture" + stdmat.diffuseMap.filename + "Not Found! Make sure you put the texture in the mod output path!") format "bitmap % aspectRatio = %" stdmat.diffuseMap.filename aspectRatio ) -- vertices/uv/normal for l=(tmpmat.vstart+1) to (tmpmat.vstart+tmpmat.vnum) do( --local nodeIndex = vert[l].blendindices[1]+1 append nodesInfo[1] (vert[l].position*s) --scale --append nodesInfo[4] vert[l].texcoord append nodesInfo[6] vert[l].normal append nodesInfo[7] (vert[l].blendindices[1]+1) append nodesInfo[9] vert[l].blendindices[4] --if vert[l].uv2 != undefined then append nodesInfo[8] vert[l].uv2 --uvs if vert[l].uv2 != undefined then ( if isAnimatedUV then( if vert[l].blendindices[4]==1 or vert[l].blendindices[4]==3 then( --rotate uv --format "Rotate UV vert %\n" l append nodesInfo[4] (vert[l].texcoord+[vert[l].uv2.x*aspectRatio,1-vert[l].uv2.y,0]) append nodesInfo[8] vert[l].texcoord ) else( append nodesInfo[4] vert[l].texcoord append nodesInfo[8] vert[l].texcoord ) ) else( append nodesInfo[4] vert[l].texcoord append nodesInfo[8] vert[l].uv2 ) ) else ( append nodesInfo[4] vert[l].texcoord --append nodesInfo[8] vert[l].texcoord ) ) -- faces local tmpindex = #() for l=(tmpmat.istart+1) to (tmpmat.istart+tmpmat.inum) do( --format "index: % face: %\n" index[l] (index[l]-tmpmat.vstart) append tmpindex (index[l]+1) if tmpindex.count==3 then( --triangle --nodeIndex local nodeIndex = vert[tmpmat.vstart+tmpindex[1]].blendindices[1]+1 --check if all 3 vertices belongs to the same node local isBlendFace = false for m=2 to 3 do( if nodeIndex != vert[tmpmat.vstart+tmpindex[m]].blendindices[1]+1 then( --format "A Blend Face: %\n" tmpindex isBlendFace = true ) ) if not isBlendFace then( append nodesInfo[5] nodeIndex -- faces append nodesInfo[2] ([tmpindex[3],tmpindex[2],tmpindex[1]]+indoffset) -- inverted -- matIDs append nodesInfo[3] k ) else( append nodesInfo[5] 0 -- faces append nodesInfo[2] ([tmpindex[3],tmpindex[2],tmpindex[1]]+indoffset) -- inverted -- matIDs append nodesInfo[3] k ) tmpindex = #() ) ) indoffset = indoffset + tmpmat.vnum ) -- create node instance --for k=1 to geom[i].lod[j].nodenum do( format " vertices: %\n faces: %\n matIDs: %\n UVs: %\n nodeIndices: %\n normals: %\n" nodesInfo[1] nodesInfo[2] nodesInfo[3] nodesInfo[4] nodesInfo[5] nodesInfo[6] format " vertices count: %\n faces count: %\n tverts count: %\n" nodesInfo[1].count nodesInfo[2].count nodesInfo[4].count local obj = mesh vertices:nodesInfo[1] faces:nodesInfo[2] materialIDS:nodesInfo[3] tverts:nodesInfo[4] --obj.name = (k-1) as string -- normals for k=1 to obj.numverts do( setNormal obj k nodesInfo[6][k] ) -- uv mapping --format "% %" obj.numverts obj.numtverts buildTVFaces obj for k=1 to obj.numfaces do( setTVFace obj k (getFace obj k) ) --add vertex color according to blendindices[4] /* key: [] index value Right Side - treads .50 r [5] - rotate .71 ( r and b ) [3] - translate .60 [4] Left Side - treads .40 r [6] - rotate .91 ( r and b ) [1] - translate .80 [2] */ local vertColors = #() for k=1 to nodesInfo[9].count do( case nodesInfo[9][k] of( 1: append vertColors [0.91,0,0] 2: append vertColors [0.80,0,0] 3: append vertColors [0.71,0,0] 4: append vertColors [0.60,0,0] 5: append vertColors [0.50,0,0] 6: append vertColors [0.40,0,0] default: append vertColors [0,0,0] ) ) BF2AddVertsToChannel obj 0 vertColors --add uv2 if exist if nodesInfo[8].count>0 then( meshop.setNumMaps obj 3 keep:true BF2AddVertsToChannel obj 2 nodesInfo[8] ) -- detach faces to different nodes convertToMesh obj local nodes = #() local blendFaces = #() --init nodes for k=geom[i].lod[j].nodenum to 1 by -1 do( nodes[k] = #() ) --blendFaces for k=1 to nodesInfo[5].count do( if nodesInfo[5][k]>0 then append nodes[nodesInfo[5][k]] k else append blendFaces nodesInfo[2][k] ) if blendFaces.count > 0 then( --format "Creating % blend faces...\n" blendFaces.count --detach blendFaces /*local detached = meshop.detachFaces obj blendFaces delete:false asMesh:true local blendMesh = Editable_mesh() blendMesh.mesh = detached update blendMesh blendMesh.name = "blendMesh" append lodDummy.children blendMesh blendMesh.material = multimat*/ /* --get nodes for blendFaces, add bone and skin(skin is added on the original obj for convenience) local nodesForBlend = #() local vertsForBlend = #() local vertsNotForBlend = #() for k=1 to blendFaces.count do( for l=1 to 3 do( local vertIndex = blendFaces[k][l] --format "vertIndex: %\n" vertIndex local nodeIndex = nodesInfo[7][vertIndex] if (findItem nodesForBlend nodeIndex) == 0 then append nodesForBlend nodeIndex if (findItem vertsForBlend vertIndex) == 0 then append vertsForBlend vertIndex else append vertsNotForBlend vertIndex ) ) format "nodes for blend faces: %\n" nodesForBlend --add bone local boneObjs = #() for k=1 to nodesForBlend.count do( local bonename = "geom" + ((i-1) as string) + "lod" + ((j-1) as string) + "node" + ((nodesForBlend[k]-1) as string) local boneObj = Pyramid name:bonename width:(0.03*s) depth:(0.03*s) height:(0.1*s) append lodDummy.children[nodesForBlend[k]].children boneObj --boneObjs[nodesForBlend[k]] boneObj append boneObjs boneObj ) --add skin modifier to blendMesh addModifier obj (Skin()) local skinMod = obj.modifiers[#skin] -- necessary for skinOps to work max modify mode select obj skinMod.bone_Limit = 1 -- only 1 bone affect one vert skinMod.weightAllVertices = off --add bones for l=1 to boneObjs.count do( if boneObjs[l]==undefined then continue local updateInt = 0 if l==boneObjs.count then updateInt=-1 --update modifier at the last add skinOps.addbone skinMod boneObjs[l] updateInt ) --add weight for l=1 to obj.numverts do( if (findItem vertsForBlend l) == 0 then continue local nodeIndex = nodesInfo[7][l] --blendindices[1] local boneIndex = findItem nodesForBlend nodeIndex if boneIndex==0 then format "Error! index % not found in nodesForBlend!" boneInfo skinOps.SetVertexWeights skinMod l boneIndex 1.0 ) --delete unblended vertices(not sure if it works) --modPanel.setCurrentObject obj.baseObject --max create mode format "vertsNotForBlend: %\n" vertsNotForBlend meshop.deleteVerts $.baseObject vertsNotForBlend --deleteVert obj vertsNotForBlend update obj --material obj.material = multimat*/ --a basic implementation -- import the whole object and skin it to nodes...(wonder if it works when export) --create nodes dummys and attach a bone to each local boneObjs = #() for k=2 to geom[i].lod[j].nodenum do( local dummyMesh = mesh vertices:#([0.0,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,0.0]) faces:#([1,2,3]) --add dummy mesh dummyMesh.name = (k-1) as string if dummyMesh.name.count<2 then dummyMesh.name = "0"+dummyMesh.name append lodDummy.children dummyMesh dummyMesh.material = multimat --bone local bonename = "geom" + ((i-1) as string) + "lod" + ((j-1) as string) + "node" + ((k-1) as string) local boneObj = Pyramid name:bonename width:(0.03*s) depth:(0.03*s) height:(0.1*s) append boneObjs boneObj append dummyMesh.children boneObj ) --do not skin on obj directly to avoid loop independence error --clone obj to store skin data local skinobj = Editable_mesh() skinobj.mesh = obj.mesh skinobj.name = "skindata_" + "geom" + ((i-1) as string) + "lod" + ((j-1) as string) append lodDummy.children skinobj --use obj itself as the base node(0) obj.name = "00" obj.wirecolor = (random [0,0,0] [1,1,1]) as color obj.material = multimat append lodDummy.children obj --add skin modifier to skinobj addModifier skinobj (Skin()) local skinMod = skinobj.modifiers[#skin] -- necessary for skinOps to work max modify mode select skinobj skinMod.bone_Limit = 1 -- only 1 bone affect one vert skinMod.weightAllVertices = off --add bones for k=1 to boneObjs.count do( if boneObjs[k]==undefined then continue local updateInt = 0 if k==boneObjs.count then updateInt=-1 --update modifier at the last add skinOps.addbone skinMod boneObjs[k] updateInt ) --add weight for k=1 to skinobj.numverts do( local nodeIndex = nodesInfo[7][k] --blendindices[1]+1 --local boneIndex = findItem nodesForBlend nodeIndex --if boneIndex==0 then format "Error! index % not found in nodesForBlend!" boneInfo if nodeIndex>1 then skinOps.SetVertexWeights skinMod k (nodeIndex-1) 1.0 ) max create mode ) --format " obj vertices count: %\n obj faces count: %\n obj tverts count: %\n" obj.numverts obj.numfaces obj.numtverts else ( --detach nodes for k=1 to geom[i].lod[j].nodenum do( --format "nodes[%].count= %\n" k nodes[k].count local detached = meshop.detachFaces obj nodes[k] delete:false asMesh:true local newMesh = Editable_mesh() newMesh.mesh = detached newMesh.wirecolor = (random [0,0,0] [1,1,1]) as color update newMesh newMesh.name = (k-1) as string if newMesh.name.count<2 then newMesh.name = "0"+newMesh.name append lodDummy.children newMesh --apply material newMesh.material = multimat --format " newMesh vertices count: %\n newMesh faces count: %\n newMesh tverts count: %\n" newMesh.numverts newMesh.numfaces newMesh.numtverts ) delete obj ) ) else( --use transformed node messagebox "Staticmeshs not supported yet!" ) ) format " lod % end\n" (j-1) ) format " geom % end\n" (i-1) ) format "End importing..root:%\n" rootDummy return rootDummy ) ) fn bf2ImportMeshFile_new filename forLightmap s= ( if filename == undefined then filename = getOpenFileName() if filename == undefined then return undefined local filetype = lowercase (getFilenameType filename) local meshinstance = bf2mesh() format "filetype: %\n" filetype case filetype of( ".bundledmesh": meshinstance.isBundledMesh = true ".skinnedmesh": meshinstance.isSkinnedMesh = true ".staticmesh": format "staticmesh\n" default: ( messagebox "Not a bf2 mesh file!" return undefined ) ) rollout rolWorkingStatus "Importing...." width:224 height:80 ( button btn1 "Please Wait ..." pos:[32,24] width:152 height:40 enabled:false ) --bf2mdtOps.importMeshFile filename forLightmap s --bf2file = fopen filename "rb" createDialog rolWorkingStatus style:#(#style_sysmenu, #style_titlebar) meshinstance.Load filename local rootNode = (meshinstance.createInstance forLightmap s) destroyDialog rolWorkingStatus return rootNode ) --test --bf2ImportMeshFile_new undefined 0 10 | |||
2017-08-12, 07:36 | #37 |
PR:BF2 Contributor
Join Date: Jun 2017
Posts: 44
Germany
|
Re: Experimental updated 3dsMax Tools. Newer Max versions support and more.
Hm, regarding the BundledMesh Skin import, I'm actually not sure anymore it's possible to always get it correctly, without having everything remain one single mesh (as you're doing right now). Since really all the skin mod does on export is change which node the vertex belongs to, leaving no information which it belonged to originally in the scene.
I guess maybe if we do weld identical vertices and then afterwards split off only those vertices belonging to a node other then the main node that represent an independent element. Assuming of course that skin is only ever applied to nodes that are connected to the main mesh, which should mostly be the case for tank threads. However mostly not the case for dampers on retractable landing gears on aircraft, I don't think we can get those correctly at all... Also, skinnedmesh import seems to work great! I'll try to integrate that somehow, since I think it will be useful for 3P animating. |
2017-08-12, 08:37 | #38 |
Retired PR Developer
|
Re: Experimental updated 3dsMax Tools. Newer Max versions support and more.
I thought of a small feature request. In Rhino's LM tutorial there's a section where staticobjects.con is imported but you have to move the folders out so 3ds Max doesn't import actual meshes, just positions as helpers. Could you add that as a script, importing positions only from staticobjects.con? I know you improved importing OG for LMing here, but I found other uses for importing positions.
|
|
|
2017-08-12, 15:16 | #39 |
Join Date: Feb 2016
Posts: 51
Norway
|
Re: Experimental updated 3dsMax Tools. Newer Max versions support and more.
This is great!
|
2017-08-14, 10:34 | #40 |
PR:BF2 Lead Developer
|
Re: Experimental updated 3dsMax Tools. Newer Max versions support and more.
The new animation tools are really nice. I am no animator myself, but since we currently have none I often have to do minor adjustments and fixes for new weapons and such. The new tools will help a lot with that especially having the soldier mesh in 3p, something our past animators never bothered to add to their scenes
I have one issue tho, I cannot create templates. How do I create the first template? |
Mineral: TIL that Wire-guided missiles actually use wire
|
|
Tags |
3dsmax, experimental, max, newer, support, tools, updated, vbf2 or pr, versions |
|
|