An open API service indexing awesome lists of open source software.

https://github.com/aniketrajnish/unity-webgpu-pbr-maps-generator

Helps generate PBR maps from a base/diffuse map depending on the workflow chosen using WebGPU.
https://github.com/aniketrajnish/unity-webgpu-pbr-maps-generator

pbr pbr-materials pbr-shading unity unity-webgpu unity3d webgpu

Last synced: about 1 month ago
JSON representation

Helps generate PBR maps from a base/diffuse map depending on the workflow chosen using WebGPU.

Awesome Lists containing this project

README

          

# Unity-WebGPU-PBR-Maps-Generator
Helps generate PBR maps from a base/diffuse map depending on the workflow chosen. This project demonstrates the power of `WebGPU` by implementing a Physically Based Rendering (PBR) map generator that runs efficiently in web browsers. It showcases the use of compute shaders for GPU-accelerated texture processing, providing a significant performance boost over traditional CPU-based methods. The output of course is not very fancy, as we don't have access to the real height information of the texture, and we're just making a guess based on the color information, which could be a hit or miss. But it's a good starting point to prototype some PBR textures quickly!

You can try out the project here- [https://makra.wtf/Unity-WebGPU-PBR-Maps-Generator/](https://makra.wtf/Unity-WebGPU-PBR-Maps-Generator/).
The page might take a while to load for the first time but once it's cached, it should load quickly on subsequent visits.

https://github.com/user-attachments/assets/ead85097-f6dc-42b5-89a2-8e2ab5d76f4b

## Features
- Generate various PBR maps from a single base texture:
- Height Map
- Normal Map
- Ambient Occlusion (AO) Map
- Roughness Map
- Metallic Map
- Specular Map
- Glossiness Map
- Choose between Metallic-Roughness and Specular-Glossiness workflows.
- GPU acceleration using compute shaders using `Unity`'s new `WebGPU` backend.
- CPU fallback for devices without GPU that supports 64 threads per block.
- Real-time preview of generated maps along with the option to download them.












Base
Height
Normal
AO
Metallic
Roughness
Specular
Glossiness

PBR maps generated from a single base texture using the tool

## WebGPU advantage

Here's a comparison of CPU vs GPU methods for generating a normal map:

### CPU Method

```csharp
private static Texture2D CPUConvertToNormalMap(Texture2D heightMap)
{
Texture2D normalMap = new Texture2D(heightMap.width, heightMap.height, TextureFormat.RGBA32, false);
for (int y = 0; y < heightMap.height; y++)
{
for (int x = 0; x < heightMap.width; x++)
{
float left = GetPixelHeight(heightMap, x - 1, y);
float right = GetPixelHeight(heightMap, x + 1, y);
float top = GetPixelHeight(heightMap, x, y - 1);
float bottom = GetPixelHeight(heightMap, x, y + 1);

Vector3 normal = new Vector3(left - right, bottom - top, 1).normalized;
normal = normal * 0.5f + Vector3.one * 0.5f;

normalMap.SetPixel(x, y, new Color(normal.x, normal.y, normal.z, 1));
}
}
normalMap.Apply();
return normalMap;
}
```

### GPU Method

```glsl
#pragma kernel CSMain

Texture2D HeightMap;
RWTexture2D NormalMap;
uint2 TextureSize;

[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
if (id.x >= TextureSize.x || id.y >= TextureSize.y)
return;

float left = HeightMap[uint2(max(id.x - 1, 0), id.y)];
float right = HeightMap[uint2(min(id.x + 1, TextureSize.x - 1), id.y)];
float top = HeightMap[uint2(id.x, max(id.y - 1, 0))];
float bottom = HeightMap[uint2(id.x, min(id.y + 1, TextureSize.y - 1))];

float3 normal = normalize(float3(left - right, bottom - top, 1));
normal = normal * 0.5 + 0.5;

NormalMap[id.xy] = float4(normal, 1);
}
```

Using compute shaders we create 8x8 threads per block, which is the maximum supported by the `WebGPU` backend. This allows us to process 64 pixels in parallel, providing a significant performance boost over the CPU method.

These are the results of the performance comparison using a system with an `Intel Core i9-13900HX` CPU and an NVIDIA GeForce `RTX 4070` GPU and `32 GB` of RAM:

https://github.com/user-attachments/assets/149acec5-1174-45ce-abce-d7a763bcffad





Map Type
Resolution
CPU Time (ms)
GPU Time (ms)
Speedup Factor




Height
512x512
350
20
17.5x



1024x1024
1500
50
30x



2048x2048
6200
150
41.3x


Normal
512x512
500
30
16.7x



1024x1024
2000
80
25x



2048x2048
8000
250
32x


AO
512x512
450
20
22.5x



1024x1024
1800
60
30x



2048x2048
7200
180
40x


Roughness
512x512
550
30
18.3x



1024x1024
2200
70
31.4x



2048x2048
8800
220
40x


Metallic
512x512
400
20
20x



1024x1024
1600
50
32x



2048x2048
6400
160
40x


Specular
512x512
420
20
21x



1024x1024
1700
60
28.3x



2048x2048
6800
180
37.8x


Glossiness
512x512
600
40
15x



1024x1024
2400
90
26.7x



2048x2048
9600
280
34.3x




plt

As we can see from the table and graph, the GPU method consistently outperforms the CPU method, with the performance gap widening as the texture resolution increases. This demonstrates the scalability and efficiency of compute shaders for texture processing tasks.

## WebGPU Limitations & Solutions
One key limitation of `WebGPU` is the lack of support for synchronous GPU readback. To address this, we use `AsyncGPUReadback` instead of the traditional `ReadPixels` method:

```csharp
private void ReadbackTexture(Texture texture, Action callback)
{
AsyncGPUReadback.Request(texture, 0, readback =>
{
if (readback.hasError)
{
Debug.LogError("GPU readback error detected.");
return;
}
Texture2D texture2D = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false);
texture2D.LoadRawTextureData(readback.GetData());
texture2D.Apply();
callback(texture2D);
});
}
```
This asynchronous approach ensures compatibility with WebGPU while maintaining efficient GPU-to-CPU data transfer. You can see an example implementation [here](https://github.com/aniketrajnish/Unity-WebGPU-PBR-Maps-Generator/blob/cc98607c42f736d329499dfdf8d609924396dd7d/src/PBR%20Maps%20Generator/Assets/Scripts/Conversion/Maps/Normal.cs#L49).

## Installation
- Clone the repository or download the `.unitypackage` from [here](https://github.com/aniketrajnish/PBR-Maps-Generator/releases/tag/v001).
- Open/Import the project in `Unity 2023.3` or later.
- If you're using the `.unitypackage`, make sure to create a project using the `Built-In Render Pipeline` and import `TextMeshPro`.
- Make sure to enable the `WebGPU` backend to take advantage of GPU acceleration. Instructions [here](https://discussions.unity.com/t/early-access-to-the-new-webgpu-backend-in-unity-2023-3/933493).

## Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. Currently working on-
- Better algorithms for generating the maps that give better results.
- Incorporating deep learning models to estimate the height information from the color information instead of just doing a greyscale conversion.

## License
MIT