4
\$\begingroup\$

I'm not using the Unity Terrain because it lacks certain features.

Amongst them, you cannot tile them: enter image description here

You cannot create concave walls or make holes in it: enter image description here

No custom textures, no detail textures, awful sculpting tools... the list goes on and on. So I imported my own Terrain as a Mesh. The collision works perfectly, however raycasting onto the Terrain is horribly inaccurate. Unity seems to compress the Mesh Collider depending on distance to player. See the video linked below. Since Unity is (by my knowledge) the only Game Engine that supports convex colliders, how do other game engines create Terrain colliders?

For a racing game or a RTS or RPG the colliders are no problem, but for a shooter it's unacceptable. Here's a video showing the problem:

https://youtu.be/coiFS6IT4wI

I've researched long and hard and there seems to be no known solution for this. So my question remains, if it's possible at all, how can i create large scale Terrains for Unity? This problem makes it completely impossible for me to create outdoor scenes. There HAS to be some kind of solution.


1) Raycasting script:

//Spread
        float spreadAmount = Mathf.Lerp(spreadMin, spreadMax, burstTimer / spreadThreshold); //Current Spread lerps between spreadMin and spreadMax by burstTimer (increases per shot)

        int i = 0;
        totalShotDamage = 0; //Buckshot sends 8 rays down the range. totalShotDamage gets total damage done by all rays. Needed for displaying damage text

        while (i < bulletCount) //Repeats Shooting Vector for bulletCount amount (needed for buckshot)
        {
            Vector3 shootDirection = shootOrigin.transform.forward; //Shoot Vector 100% accuracy

            shootDirection += shootOrigin.transform.right * (Random.Range(-spreadAmount, spreadAmount)); //Randomizes Vector horizontally, reduces accuracy
            shootDirection += shootOrigin.transform.up * (Random.Range(-spreadAmount, spreadAmount)); //Randomizes Vector Vectically, reduces accuracy

            Ray ray = new Ray(shootOrigin.transform.position, shootDirection); //Ray from Shoot vector
            RaycastHit hitInfo;

            if (Physics.Raycast(ray, out hitInfo, 2000, shootLayerMask)) //Sets range of gun & sends ray
            {
                Vector3 hitPoint = hitInfo.point; //Point of impact with any object
                GameObject go = hitInfo.collider.gameObject; //GameObject of impacted Object

                string targetTag = hitInfo.collider.gameObject.tag; //Tag of GameObject of impacted Object

                addHitParticleEffects(targetTag, hitInfo, enableBulletholes); //Add hitparticle effects based on Tag (IMPACTmaterial)
                damageEnemy(targetTag, hitInfo, damage, damageRollOff); //Damage enemy
            }
            i++; //total bullet count (needed for buckshot)
        }

2) Terrain Inspector Settings

enter image description here

3) LOD Settings

There are no LOD Settings (yet). Individual Planes of the whole Terrain and objects on top of it simply pop in and out of existence depending on the Players position.

\$\endgroup\$
1
  • \$\begingroup\$ Can you show us 1) the code you're using for raycasting, 2) the inspector configuration for your terrain's meshcollider, 3) any level of detail settings you're applying to the terrain meshes? \$\endgroup\$
    – DMGregory
    Commented Feb 12, 2018 at 16:22

2 Answers 2

4
+50
\$\begingroup\$

(1) Notes on terrain systems

Outdoor scenes are always a challenge to render and interact with, given viewing distance and subsequent complexity involved. This is just a reality of outdoor terrain. One often has to create one's own LoD systems (or at least heavily adapt those available) to get what one wants.

There is no way they can be both general purpose (as Unity's is) and fast / efficient; especially given all the other factors involved: static vs dynamic, LoD structure, etc. etc. Custom (concave) mesh-based collision is a very slow check, which is undoubtedly (part of) the reason Unity uses a sort of LoD on the mesh itself.

Unity doesn't support overhangs in terrain, because it uses heightmaps, a very old and very efficient system for reducing complexity and thereby cost, in various areas from rendering to physics to networking. It's typically cheaper to use a planar heightmap and run through a list of n objects that act as overhangs, than to make the entire terrain suitable for creating overhangs.

Geometry-based raycasts against large meshes using (concave) MeshColliders are COSTLY, because the collider has to check against the triangle count of the underlying mesh. No wonder Unity applies it's own optimisations in the process... as you have found. Concave geometry checks are an order of magnitude more costly compared with convex checks.

(2) Solutions

I would voxelise each chunk into a low resolution grid (3D array) by sampling the point at the centre of each grid cell to see whether that point falls inside or outside the fine polygon chunk mesh. If you raycast that grid using a cheap 3D-DDA raycast (not the same as Unity raycasting) and score a hit, then you can perform a more costly check for the associated subsection of the chunk mesh, using a standard triangles-based Unity raycast. Grid & DDA provide broadphase collision detection.

The voxelisation sampling step would involve you sampling either:

  • Each chunk of your custom mesh directly

OR

  • The world heightmap AND
  • The list of N objects sitting on the surface thereof (possibly creating overhangs).

It may be that others can give a better answer for Unity specifically, but I think you will find these are limitations inherent in any general purpose terrain system, with Unity being no exception.

One way or another, some sort of spatial acceleration structure is needed to solve these problems of cost without reducing the fidelity of your terrain. See octrees, quadtrees, KD-trees, and the like; however, having the data structure available and working (quickly) is one thing; inserting data into it according to your design needs is a whole other story that will need addressing.

Other than that I can only say, game design that is constrained often leads to better gameplay. You may be better off starting with smaller levels and working your way up to complex ones from there as you discover what is technically possible and feasible, in various areas.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you for your answer. I have managed to solve the problem. The solution might surprise you, see the answer below. \$\endgroup\$
    – AzulShiva
    Commented Aug 9, 2018 at 9:25
0
\$\begingroup\$

First of all I have no idea how all this stuff works and why. But the answer was a lot simpler than ArcaneEngineer would suggest. The problem seemed to be here:

enter image description here

The Model was scaled to 32 in Blender. After scaling it down to 1 and reimporting to Unity, and scaling it back up inside Unity the Mesh Collider was very accurate.

I experimented with that and the result is: The higher the scale inside Blender when you export the model the less accurate the Mesh Collider is. The lower the scale (such as 0.01) the more accurate the Mesh Collider is. It had absolutely nothing to do with the amount of Polygons. Unity is not compressing the mesh for the MeshCollider.

And no the MeshCollider is not expensive at all. I was running hundreds of fps with a 200k Mesh Collider on the Model. Disabling the MeshCollider gave an increase of 2-3 fps. However I am using the MeshCollider against 10-20 Sphere or Capsule colliders and of course for RayCasting.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Old question, but in Blender you can "apply the scale" of an object using ctrl+a then choosing "scale". This would change the scale value to 1 but keep it the size that it currently is. \$\endgroup\$
    – SoloCrowd
    Commented Sep 28, 2020 at 23:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .