#3D render textures in a compute shader?

1 messages · Page 1 of 1 (latest)

unreal zodiac
#

I'm creating a 3D render texture, and I'm trying to generate some noise on it in a compute shader so I can use the rendertexture in a shader I'm working on. But I can't figure out how to get it going! This is currently what I'm doing to create the 3d texture:

RenderTexture tex = new RenderTexture(volumeSize, volumeSize, 0, RenderTextureFormat.RHalf, RenderTextureReadWrite.Linear);
tex.enableRandomWrite = true;
tex.dimension = UnityEngine.Rendering.TextureDimension.Tex3D;
tex.volumeDepth = volumeSize;
tex.Create();

shader.SetTexture(shader.FindKernel("CSMain"), "Texture", tex);
shader.SetInt("volumeSize", volumeSize);
shader.Dispatch(shader.FindKernel("CSMain"), volumeSize,volumeSize,volumeSize);
#

im not sure how to get this thing to properly render though

#

this is the actual shader itself

// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture3D<float4> Texture;

int volumeSize;
[numthreads(10,10,10)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    float x = id.x / volumeSize;
    // TODO: insert actual code here!
    Texture[id.xyz] = float4(x, 0, 0, 0);
}
#

but for some reason, it just shows up as white in the inspector

devout zephyr
#

your numthreads seem strange lol

#

but anyway, you're looking at the texture during play mode right

#

quite confused actually

#

your texture cpu side is an rhalf but on the gpu side its a full rgba32

#

@unreal zodiac cursed

unreal zodiac
unreal zodiac
unreal zodiac
#

sorry for the ping bomb lol

devout zephyr
unreal zodiac
#

that doesn make sense...

#

oh wait thats bc this is 1x1x1 hang on

devout zephyr
devout zephyr
unreal zodiac
#

right so i gotta learn a bit more

#

im mainly using this to generate noise, so all i really need is just one float

#

but im not sure if there's a texture format that supports just a grayscale value

devout zephyr
#

so on the cpu side you got it right

unreal zodiac
#

oh so i just gotta change it to that

devout zephyr
#

yeah exactly

unreal zodiac
#

ok so that's the format done

devout zephyr
#

see how they match now

unreal zodiac
#

yay!!!

unreal zodiac
#

so that might be the trouble

#

im not necessarily sure how to figure out what thread size i need

devout zephyr
#

volumeSize is 25 right?

unreal zodiac
devout zephyr
#

i suggest understanding that diagram

#

but as a tdlr

#

a thread is the basic unit in the gpu
threads are organized into groups
the numthreads(x, y, z) determines the dimensions of these groups
you dispatch groups of threads. dispatch(x, y, z) determines how many groups of threads you dispatch

#

so in your case, you thread groups are 10x10x10

#

and you dispatch 25x25x25 of them

unreal zodiac
devout zephyr
#

which totals to just a ridiculous number of threads

unreal zodiac
#

yeah im starting to see how i fucked up lol

#

what if i did a thread group of 1x1x1? and then did 25x25x25?

devout zephyr
#

okay so there's lots of ways of organizing this right

#

you could also do a thread group size of 25x25x25 and dispatch only one group

#

now, threads that belong to the same group actually get all kinds of advantages, like memory and performance stuffs

#

but, there's a max number of threads that can belong in a group

unreal zodiac
#

i dont think im able to do 25x25x25

#

yeah

devout zephyr
#

so that's your job to figure out how to do this efficiently

#

one option could be 7x7x7 and dispatch 4x4x4, but that would leave 6327 or 28.8% of your threads dispatched unused

unreal zodiac
#

i dont even know the math of how to figure that out

devout zephyr
#

basically you need 25x25x25

unreal zodiac
#

maybe 8x8x8 and 3x3x3? does that even work?

devout zephyr
#

but there's a maximum to each thread group which i'll leave you to find out

devout zephyr
unreal zodiac
#

the max is 1024

unreal zodiac
#

i mean i could just drop it one

devout zephyr
#

haha that's one option

#

powers of two are always nice

unreal zodiac
#

hmm alright

#

i do sorta wanna save the figuring out for a bit later, ive dropped the res to 24 and im now using 8x8x8 and 3x3x3

#

yet for some reason, it still doesnt really want to render

devout zephyr
#

show your code

unreal zodiac
#
tex = new RenderTexture(volumeSize, volumeSize, 0, RenderTextureFormat.RHalf, RenderTextureReadWrite.Linear);
tex.dimension = UnityEngine.Rendering.TextureDimension.Tex3D;
tex.volumeDepth = volumeSize;
tex.enableRandomWrite = true;
tex.Create();


shader.SetTexture(shader.FindKernel("CSMain"), "tex", tex);
shader.SetInt("volumeSize", volumeSize);
shader.Dispatch(shader.FindKernel("CSMain"), 3, 3, 3);
#

compute code:

// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture3D<half> tex;

int volumeSize;
[numthreads(8,8,8)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    // TODO: insert actual code here!
    tex[id.xyz] = id.x / 24;
}
devout zephyr
#

zero the texture in the shader

unreal zodiac
#

still white

#

by zero, you mean output zero?

#

bc that's what i just did

devout zephyr
#

maybe switch to just the R channel?

#

im not sure how to visualize a 3d texture

#

that's weird to me

unreal zodiac
#

thats pretty much what i understand of it

unreal zodiac
#

its full white in all channels

devout zephyr
#

try it with a 2d texture first

unreal zodiac
#

also

#

updated unity, it works

#

and it has a nifty 3d view

#

and you can view all the slices and everything

