{"name":"lineIntersectsSurfaces","operator":null,"title":"lineIntersectsSurfaces","type":"command","url":"https://community.bistudio.com/wiki/lineIntersectsSurfaces","revid":377700,"updated":"2026-01-02T09:03:29Z","groups":["Math - Geometry"],"status":"ok","replaced_by":[],"games":[{"game":"arma3","name":"Arma 3","version":"1.50"}],"since":{"game":"arma3","name":"Arma 3","version":"1.50"},"arma3_since":"1.50","branch":null,"locality":{"argument":"global","effect":null,"server_exec":false},"exec":null,"description":"Returns a list of intersections with surfaces and ground from *begPosASL* to *endPosASL*. Doesn't return intersection with sea surface. Works underwater, unlike lineIntersects. Hardcoded max distance: 5000m.\n\n> [!IMPORTANT]\n> - if *begPosASL* is under the ground and *endPosASL* is above it, the command will only return intersection with the ground, this is an engine limitation and none of the intersectXXX commands will work when initiated from under the ground.\n> - only a single LOD is checked for intersection. LOD2 will only be checked if LOD1 is unavailable.\n\nSince Arma 3 v2.20, there is an alternative syntax that does multiple checks in parallel, faster than multiple calls.","syntaxes":[{"syntax":"lineIntersectsSurfaces [begPosASL, endPosASL, ignoreObj1, ignoreObj2, sortMode, maxResults, LOD1, LOD2, returnUnique]","since":null,"effect":null,"exec":null,"params":[{"name":"begPosASL","type":"PositionASL","optional":false,"default":null,"description":"virtual line start","types":["PositionASL"],"since":null,"text":"begPosASL: PositionASL - virtual line start"},{"name":"endPosASL","type":"PositionASL","optional":false,"default":null,"description":"virtual line end","types":["PositionASL"],"since":null,"text":"endPosASL: PositionASL - virtual line end"},{"name":"ignoreObj1","type":"Object","optional":true,"default":"objNull","description":"first object to ignore","types":["Object"],"since":null,"text":"ignoreObj1: Object - (Optional, default objNull) first object to ignore"},{"name":"ignoreObj2","type":"Object","optional":true,"default":"objNull","description":"second object to ignore","types":["Object"],"since":null,"text":"ignoreObj2: Object - (Optional, default objNull) second object to ignore"},{"name":"sortMode","type":"Boolean","optional":true,"default":"true","description":"true: closest to furthest, false: furthest to closest","types":["Boolean"],"since":null,"text":"sortMode: Boolean -  (Optional, default true) true: closest to furthest, false: furthest to closest"},{"name":"maxResults","type":"Number","optional":true,"default":"1","description":"max results to return. -1 to return every result","types":["Number"],"since":null,"text":"maxResults: Number - (Optional, default 1) max results to return. -1 to return every result"},{"name":"LOD1","type":"String","optional":true,"default":"\"VIEW\"","description":"primary LOD to look for intersection. Can be one of:\n- \"FIRE\"\n- \"VIEW\"\n- \"GEOM\"\n- \"IFIRE\" - (\"I\" stands for Indirect, *almost* identical to \"FIRE\")\n- \"NONE\"\n- Arma 3 v2.02 \"PHYSX\" - PhysX geometry LOD\n- Arma 3 v2.08 \"ROADWAY\" - only works from the top","types":["String"],"since":"arma3 1.52","text":"LOD1: String - (Optional, default \"VIEW\") primary LOD to look for intersection. Can be one of:\n- \"FIRE\"\n- \"VIEW\"\n- \"GEOM\"\n- \"IFIRE\" - (\"I\" stands for Indirect, *almost* identical to \"FIRE\")\n- \"NONE\"\n- Arma 3 v2.02 \"PHYSX\" - PhysX geometry LOD\n- Arma 3 v2.08 \"ROADWAY\" - only works from the top"},{"name":"LOD2","type":"String","optional":true,"default":"\"FIRE\"","description":"secondary LOD to look for intersection. See *LOD1* for possible values","types":["String"],"since":"arma3 1.52","text":"LOD2: String - (Optional, default \"FIRE\") secondary LOD to look for intersection. See *LOD1* for possible values"},{"name":"returnUnique","type":"Boolean","optional":true,"default":"true","description":"when false, all intersections in the same object are included, otherwise only the first one","types":["Boolean"],"since":"arma3 1.70","text":"returnUnique: Boolean - (Optional, default true) when false, all intersections in the same object are included, otherwise only the first one"}],"returns":{"type":"Array of Arrays with [intersectPosASL, surfaceNormal, intersectObj, parentObject, selectionNames, pathToBisurf]","types":["Array"],"description":"intersectPosASL: PositionASL - the actual position where line intersects surface - surfaceNormal: Vector - a normal to the intersected surface - intersectObject: Object - the object the surface belongs to (could be proxy object) - objNull if terrain - parentObject: Object - the object proxy object belongs to (not always the same as intersect object) - objNull if terrain - Arma 3 v2.10 selectionNames: Array of Strings - Names of the intersected selections (bones). Returns `[]` if there is no intersection with a selection. - Arma 3 v2.10 pathToBisurf: String - path to intersected surface properties (.bisurf) file. Returns `\"\"` if surface has no special properties. Terrain surface properties begin with `1.`, and the surface properties are defined in `CfgSurfaces`. For example, if it returns `1. GdtVRsurface01`, properties are defined in: `configFile >> \"CfgSurfaces\" >> \"GdtVRsurface01\"`","text":"Array of Arrays with [intersectPosASL, surfaceNormal, intersectObj, parentObject, selectionNames, pathToBisurf]\n- intersectPosASL: PositionASL - the actual position where line intersects surface\n- surfaceNormal: Vector - a normal to the intersected surface\n- intersectObject: Object - the object the surface belongs to (could be proxy object) - objNull if terrain\n- parentObject: Object - the object proxy object belongs to (not always the same as intersect object) - objNull if terrain\n- Arma 3 v2.10 selectionNames: Array of Strings - Names of the intersected selections (bones). Returns `[]` if there is no intersection with a selection.\n- Arma 3 v2.10 pathToBisurf: String - path to intersected surface properties (.bisurf) file. Returns `\"\"` if surface has no special properties. Terrain surface properties begin with `1.`, and the surface properties are defined in `CfgSurfaces`. For example, if it returns `1. GdtVRsurface01`, properties are defined in: `configFile >> \"CfgSurfaces\" >> \"GdtVRsurface01\"`"},"form":"unary","operator":null,"left":null,"right":{"text":"[begPosASL, endPosASL, ignoreObj1, ignoreObj2, sortMode, maxResults, LOD1, LOD2, returnUnique]","types":["Array"]}},{"syntax":"lineIntersectsSurfaces [[element1, element2, ...]]","since":"arma3 2.20","effect":null,"exec":null,"params":[{"name":"elementN","type":null,"optional":true,"default":"objNull","description":"Array with [begPosASL, endPosASL, ignoreObj1, ignoreObj2, sortMode, maxResults, LOD1, LOD2, returnUnique]\n- begPosASL: PositionASL - virtual line start\n- endPosASL: PositionASL - virtual line end\n- ignoreObj1: Object -  first object to ignore\n- ignoreObj2: Object - (Optional, default objNull) second object to ignore\n- sortMode: Boolean -  (Optional, default true) true: closest to furthest, false: furthest to closest\n- maxResults: Number - (Optional, default 1) max results to return. -1 to return every result\n- LOD1: String - (Optional, default \"VIEW\") primary LOD to look for intersection. Can be one of:\n  - \"FIRE\"\n  - \"VIEW\"\n  - \"GEOM\"\n  - \"IFIRE\" - (\"I\" stands for Indirect, *almost* identical to \"FIRE\")\n  - \"NONE\"\n  - \"PHYSX\" - PhysX geometry LOD\n  - \"ROADWAY\" - only works from the top\n- LOD2: String - (Optional, default \"FIRE\") secondary LOD to look for intersection. See *LOD1* for possible values\n- returnUnique: Boolean - (Optional, default true) when false, all intersections in the same object are included, otherwise only the first one","types":["Array"],"since":null,"text":"elementN: Array with [begPosASL, endPosASL, ignoreObj1, ignoreObj2, sortMode, maxResults, LOD1, LOD2, returnUnique]\n- begPosASL: PositionASL - virtual line start\n- endPosASL: PositionASL - virtual line end\n- ignoreObj1: Object - (Optional, default objNull) first object to ignore\n- ignoreObj2: Object - (Optional, default objNull) second object to ignore\n- sortMode: Boolean -  (Optional, default true) true: closest to furthest, false: furthest to closest\n- maxResults: Number - (Optional, default 1) max results to return. -1 to return every result\n- LOD1: String - (Optional, default \"VIEW\") primary LOD to look for intersection. Can be one of:\n  - \"FIRE\"\n  - \"VIEW\"\n  - \"GEOM\"\n  - \"IFIRE\" - (\"I\" stands for Indirect, *almost* identical to \"FIRE\")\n  - \"NONE\"\n  - \"PHYSX\" - PhysX geometry LOD\n  - \"ROADWAY\" - only works from the top\n- LOD2: String - (Optional, default \"FIRE\") secondary LOD to look for intersection. See *LOD1* for possible values\n- returnUnique: Boolean - (Optional, default true) when false, all intersections in the same object are included, otherwise only the first one"}],"returns":{"type":"Array of Arrays with [intersectPosASL, surfaceNormal, intersectObj, parentObject, selectionNames, pathToBisurf]","types":["Array"],"description":"intersectPosASL: PositionASL - the actual position where line intersects surface - surfaceNormal: Vector - a normal to the intersected surface - intersectObject: Object - the object the surface belongs to (could be proxy object) - objNull if terrain - parentObject: Object - the object proxy object belongs to (not always the same as intersect object) - objNull if terrain - selectionNames: Array of Strings - Names of the intersected selections (bones). Returns `[]` if there is no intersection with a selection. - pathToBisurf: String - path to intersected surface properties (.bisurf) file. Returns `\"\"` if surface has no special properties. Terrain surface properties begin with `1.`, and the surface properties are defined in `CfgSurfaces`. For example, if it returns `1. GdtVRsurface01`, properties are defined in: `configFile >> \"CfgSurfaces\" >> \"GdtVRsurface01\"`","text":"Array of Arrays with [intersectPosASL, surfaceNormal, intersectObj, parentObject, selectionNames, pathToBisurf]\n- intersectPosASL: PositionASL - the actual position where line intersects surface\n- surfaceNormal: Vector - a normal to the intersected surface\n- intersectObject: Object - the object the surface belongs to (could be proxy object) - objNull if terrain\n- parentObject: Object - the object proxy object belongs to (not always the same as intersect object) - objNull if terrain\n- selectionNames: Array of Strings - Names of the intersected selections (bones). Returns `[]` if there is no intersection with a selection.\n- pathToBisurf: String - path to intersected surface properties (.bisurf) file. Returns `\"\"` if surface has no special properties. Terrain surface properties begin with `1.`, and the surface properties are defined in `CfgSurfaces`. For example, if it returns `1. GdtVRsurface01`, properties are defined in: `configFile >> \"CfgSurfaces\" >> \"GdtVRsurface01\"`"},"form":"unary","operator":null,"left":null,"right":{"text":"[[element1, element2, ...]]","types":["Array"]}}],"examples":[{"text":"```sqf\n_intersections = lineIntersectsSurfaces [eyePos player, aimPos chopper, player, chopper, true, -1];\n```","code":["_intersections = lineIntersectsSurfaces [eyePos player, aimPos chopper, player, chopper, true, -1];"]},{"text":"```sqf\narrow = \"Sign_Arrow_F\" createVehicle [0,0,0];\nonEachFrame {\n    _ins = lineIntersectsSurfaces [\n        AGLToASL positionCameraToWorld [0,0,0], \n        AGLToASL positionCameraToWorld [0,0,1000], \n        player\n    ];\n    if (count _ins == 0) exitWith { arrow setPosASL [0,0,0] };\n    arrow setPosASL (_ins select 0 select 0);\n    arrow setVectorUp (_ins select 0 select 1);\n    hintSilent str _ins;\n};\n```","code":["arrow = \"Sign_Arrow_F\" createVehicle [0,0,0];\nonEachFrame {\n\t_ins = lineIntersectsSurfaces [\n\t\tAGLToASL positionCameraToWorld [0,0,0], \n\t\tAGLToASL positionCameraToWorld [0,0,1000], \n\t\tplayer\n\t];\n\tif (count _ins == 0) exitWith { arrow setPosASL [0,0,0] };\n\tarrow setPosASL (_ins select 0 select 0);\n\tarrow setVectorUp (_ins select 0 select 1);\n\thintSilent str _ins;\n};"]},{"text":"This should detect glass windows and wire fences (since Arma 3 v1.52):\n\n```sqf\nwirefence = \"Land_New_WiredFence_5m_F\" createVehicle position player;\narrow = \"Sign_Arrow_F\" createVehicle [0,0,0];\nonEachFrame {\n    _ins = lineIntersectsSurfaces [\n        AGLToASL positionCameraToWorld [0,0,0], \n        AGLToASL positionCameraToWorld [0,0,1000], \n        player,\n        objNull,\n        true,\n        1,\n        \"GEOM\",\n        \"NONE\"\n    ];\n    if (count _ins == 0) exitWith { arrow setPosASL [0,0,0] };\n    arrow setPosASL (_ins select 0 select 0);\n    arrow setVectorUp (_ins select 0 select 1);\n    hintSilent str _ins;\n};\n```","code":["wirefence = \"Land_New_WiredFence_5m_F\" createVehicle position player;\narrow = \"Sign_Arrow_F\" createVehicle [0,0,0];\nonEachFrame {\n\t_ins = lineIntersectsSurfaces [\n\t\tAGLToASL positionCameraToWorld [0,0,0], \n\t\tAGLToASL positionCameraToWorld [0,0,1000], \n\t\tplayer,\n\t\tobjNull,\n\t\ttrue,\n\t\t1,\n\t\t\"GEOM\",\n\t\t\"NONE\"\n\t];\n\tif (count _ins == 0) exitWith { arrow setPosASL [0,0,0] };\n\tarrow setPosASL (_ins select 0 select 0);\n\tarrow setVectorUp (_ins select 0 select 1);\n\thintSilent str _ins;\n};"]},{"text":"Alternative syntax to check intersections in parallel. Will draw a redline to the first intersecting object between the player and unit:\n\n```sqf\nprivate _handle = addMissionEventHandler [\"Draw3D\", {\n    private _enemies = units opfor;\n    private _enemyDataArray = _enemies apply { [eyePos player, eyePos _x, player, _x] };\n    \n    private _intersections = lineIntersectsSurfaces [_enemyDataArray];\n    {\n        // No intersections found, draw green '+' icon at unit\n        if (_x isEqualTo []) then {\n            drawIcon3D [\n                \"\\a3\\ui_f\\data\\gui\\cfg\\cursors\\add_gs.paa\",\n                [0, 1, 0, 1],\n                ASLToAGL (eyePos (_enemies#_forEachIndex)),\n                0.5, 0.5, 0,\n                str (_enemies#_forEachIndex)\n            ];\n        } else {\n            private _firstIntersection = _x#0;\n            // Draw red line and '+' icon to first intersecting object\n            drawIcon3D [\n                \"\\a3\\ui_f\\data\\gui\\cfg\\cursors\\add_gs.paa\",\n                [1, 0, 0, 1],\n                ASLToAGL (_firstIntersection#0),\n                0.5, 0.5, 0,\n                str (_enemies#_forEachIndex) + \"- Blocked by \" + str (_firstIntersection#2)\n            ];\n            drawLine3D [\n                ASLToAGL (eyePos player),\n                ASLToAGL (_firstIntersection#0),\n                [1, 0, 0, 1],\n                5\n            ];\n        };\n    } forEach _intersections;\n}];\n```","code":["private _handle = addMissionEventHandler [\"Draw3D\", {\n\tprivate _enemies = units opfor;\n\tprivate _enemyDataArray = _enemies apply { [eyePos player, eyePos _x, player, _x] };\n\t\n\tprivate _intersections = lineIntersectsSurfaces [_enemyDataArray];\n\t{\n\t\t// No intersections found, draw green '+' icon at unit\n\t\tif (_x isEqualTo []) then {\n\t\t\tdrawIcon3D [\n\t\t\t\t\"\\a3\\ui_f\\data\\gui\\cfg\\cursors\\add_gs.paa\",\n\t\t\t\t[0, 1, 0, 1],\n\t\t\t\tASLToAGL (eyePos (_enemies#_forEachIndex)),\n\t\t\t\t0.5, 0.5, 0,\n\t\t\t\tstr (_enemies#_forEachIndex)\n\t\t\t];\n\t\t} else {\n\t\t\tprivate _firstIntersection = _x#0;\n\t\t\t// Draw red line and '+' icon to first intersecting object\n\t\t\tdrawIcon3D [\n\t\t\t\t\"\\a3\\ui_f\\data\\gui\\cfg\\cursors\\add_gs.paa\",\n\t\t\t\t[1, 0, 0, 1],\n\t\t\t\tASLToAGL (_firstIntersection#0),\n\t\t\t\t0.5, 0.5, 0,\n\t\t\t\tstr (_enemies#_forEachIndex) + \"- Blocked by \" + str (_firstIntersection#2)\n\t\t\t];\n\t\t\tdrawLine3D [\n\t\t\t\tASLToAGL (eyePos player),\n\t\t\t\tASLToAGL (_firstIntersection#0),\n\t\t\t\t[1, 0, 0, 1],\n\t\t\t\t5\n\t\t\t];\n\t\t};\n\t} forEach _intersections;\n}];"]}],"multiplayer":null,"problems":null,"aliases":[],"see_also":["lineIntersectsObjs","lineIntersectsWith","lineIntersects","terrainIntersectASL","terrainIntersectAtASL","terrainIntersect","intersect","cursorObject","cursorTarget","checkVisibility"],"notes":[{"user":"Killzone_Kid","date":"2015-08-27T12:44:00Z","text":"Fast check if the player is in a house:\n\n```sqf\nKK_fnc_inHouse = {\n    lineIntersectsSurfaces [\n        getPosWorld _this, \n        getPosWorld _this vectorAdd [0, 0, 50], \n        _this, objNull, true, 1, \"GEOM\", \"NONE\"\n    ] select 0 params [\"\",\"\",\"\",\"_house\"];\n    if (_house isKindOf \"House\") exitWith { true };\n    false\n};\nonEachFrame { hintSilent str (player call KK_fnc_inHouse) };\n```"},{"user":"Pierre MGI","date":"2016-01-30T20:10:00Z","text":"This command is useful to place weaponholder (and then spawned weapons) on floor of houses, correcting  the spawn position (can_collide) to intersect with floor:\n\n```sqf\nMGI_fnc_setPosAGLS = {\n    params [\"_obj\", \"_pos\"];\n    _wh_pos = getPosASL _obj;\n\n    _pos set [2, (ATLToASL _pos select 2) - 10];\n    _ins = lineIntersectsSurfaces [_wh_pos, _pos,_obj, objNull, true, 1, \"VIEW\", \"FIRE\"];\n    _surface_distance = if (count _ins > 0) then [{ (_ins select 0 select 0) distance _wh_pos }, { 0 }];\n    _wh_pos set [2, (getPosASL _obj select 2) - (_surface_distance)];\n    _weaponholder setPosASL _wh_pos;\n};\n```\n\nAfter the position (_pos) obtained in BIS_fnc_buidingPositions array:\n\n```sqf\nprivate _weaponHolder = createVehicle [\"groundWeaponHolder\", _pos, [], 0, \"CAN_COLLIDE\"];\n[_weaponHolder, _pos] call MGI_fnc_setPosAGLS;\n```\n\nThen fill your weapon holder."},{"user":"Tankbuster","date":"2024-01-06T15:41:15Z","text":"Note that dome_big and dome_small objects have glass roof panels which this function can't see if it intersects those windows"}],"categories":["Arma 3: New Scripting Commands","Arma 3: Scripting Commands","Command Group: Math - Geometry","Introduced with Arma 3 version 1.50","Scripting Commands"]}