Glass shatter effect in Unity

Hello everyone, welcome back.

A week or so ago Valve had dropped another Counter strike 2 update with 2 maps and it had a cool new glass shattering effect.

Now I think the effect is really cool and decided to recreate it in Unity.

I am using Unity version 2023.1. but this will work on any other version just fine.

Okay so I have created 2 fbx models for glass panel, 1 is intact and the second for shattered version.

Once you import them in Unity, in the import settings under model tab, uncheck convert units and check bake axis conversion.



Theory

To break our glass we will just swap our intact version with the shattered one.

We will shatter it when our bullet collide with our glass panel, we will destroy our intact glass and bullet.

We will instantiate the shattered version with same position, rotation and scale of our intact version.

We will use our bullets position and cast a sphere, that way we will get rigidbodies of our shattered glass's shards and add an explosive force.

Glass prefabs

Create a prefab for our intact version, add a BoxCollider to it.




Create another prefab for our shattered version, it has glass shards as children, select them and add MeshCollider and RigidBody to each and all of them with settings shown in below screenshot.



Create a script, call it ShatteredGlass. and assign it to our shattered prefab.

using UnityEngine;

public class ShatteredGlass : AutoDestroy
{
[SerializeField] private float explosiveForce = 100f;
[SerializeField] private float explosiveRadius = 1f;

public void ApplyForce(Vector3 projectilePosition) {
Collider[] colliders = Physics.OverlapSphere(projectilePosition, explosiveRadius);
foreach (Collider collider in colliders) {
if(collider.TryGetComponent(out Rigidbody rigidbody)) {
rigidbody.AddExplosionForce(explosiveForce, projectilePosition, explosiveRadius);
}
}
}
}

In this script we are casting a sphere and applying explosive force on rigidbodies withing that sphere for an impact feel.

We have derived ShatteredGlass from AutoDestroy class which just as the name suggest auto destroys gameobject after specified time

using UnityEngine;

public class AutoDestroy : MonoBehaviour
{
[SerializeField] private float timeToLive = 1f;

protected virtual void Awake() {
Destroy(gameObject, timeToLive);
}
}

Also attach an AudioSource component on shattered prefab and apply the glass break script.

It would look something like this.





Create new script called Glass and attach it to our intact version prefab.

using UnityEngine;

public class Glass : MonoBehaviour
{
[SerializeField] private ShatteredGlass shatteredVersion;

public void Break(Vector3 projectilePosition) {
ShatteredGlass shatteredGlass = Instantiate(shatteredVersion, transform.position, transform.rotation);
shatteredGlass.transform.localScale = transform.localScale;
shatteredGlass.ApplyForce(projectilePosition);
Destroy(gameObject);
}
}

Here we will swapping the intact version with the shattered version.




Projectile

To call the Break() we will create a prefab for our bullet, which in our case will be a scaled down version of default 3d sphere.

Create a new script called Projectile and attach it to our prefab.

using UnityEngine;

public class Projectile : AutoDestroy
{
private void OnCollisionEnter(Collision collision) {
if(collision.gameObject.TryGetComponent(out Glass glass)) {
glass.Break(transform.position);
}
Destroy(gameObject);
}
}

Here we are checking in OnCollisionEnter() if object we have collided with has a Glass component, and if it does call its Break(), we are also passing the position of our bullet as well.

Finally we are destroying the projectile, also notice that our Projectile derives from AutoDestroy.



Shooting

For shooting mechanism we will use 2 scripts, CameraRotate to look around.

using ShaderTutorials;
using UnityEngine;

public class CameraRotate : MonoBehaviour {
private Vector3 rotation;
private InputControls inputControls;

[SerializeField] private float rotationSpeed = 10f;

private void Awake() {
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;

inputControls = new InputControls();
rotation = transform.eulerAngles;
}

private void OnEnable() {
inputControls.Mouse.Enable();
}

private void OnDisable() {
inputControls.Mouse.Disable();
}

private void Update() {
Vector2 delta = inputControls.Mouse.Look.ReadValue<Vector2>();
rotation = rotation + new Vector3(-delta.y, delta.x, 0) * rotationSpeed * Time.deltaTime;
transform.rotation = Quaternion.Euler(rotation);
}
}

It works on new input system and we are just reading the mouse delta and adding it to our camera's rotation.

We will use BazookaMan script for shooting.

using UnityEngine;

public class BazookaMan : MonoBehaviour
{
[SerializeField] private float projectileForce = 10;
[SerializeField] private Transform firePoint;
[SerializeField] private Rigidbody projectile;
[SerializeField] private AudioSource audioSource;

private void Update() {
if(Input.GetMouseButtonDown(0)) {
Fire();
}
}

private void Fire() {
Rigidbody newProjectile = Instantiate(projectile, firePoint.position, Quaternion.identity);
newProjectile.AddForce(firePoint.forward * projectileForce, ForceMode.VelocityChange);
audioSource.Play();
}
}

Here, we are listening for left clicks in Update(), in Fire() we are instantiating our projectile prefab, adding some force and playing the audio clip.

Attach both our script and AudioSource component on our camera.




That's it!

Trouble following along? Check out this Video!



Thank you so much for reading!

Comments