devout zephyr
#

oh what

#

how did you update

unreal zodiac
devout zephyr
#

you're just going to see one side of the cube as a little black but everything else white

unreal zodiac
#

i was making it on 2019 because when i used the new versions the slowdowns were incredible

devout zephyr
#

should be?

unreal zodiac
#

oh no i changed the size of the volume to 24 so that extra one isnt there

devout zephyr
#

oh hmmm true

unreal zodiac
#

thanks for helping out though you're a lifesaver

devout zephyr
#

i did a lot of work to figure this stuff out so i thought id try to help make it easier for other people

#

imagine just staring at a black texture not even having a debugger or anything

#

but compute shaders are literally my favorite

unreal zodiac
devout zephyr
#

i probably should download it

#

i just use the texture itself to debug

#

colors mean different things

unreal zodiac
#

yeah maybe

#

one thing i wanted to ask, im using keijiro's noise library to generate some perlin noise

#

and i believe i import it using this

#include "Packages/jp.keijiro.noiseshader/Shader/ClassicNoise3D.hlsl"
#

did that, tried referencing a method but its not doing anything and i dont know if its because compute shaders can't do #import or if it just isn't working

#

@devout zephyrhave you had any experience in it?

devout zephyr
#

just rip the code right off the shader

#

or move the shader into the same folder

#

likely your path is wrong

#

probably need a bunch of ../../../

unreal zodiac
unreal zodiac
#

also just copied it all into the same folder and it still aint working, ill have to look for something else

devout zephyr
unreal zodiac
#

hm right

unreal zodiac
#

definitely the noise shader's issue, as doing a sine wave based on the position works normally

devout zephyr
#

copy the code directly

unreal zodiac
#

nothing

#

no errors though

devout zephyr
#

write your own code lol

unreal zodiac
#

one thing i wanna ask though this is really weird

#

more or less a whole seperate issue but still related to it

devout zephyr
#

life tip: if you need to preface a message with that you better think really hard about saying it

unreal zodiac
#

no no no its not like

#

its not weird like that its like

#

ok right so i copied the thread settings to another compute shader im doing

#

and made another 3d texture, just like this, same thing

tex = new RenderTexture(volumeSize, volumeSize, 0, RenderTextureFormat.RHalf, RenderTextureReadWrite.Linear);
tex.dimension = UnityEngine.Rendering.TextureDimension.Tex3D;
tex.volumeDepth = volumeSize;
tex.enableRandomWrite = true;
tex.Create();
#

used settexture, and in a compute shader im doing this

#
tex[id.xyz] = sin(id.y);
#

which only... sorta works

#

im not sure what's wrong with this at all

#

like the code is only running for a certain part of it?

#

but that doesnt make sense, it's the same size and thread settings as before

#

ok turns out i actually did mess up the thread settings please ignore me

devout zephyr
#

is it working

unreal zodiac
#

give me a second

#

yeah, its working, but the previous system i used was only created with 1 thread group on the X in mind, but now that there's 3 thread groups on each axis it's sorta broken

#

like im passing a 3d array into the compute shader using a compute buffer, but i dont think that preserves the dimensions

#

so in the shader, i need to reference it with a 1d index

devout zephyr
#

wait how

#

i don't think you can pass a 2d array?

unreal zodiac
#

that's the thing, the array is 3d in unity but 1d in the comp shader

devout zephyr
#

show code

#

how are you passing in a 3d array when it takes a 1d param?

#

also just use a 3d array on the compute shader side then

unreal zodiac
#

public VolumeCell[,,] cells;

ComputeBuffer cellsBuffer = new ComputeBuffer(cells.Length, (sizeof(int) * 3) + (sizeof(float)));
        cellsBuffer.SetData(cells);
unreal zodiac
devout zephyr
#

alright but you have no idea how that data is laid out

#

i'd just perform your own flattening operation for sanity

unreal zodiac
#

i mean you said there was a 3d array equivalent for compute shaders so i'd rather use that

devout zephyr
#

no you don't know how the data is laid out

#

remember, memory is linear. and that is how it is transferred between cpu and gpu, as a linear chuck

#

there are many ways to flatten a 3d array to a 1d array, and there are many ways to take that 1d array and interpret it as a 3d array

#

you cannot be sure that the cpu and gpu are using the same methods

#

unless of course, you code both methods

unreal zodiac
#

you've got a true

#

i'll write that out real quick

unreal zodiac
#

im trying to write this out but im sorta getting stuck turning the 1d back to the 3d

devout zephyr
#

don't do it that way

#

it is an array of 2d arrays

#

and the 2d arrays are just arrays of 1d arrays

#

heres some inspiration for your shader journey

unreal zodiac
unreal zodiac
#

ive made it so it iterates on the X, then the Y, then the Z

#

which is coolio, but now i gotta do this in the shader which im sorta stuck on

#

@devout zephyrwould something like this work for converting the 3d array index of the compute shader into a 1d one for the array?

int get1DIndex(uint3 pos)
{
    int index = 0;
    for(int z = 0; z < pos.z; z++)
    {
        index += volumeSize;
    }

    for(int y = 0; y < pos.y; y++)
    {
        index += volumeSize;
    }

    index += pos.x;
}
devout zephyr
#

no

unreal zodiac
#

ouch

devout zephyr
#

well hmm

#

assuming volume size is 24, decode 48

unreal zodiac
#

the size on each axis is 24 so it's adding...

#

wait wait wait, i think i need to do volumeSize squared on the Z loop

devout zephyr
#

yeah there you go

unreal zodiac
#

Yay!