Hey,
I was looking into your code for clouds.
You got way too much files to generate these clouds. gave me a headache. While everything works as intended, very hard to port into my project.
i was reading the code for two days, cause its either this or harakiri seppuku :-) . tried various things with ChatGPT, Qwen, Deepseek. Still too complicated, they basically butchered your code.
30 mins ago, decided to give grok a try,
prompt :
i need a full 3d worley texture generator takes in some params, outputs a Texture3D for unity3d csharp. you can use compute shader for that. and we will have a way to visualize slices in either of the 3 directions, the slice texture will be sent to another material, its just a shader graph shader that takes in a _ColorMap texture2D in order to display. so this noise class has a set of variables that we can set in inspector, generate a 3d worley texture, then allows us to use a dir enum selector and a slider to visualize slices. it has only one function to generate the noise texture and thats it.
gave additional instructions for updating with a bool, and the slider to switch slices.
After pasting errors, and grok fixing them with zero efforts, 2 minutes process :
monobehavior code
`using UnityEngine;
using UnityEditor; // For DestroyImmediate in edit mode
public class WorleyNoise3DGenerator : MonoBehaviour
{
public enum SliceDirection { X, Y, Z }
[Header("Noise Parameters")]
[SerializeField, Range(128, 1024)] private int resolution = 64;
[SerializeField, Range(16, 512)] private int numPoints = 32;
[SerializeField, Range(0.1f, 10f)] private float noiseScale = 1f;
[SerializeField] private bool regenerate = false;
[Header("Visualization")]
[SerializeField] private SliceDirection sliceDirection = SliceDirection.Z;
[SerializeField, Range(0f, 1f)] private float slicePosition = 0f;
[SerializeField] private Material sliceMaterial;
[Header("Compute Shader")]
[SerializeField] private ComputeShader worleyShader;
private RenderTexture noiseTexture; // Changed from Texture3D to RenderTexture
private RenderTexture sliceTexture;
private ComputeBuffer pointsBuffer;
private int kernelHandle;
private int sliceKernelHandle;
public RenderTexture NoiseTexture => noiseTexture; // Updated type to RenderTexture
private void OnValidate()
{
// Ensure resolution is valid
resolution = Mathf.Max(16, resolution);
if (regenerate)
{
GenerateNoiseTexture();
regenerate = false; // Reset regenerate flag after generation
}
else
{
UpdateSlice(); // Only update the slice if not regenerating
}
}
private void OnDestroy()
{
// Clean up resources safely
if (noiseTexture != null)
{
if (Application.isPlaying)
Destroy(noiseTexture);
else
DestroyImmediate(noiseTexture);
}
if (sliceTexture != null)
{
sliceTexture.Release();
}
if (pointsBuffer != null)
{
pointsBuffer.Release();
}
}
[ContextMenu("Generate Noise Texture")]
public void GenerateNoiseTexture()
{
// Initialize compute shader
kernelHandle = worleyShader.FindKernel("CSMain");
sliceKernelHandle = worleyShader.FindKernel("Slice");
// Create or recreate RenderTexture for 3D noise
if (noiseTexture != null)
{
if (Application.isPlaying)
Destroy(noiseTexture);
else
DestroyImmediate(noiseTexture);
}
noiseTexture = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.RFloat)
{
dimension = UnityEngine.Rendering.TextureDimension.Tex3D, // Set as 3D texture
volumeDepth = resolution,
enableRandomWrite = true, // Enable UAV for compute shader
wrapMode = TextureWrapMode.Repeat, // Ensure seamless tiling
filterMode = FilterMode.Bilinear
};
noiseTexture.Create();
// Create or recreate slice texture
if (sliceTexture != null)
{
sliceTexture.Release();
}
sliceTexture = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.RFloat)
{
enableRandomWrite = true,
wrapMode = TextureWrapMode.Repeat,
filterMode = FilterMode.Bilinear
};
sliceTexture.Create();
// Generate random points for Worley noise
Vector3[] points = new Vector3[numPoints];
for (int i = 0; i < numPoints; i++)
{
points[i] = new Vector3(Random.value, Random.value, Random.value);
}
// Set up compute buffer
if (pointsBuffer != null)
{
pointsBuffer.Release();
}
pointsBuffer = new ComputeBuffer(numPoints, sizeof(float) * 3);
pointsBuffer.SetData(points);
// Set compute shader parameters for noise generation
worleyShader.SetTexture(kernelHandle, "Result", noiseTexture);
worleyShader.SetInt("resolution", resolution);
worleyShader.SetInt("numPoints", numPoints);
worleyShader.SetFloat("scale", noiseScale);
worleyShader.SetBuffer(kernelHandle, "points", pointsBuffer);
// Dispatch compute shader for noise generation
int threadGroups = Mathf.CeilToInt(resolution / 8f);
worleyShader.Dispatch(kernelHandle, threadGroups, threadGroups, threadGroups);
// Update slice visualization
UpdateSlice();
}
private void UpdateSlice()
{
if (noiseTexture == null || sliceMaterial == null || sliceTexture == null) return;
// Set compute shader parameters for slice extraction
worleyShader.SetTexture(sliceKernelHandle, "SourceTexture", noiseTexture);
worleyShader.SetTexture(sliceKernelHandle, "SliceTexture", sliceTexture);
worleyShader.SetInt("resolution", resolution);
worleyShader.SetInt("sliceIndex", Mathf.FloorToInt(slicePosition * (resolution - 1)));
worleyShader.SetInt("sliceDirection", (int)sliceDirection);
// Dispatch compute shader for slice extraction
int threadGroups = Mathf.CeilToInt(resolution / 8f);
worleyShader.Dispatch(sliceKernelHandle, threadGroups, threadGroups, 1);
// Assign slice texture to material
sliceMaterial.SetTexture("_ColorMap", sliceTexture);
}
}
`
compute shader code :
`
#pragma kernel CSMain
#pragma kernel Slice
// --- 3D Noise Generation ---
RWTexture3D Result;
int resolution;
int numPoints;
float scale;
StructuredBuffer points;
[numthreads(8,8,8)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
if (id.x >= resolution || id.y >= resolution || id.z >= resolution) return;
float3 uv = float3(id) / (float)resolution;
float minDist = 1.0f;
// Iterate over all points
for (int i = 0; i < numPoints; i++)
{
float3 worleyPoint = points[i];
// Check the point in the 3x3x3 grid of neighboring cells
for (int x = -1; x <= 1; x++)
for (int y = -1; y <= 1; y++)
for (int z = -1; z <= 1; z++)
{
float3 offset = float3(x, y, z);
float3 wrappedPoint = worleyPoint + offset;
float3 diff = uv - wrappedPoint;
diff = frac(diff + 0.5) - 0.5; // Center the difference for wrapping
float dist = length(diff) * scale;
minDist = min(minDist, dist);
}
}
// Output normalized distance
Result[id] = saturate(minDist);
}
// --- Slice Extraction ---
Texture3D SourceTexture;
RWTexture2D SliceTexture;
int sliceIndex;
int sliceDirection; // 0 = X, 1 = Y, 2 = Z
[numthreads(8,8,1)]
void Slice(uint3 id : SV_DispatchThreadID)
{
if (id.x >= resolution || id.y >= resolution) return;
float value;
if (sliceDirection == 0) // X-axis (YZ plane)
{
value = SourceTexture[uint3(sliceIndex, id.x, id.y)];
}
else if (sliceDirection == 1) // Y-axis (XZ plane)
{
value = SourceTexture[uint3(id.x, sliceIndex, id.y)];
}
else // Z-axis (XY plane)
{
value = SourceTexture[uint3(id.x, id.y, sliceIndex)];
}
SliceTexture[id.xy] = value;
}
`
This just works. lol.
I was integrating your atmosphere in my planet system, adapted to urp, worked, then tried messing with raymarching actual clouds in atmo, after much trial failure loops, figured out that in fact if you take the time to understand it, not skipping, its just dead simple, and your video helped a lot, its unbelievable that your stuff is free. Not sure if you understand the value of your own code bro, this is paid level modules, that kind of features only one game has them Star citizen 800 million usd budget.
Thanks to your channel and code, i could pull out of inexistence, isosphere tri lod, quadsphere lod, planet atmosphere, terrain erosion, and this 2 mins worley generator.
With ai this makes life so so much easier. when i see people vibe code their bouncing balls in a circle, makes me cry. lol.
Only qwen can parse a github and actually list all the code, but their model is dumb, gpt-5 is a magistral failure. Grok is beyond sanity, the savior of the day that nobody uses lol, besides shitposting on X.
Thanks a lot for your work, you should keep posting videos, whatever they do in the game industry you got the skills and dedication to replicate. There are so much papers that never see the light of day, because the aaa studios wont even try integrating in a game.
Have a good day.
Hey,
I was looking into your code for clouds.
You got way too much files to generate these clouds. gave me a headache. While everything works as intended, very hard to port into my project.
i was reading the code for two days, cause its either this or harakiri seppuku :-) . tried various things with ChatGPT, Qwen, Deepseek. Still too complicated, they basically butchered your code.
30 mins ago, decided to give grok a try,
prompt :
i need a full 3d worley texture generator takes in some params, outputs a Texture3D for unity3d csharp. you can use compute shader for that. and we will have a way to visualize slices in either of the 3 directions, the slice texture will be sent to another material, its just a shader graph shader that takes in a _ColorMap texture2D in order to display. so this noise class has a set of variables that we can set in inspector, generate a 3d worley texture, then allows us to use a dir enum selector and a slider to visualize slices. it has only one function to generate the noise texture and thats it.gave additional instructions for updating with a bool, and the slider to switch slices.
After pasting errors, and grok fixing them with zero efforts, 2 minutes process :
monobehavior code
`using UnityEngine;
using UnityEditor; // For DestroyImmediate in edit mode
public class WorleyNoise3DGenerator : MonoBehaviour
{
public enum SliceDirection { X, Y, Z }
}
`
compute shader code :
`
#pragma kernel CSMain
#pragma kernel Slice
// --- 3D Noise Generation ---
RWTexture3D Result;
int resolution;
int numPoints;
float scale;
StructuredBuffer points;
[numthreads(8,8,8)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
if (id.x >= resolution || id.y >= resolution || id.z >= resolution) return;
}
// --- Slice Extraction ---
Texture3D SourceTexture;
RWTexture2D SliceTexture;
int sliceIndex;
int sliceDirection; // 0 = X, 1 = Y, 2 = Z
[numthreads(8,8,1)]
void Slice(uint3 id : SV_DispatchThreadID)
{
if (id.x >= resolution || id.y >= resolution) return;
}
`
This just works. lol.
I was integrating your atmosphere in my planet system, adapted to urp, worked, then tried messing with raymarching actual clouds in atmo, after much trial failure loops, figured out that in fact if you take the time to understand it, not skipping, its just dead simple, and your video helped a lot, its unbelievable that your stuff is free. Not sure if you understand the value of your own code bro, this is paid level modules, that kind of features only one game has them Star citizen 800 million usd budget.
Thanks to your channel and code, i could pull out of inexistence, isosphere tri lod, quadsphere lod, planet atmosphere, terrain erosion, and this 2 mins worley generator.
With ai this makes life so so much easier. when i see people vibe code their bouncing balls in a circle, makes me cry. lol.
Only qwen can parse a github and actually list all the code, but their model is dumb, gpt-5 is a magistral failure. Grok is beyond sanity, the savior of the day that nobody uses lol, besides shitposting on X.
Thanks a lot for your work, you should keep posting videos, whatever they do in the game industry you got the skills and dedication to replicate. There are so much papers that never see the light of day, because the aaa studios wont even try integrating in a game.
Have a good day.