# ScreenSpaceDecal

## Introduction

### Decal Effects in Cocos Game Development

Have you ever played the game `CS`? I can vividly recall playing with friends in an internet cafe, furiously pressing `B41` and `B51` to spray at each other.

In this classic `FPS` game, there’s a particularly interesting system, which is the spray paint (decal) system. It’s a feature that allows players to spray graffiti on walls, floors, and various surfaces.

Getting back on track, how do we implement such an interesting and fun feature in our game development?

Today, I’ll introduce how to implement decal effects in Cocos game development. Thank you for your continuous support, reading, and sharing.

## 1. What Are the Methods to Implement Decals?

### Decal Effects are commonly used in game development for graffiti, bullet holes, tattoos, etc.

However, unlike `2D` games, in `3D` game development, implementing `3D` decals requires considering the depth and perspective effects of objects.

This means that when implementing decals, we need to take into account factors such as vertex positions and normal directions.

Below are a few methods I have thought of for implementing decal effects in `3D` games:

1. Using Quads: We can make the image into a quad and place it at the specified coordinates in the game scene, adjusting the rotation accordingly. The downside is that it only supports flat surfaces like walls and floors.

2. Dynamic Mesh Creation: We can use rays and cuboids to cut and trim the model’s `Mesh` to obtain the required `Mesh` information, then map our decal texture onto it, and create it using `utils.MeshUtils.createMesh`.

3. Using Shaders: We can use depth maps to reconstruct world coordinates, achieving screen-space decal effects.

## 2. Screen-Space Decals

Screen-space decal effects are quite ingenious but require some time to understand.

The principle is to use a cuboid object to intersect with models in the scene, then map the decal texture onto the surfaces of the scene models.

We need to use the depth map in the fragment shader to calculate the position in world space corresponding to the screen space coordinates, and finally transform it back to model space for cuboid clipping and texture mapping.

Those familiar with rendering principles may know that our normal rendering process is roughly as follows:

Vertices in model space → through transformation matrix Mworld space → through transformation matrix Vview space → through transformation matrix Pclip space → through perspective divisionNDC → through screen mapping → fragments in screen space.

If we reverse the above process, we can transform screen space coordinates back to model space.

The core issue here is how to reconstruct world coordinates from the depth map.

You can search for keywords such as Yutu, Cocos, depth map, world coordinate reconstruction, Shader, decal, and Decal to get an understanding of the core principles involved, which will make it easier to comprehend the principle behind decal implementation.

## 3. Let’s Implement the Decal Effect

### 1. Resource Preparation

First, we need to get some decal textures and a simple scene from the artists, preferably with uneven surfaces to better showcase the decal effect.

• Environment: CocosCreator
• Version: 3.8.2

First, we copy `builtin-unlit.effect` to quickly create and customize our `Shader`.

Then, in the vertex shader, add a `v_screenPos` to pass the coordinates to the fragment shader for processing.

Next, in the fragment shader, receive `v_screenPos` and process it according to the following snippet:

Here, `depthTexture` is our depth map. Since we can’t directly obtain it in the Shader, we need to do some extra operations in the script to pass the depth map to the Shader. This process is somewhat cumbersome.

### 3. Obtaining the Depth Map

First, divide the scene and the cuboid used for decals into different layers, namely `SCENE` and `VIEWBOX`.

Change the visibility of the main camera to `SCENE` and `VIEWBOX`.

Add a `RenderTexture` to receive the depth map rendered by the camera.

Add a sub-camera under the main camera, set its visibility to only `SCENE`, and bind the `RenderTexture` to it. Keep other parameters the same as the main camera.

Finally, write a simple script to pass the depth map to the Shader.

### 4. Notes

Since there is no direct method to get the inverse matrix of `cc_matWorld` in the Shader, we need to calculate it ourselves.

In the process of learning about depth maps, you will also encounter linear and non-linear depth. It’s worth learning about these concepts.

### 5. Demonstration

Now we’ve successfully applied our decals to the uneven ground.

Since the effect might not be very intuitive, we add a dragging script and collider to enable simple dragging.

Now our decals can move around.

Various types of decals.