I was wondering if there was a script to automatically (and reliably!) delete backfaces based on a moving camera ( or cameras)? It seems like a great task for a script or a robot, but here we are doing it by hand...
It makes no sense.
polyboost or max2010 lets you select faces that are facing to the perspective, with ctrl + i you can select the inverse.
It ccould be though that you need to do that multiple times with a moving camera and perhaps write some script that merges the inverted selections to a whole.
why not addative select the polys at multiple points along the cameras path, then invert to get the ones not needed, did this befor and it seamed to work quite well, but it depends on how complex the scene is and how many camera veiws you have
Hi MightyPea,
here is a function to do the job: feed it with an Editable Poly/Mesh, a camera and a frame range, and it will select all faces facing backward relative to camera in every frame of specified range. Let me know if you need a Floater with some interface.
function getBackFacesInRange obj camScan iFrameA iFrameZ =
(
local p3ViewDir = [0,0,0]
local p3ViewPos = [0,0,0]
local p3FaceCenter = [0,0,0]
local p3ScanDir = [0,0,0]
if (classOf obj == Editable_Poly) then
(
local baFaces = #{1..(polyOp.getNumFaces obj)}
local baBackFaces = baFaces
local baFrameBackFaces = #{}
for iFrame = iFrameA to iFrameZ by 1 do
(
at time iFrame
(
p3ViewDir = -camScan.transform.row3
p3ViewPos = camScan.position
baFrameBackFaces = #{}
for iFace in baFaces do
(
p3FaceCenter = polyOp.getSafeFaceCenter obj iFace
if (p3FaceCenter == undefined) then
p3FaceCenter = polyOp.getFaceCenter obj iFace
if (camScan.orthoProjection) then
p3ScanDir = p3ViewDir
else
p3ScanDir = normalize (p3FaceCenter - p3ViewPos)
p3FaceNormal = polyOp.getFaceNormal obj iFace
if ((dot p3FaceNormal p3ScanDir) > 0) then
baFrameBackFaces[iFace] = true
)
baBackFaces *= baFrameBackFaces
)
)
-- for visual feedback only
polyOp.setFaceSelection obj baBackFaces
)
else if (classOf obj == Editable_Mesh) then
(
local baFaces = #{1..(meshOp.getNumFaces obj)}
local baBackFaces = baFaces
local baFrameBackFaces = #{}
for iFrame = iFrameA to iFrameZ by 1 do
(
at time iFrame
(
p3ViewDir = -camScan.transform.row3
p3ViewPos = camScan.position
baFrameBackFaces = #{}
for iFace in baFaces do
(
p3FaceCenter = meshOp.getFaceCenter obj iFace
if (camScan.orthoProjection) then
p3ScanDir = p3ViewDir
else
p3ScanDir = normalize (p3FaceCenter - p3ViewPos)
p3FaceNormal = getFaceNormal obj iFace
if ((dot p3FaceNormal p3ScanDir) > 0) then
baFrameBackFaces[iFace] = true
)
baBackFaces *= baFrameBackFaces
)
)
-- for visual feedback only
setFaceSelection obj baBackFaces
)
else
(
throw "Wrong input in function getBackFacesInRange()"
)
return baBackFaces
)
Here is my version of this thing ,it works on Editable Poly only with no instances, it evaluates all the geometry in the scene
/*****************************************************************************************************************
Made by: Popescu Alexandru Cristian (KIKI) kiki_karon@yahoo.com
Script: Camera_Culling v10.
Description : It tryes to delete the sceen tris that are not visible for the selected camera.
******************************************************************************************************************/
struct TKey
(
Number,
objectList
)
struct TObject
(
objectName,
visFaces
)
--make all names in scene unique
function polyop_UniqueName=
(
for o in objects do
(
if ((classof o) == Editable_Poly) do
(
o.name = (uniquename o.name);
)
)
)
--break grup
function break_Grup =
(
for o in objects do
(
if (isGroupHead o) do
(
ungroup o
)
)
)
function object_Delete_Vertex0_objects object_list =
(
for o in objects do
(
if ( (classof o) == Editable_Poly) do
(
if (o.Verts.Count < 0) do
(
delete o
)
)
)
)
--test if the object bounding sphere is in camera bounding sphere
function object_in_cameraspace camera obj =
(
tanC = tan (camera.FOV /2);
obj_center = obj.center * (inverse camera.transform);
obj_centerZ = -obj_center.z;
obj_center = ([1,1,1] + obj_center) / obj_centerZ/ tanC;
obj_center.y = obj_center.y*(getRendImageAspect());
obj_max = obj.max * (inverse camera.transform);
obj_maxZ = -obj_max.z;
obj_max = ([1,1,1] + obj_max ) / obj_maxZ/ tanC;
obj_max.y = obj_max.y*(getRendImageAspect());
obj_distance = (distance obj_center obj_max);
if (distance [obj_center.x,obj_center.y] [0,0]) < (obj_distance + 1.5) do
(
return true;
)
return false;
)
function Select_Visible_Poly camera obj BFC_factor =
(
vis_poly = #()
the_tan = (tan (camera.FOV/2));
for p in obj.Faces do
(
--BFC
normal = polyop.GetFaceNormal obj p.index
lookAtCamera = dot camera.dir normal
if (lookAtCamera > BFC_factor) do
(
verts = (polyop.getVertsUsingFace obj p)
vis_Verts = false;
ScreenSpace_Verts = #()
----
iterate_in_verts = true;
for v in verts do
(
if iterate_in_verts do
(
--world pos
pos_W_v = polyop.getVert obj v;
--camera pos
pos_C_v = (pos_W_v * (inverse camera.transform));
--screen space
if (pos_C_v.z < 0) do
(
the_z = -pos_C_v.z
pos_S_v = ([1,1,1] + pos_C_v)/ the_z / the_tan;
pos_S_v.y = pos_S_v.y*(getRendImageAspect());
--for the polys with verts outside of the frustum test
append ScreenSpace_Verts pos_S_v;
--Frustum
testA = ((pos_S_v.x < 1) and (pos_S_v.x > -1) and (pos_S_v.y < 1) and (pos_S_v.y > -1))
if testA do
(
--append vis_Verts v;
vis_Verts = true;
--the calculations become irelevant after one relevant vert
iterate_in_verts = false;
--print v
)
)
)
)
--test for polys with verts outside of the frustum
if (iterate_in_verts == true) do
(
Verts_Type = #()
for ssp in ScreenSpace_Verts do
(
--XP =
if (ssp.x > 1) and (ssp.y < 1) and (ssp.y > -1) do
(
append Verts_Type 1
)
--XN =
if (ssp.x < -1) and (ssp.y < 1) and (ssp.y > -1) do
(
append Verts_Type 2
)
--YP =
if (ssp.y > 1) and (ssp.x < 1) and (ssp.x > -1) do
(
append Verts_Type 3
)
--YN =
if (ssp.y < -1) and (ssp.x < 1) and (ssp.x > -1) do
(
append Verts_Type 4
)
--CXP1
if (ssp.x > 1) and (ssp.y > 1) and (ssp.y > -1) do
(
append Verts_Type 5
)
--CXP2
if (ssp.x > 1) and (ssp.y < 1) and (ssp.y < -1) do
(
append Verts_Type 6
)
--CXNP1
if (ssp.x < -1) and (ssp.y > 1) and (ssp.y > -1) do
(
append Verts_Type 7
)
--CXNP2
if (ssp.x < -1) and (ssp.y < 1) and (ssp.y < -1) do
(
append Verts_Type 8
)
)
for ver_tC = 1 to Verts_Type.Count do
(
ver_t = Verts_Type[ver_tC];
for ver_t2C = 1 to Verts_Type.Count do
(
if (ver_tC != ver_t2C) do
(
ver_t2 = Verts_Type[ver_t2C];
if (ver_t == 1) and ((ver_t2 == 2) or (ver_t2 == 8) or (ver_t2 == 7) or (ver_t2 == 3) or (ver_t2 == 4)) do
(
vis_Verts = true;
)
if (ver_t == 2) and ((ver_t2 == 1) or (ver_t2 == 3) or (ver_t2 == 4) or (ver_t2 == 5) or (ver_t2 == 6)) do
(
vis_Verts = true;
)
if (ver_t == 3) and ((ver_t2 == 1) or (ver_t2 == 2) or (ver_t2 == 5) or (ver_t2 == 4) or (ver_t2 == 7)) do
(
vis_Verts = true;
)
if (ver_t == 4) and ((ver_t2 == 1) or (ver_t2 == 6) or (ver_t2 == 3) or (ver_t2 == 8) or (ver_t2 == 2)) do
(
vis_Verts = true;
)
if (ver_t == 5) and ((ver_t2 == 3) or (ver_t2 == 8) or (ver_t2 == 2)) do
(
vis_Verts = true;
)
if (ver_t == 6) and ((ver_t2 == 4) or (ver_t2 == 7) or (ver_t2 == 2)) do
(
vis_Verts = true;
)
if (ver_t == 7) and ((ver_t2 == 1) or (ver_t2 == 6) or (ver_t2 == 3)) do
(
vis_Verts = true;
)
if (ver_t == 8) and ((ver_t2 == 1) or (ver_t2 == 5) or (ver_t2 == 4)) do
(
vis_Verts = true;
)
)
)
)
Verts_Type = undefined;
)
if (vis_Verts == true) do
(
append vis_poly p.index;
)
ScreenSpace_Verts = undefined;
)
)
--polyop.SetFaceSelection obj vis_poly
--cleen used memory
GC();
return vis_poly;
)
function polyop_SetTKey frameNum CameraI Threshold =
(
sliderTime = (frameNum as time);
curent_key = TKey();
curent_key.Number = frameNum;
curent_key.objectList = #();
for o in objects do
(
if (((classof o) == Editable_Poly) and (object_in_cameraspace CameraI o)) do
(
curent_obj = TObject();
curent_obj.objectName = o.name;
curent_obj.visFaces = (Select_Visible_Poly CameraI o Threshold)
append curent_key.objectList curent_obj;
)
)
return curent_key
)
function polyop_Generate_TKeyArray Camera BFC_Threshold fstar fend =
(
if (fstar == fend) then
(
animationRange = interval fstar (fend+1);
)
else
(
animationRange = interval fstar fend;
)
--we are forring through this values so the fstar should allways be smaller then fend
if (fstar > fend) do
(
temp = fstar;
fstar = fend;
fend = temp;
)
total_range = (fend - fstar);
TKeyArray = #()
progressStart "Culling";
progressUpdate 1;
for t = (fstar) to (fend) do
(
range = (t - fstar)
ratio = 1;
if (range > 0) do
(
ratio = (100*range)/total_range;
)
progres = (ratio);
cont = progressUpdate (progres);
if (not(cont)) do
(
progressEnd();
return TKeyArray;
)
Tkey_t = polyop_SetTKey t Camera BFC_Threshold ;
append TKeyArray Tkey_t;
)
progressEnd();
return TKeyArray
)
function polyop_Generate_VisibleFaceSelection Camera BFC_Threshold fstar fend =
(
lTKeyArray = polyop_Generate_TKeyArray Camera BFC_Threshold fstar fend ;
for o in objects do
(
if ((classof o) == Editable_Poly) do
(
--
finalSelection = #()
--
for lTkey in lTKeyArray do
(
for lTObject in lTkey.objectList do
(
if (lTObject.objectName == o.name) do
(
for sf in lTObject.visFaces do
(
if ((findItem finalSelection sf) == 0) do
(
append finalSelection sf
)
)
)
)
)
polyop.SetFaceSelection o finalSelection;
)
)
)
function polyop_Delete_non_Selected_Faces object_list =
(
for o in object_list do
(
if ((classof o) == Editable_Poly) do
(
deleted_faces = #();
Selected_Faces2 = ((polyop.GetFaceSelection o) as array);
for F in o.Faces do
(
if ((findItem Selected_Faces2 F.index) == 0) do
(
append deleted_faces F.index;
)
)
polyOP.DeleteFaces o deleted_faces delIsoVerts:true;
)
)
)
function polyop_Delete_non_Visible_Polys Camera BFC_Threshold fstar fend =
(
break_Grup();
polyop_UniqueName();
polyop_Generate_VisibleFaceSelection Camera BFC_Threshold fstar fend ;
--sometimes max misses a few things, call the cleen functions more then oance...
polyop_Delete_non_Selected_Faces objects;
polyop_Delete_non_Selected_Faces objects;
object_Delete_Vertex0_objects objects;
object_Delete_Vertex0_objects objects;
object_Delete_Vertex0_objects objects;
)
--Select_Visible_Poly -0.2
--interface
rollout cullingRollout "Camera Culling rev 10.0" width:240 height:230
(
button btn1 "Delete invisible polys for the selected camera" pos:[8,114] width:225 height:36
pickbutton select_cameraB "Select the camera" pos:[8,74] width:225 height:36
spinner bfc_t "BFC threshold" pos:[48,10] width:90 height:16 enabled:true range:[-1,1,-0.2] type:#float scale:0.01
spinner frame_start "Start Frame " pos:[48,32] width:90 height:16 enabled:true range:[-100000,100000,0] type:#integer scale:1
spinner frame_end "End Frame " pos:[48,54] width:90 height:16 enabled:true range:[-100000,100000,100] type:#integer scale:1
label lbl1 " Go to: n Edit->Fetch for undon --------------------------------n Popescu Alexandru Cristian n kiki_karon@yahoo.com" pos:[5,154] width:311 height:80
on cullingRollout close do
(
global cullingRollout_available_hash123rttyh2 = false;
)
on select_cameraB picked obj do
(
if (((classof obj) == Freecamera ) or ((classof obj) == Targetcamera)) do
(
select_cameraB.text = obj.name
)
)
on btn1 pressed do
(
if (select_cameraB.text != "Select the camera") do
(
if (isDeleted select_cameraB.object) do
(
select_cameraB.text = "Select the camera";
)
if ((not(isDeleted select_cameraB.object)) and (select_cameraB.object != undefined) and (select_cameraB.text != "Select the camera")) do
(
holdMaxFile();
init_num_poly = 0;
for o in objects do
(
init_num_poly += (GetTriMeshFaceCount o)[1];
)
if (heapSize < 32000000) do
(
--set the max memory the script can use to 32MB;
heapSize = 32000000;
)
--this is a max-shit safe frame problem haxor fix
old_fov = select_cameraB.object.FOV ;
select_cameraB.object.FOV = select_cameraB.object.FOV + (select_cameraB.object.FOV * 0.1);
--
polyop_Delete_non_Visible_Polys select_cameraB.object bfc_t.Value frame_start.Value frame_end.Value;
select_cameraB.object.FOV = old_fov;
final_num_poly = 0;
for o in objects do
(
final_num_poly += (GetTriMeshFaceCount o)[1];
)
MessageBox ("Number of triangles deleted :" + ((init_num_poly - final_num_poly) as string)) title:"Culling" beep:false ;
object_Delete_Vertex0_objects objects;
)
)
)
)
--only one instance of this dialog available
if (cullingRollout_available_hash123rttyh2 != true) do
(
createdialog cullingRollout;
global cullingRollout_available_hash123rttyh2 = true;
)
--If you see any problems with this script, and you have the time, write me an email (kiki_karon@yahoo.com)
/*
-This is versio 9 of this script,the first official version
-We are now at version 10 of this script,function object_in_cameraspace was added, and used in polyop_SetTKey,it is a simple bounding sphere test,object versus camera space
*/
--If you see any problems with this script, and you have the time, write me an email (kiki_karon@yahoo.com)
Hi Razor, this is quite an ancient thread. I almost forgot about this script. I'm quite sure it is possible to take into account multiple cameras.
You must be aware that this script takes into account only camera view direction, and not camera frustum. It is something I'd like to code and include in the new set of instrument I'm currently developing. I've just taken note about your request and will do my best to add it to upcoming version. Thank you.
Anyway if you need it promptly, I can update this one to multiple cameras. Please let me know.
Replies
It ccould be though that you need to do that multiple times with a moving camera and perhaps write some script that merges the inverted selections to a whole.
here is a function to do the job: feed it with an Editable Poly/Mesh, a camera and a frame range, and it will select all faces facing backward relative to camera in every frame of specified range. Let me know if you need a Floater with some interface.
I had some free time, so here is the script with a simple interface.
When I worked on Elite Force 2 (first person shooter), I used this script to delete polygons that never faced the camera during animation.
The script may need to be updated a little, since it's a little old....
You must be aware that this script takes into account only camera view direction, and not camera frustum. It is something I'd like to code and include in the new set of instrument I'm currently developing. I've just taken note about your request and will do my best to add it to upcoming version. Thank you.
Anyway if you need it promptly, I can update this one to multiple cameras. Please let me know.