Temaran/UnrealEngineShaderPluginDemo

FTexture2DRHIRef texture and vertex shader

Closed this issue · 10 comments

Hello, I need a little help about two points.

I'm testing the plugin and I want to create a FTexture2DRHIRef texture to give as input directly to the pixel shader, How Can I do it? I did:

FRHIResourceCreateInfo CreateInfo;
InputTexture = RHICreateTexture2D(960, 540, PF_R32_UINT, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);

but then how can I fill the data? for example how to obtain a black texture?

Second question is, in the PixelShaderExample I found out the MainVertexShader function.
How can I use it? because if for example I set
OutPosition = InPosition*3;

nothing change! instead I was expecting to see cubes in the example enlarge three time themselves. So how I can use properly the vertex shader?

I’m sorry for the newby question,
I’m very grateful for your help,

Thank you for the (unexpected) quick reply!
OK, regarding the FRHI command I found this:
https://docs.unrealengine.com/latest/INT/API/Runtime/RHI/FRHICommandList/index.html

I will look to the functions listed here.
Can you suggest a more verbose documentation or simple related tutorial?

Regarding DirectX/OpenGL. I know a little of OpenGL. In fact, I wrote some (working) shaders in OpenGL but now I have the task to implement the same here in UE4 (and so googling and searching I found your plugin!). UE4 is so big that I'm confused!

So, I will try the functions as soon as possible and I will let you know (and I will write a reply here hoping to be help for someone in future). Unfortunately I can't access the working station now so I think I will try in the next days.

For what regards the second question, the render target one, I will read something about that. Just to be sure we have the same vocabulary, with "render target" are we speaking about "buffers" like in OpenGL?

Again thank you, I will write results and/or new doubts when I will read something more about the topic or tried solutions. Sorry for my bad English I'm not a native speaker.

Hello again, Sorry if I bore you, If I do this please tell me and I will write these question on the ue4 general forum.

So I tried to use the ClearColorTexture() function but in order to use it I need a RHICmdList, Which I create in the line above.

	//MY STUFF
	FRHIResourceCreateInfo CreateInfo;
	FLinearColor my_color = FLinearColor(1, 1, 0, 1);
	InputTexture = RHICreateTexture2D(960, 540, PF_R32_UINT, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
	/* Get global RHI command list */
	FRHICommandListImmediate& myRHICmdList = GRHICommandList.GetImmediateCommandList();
	myRHICmdList.ClearColorTexture(InputTexture, my_color, FIntRect());
	//end my stuff

If I try to do something like this (this code is placed between the execution of the compute shader and the pixel shader).. ue4 crashes.

If I try to access single pixel like in this example_https://answers.unrealengine.com/questions/25594/accessing-pixel-values-of-texture2d.html

	//my stuff due
	FColor my_FColor = FColor(1, 0, 0, 1);
	FTexture2DMipMap* MyMipMap = &InputTexture->GetTexture2D()->PlatformData->Mips[0];
	FByteBulkData* RawImageData = &MyMipMap->BulkData;
	FColor* FormatedImageData = static_cast<FColor*>(RawImageData->Lock(LOCK_READ_ONLY));
	
	uint32 TextureWidth = MyMipMap->SizeX, TextureHeight = MyMipMap->SizeY;
	FColor PixelColor;
	for (int i = 0; i < TextureWidth*TextureHeight; i++) {
		FormatedImageData[i] = my_FColor;
	}
	
	/*
	uint8 PixelX = 5, PixelY = 10;
	if (PixelX >= 0 && PixelX < TextureWidth && PixelY >= 0 && PixelY < TextureHeight)
	{
		PixelColor = FormatedImageData[PixelY * TextureWidth + PixelX];
	}*/
	RawImageData->Unlock();
	InputTexture->GetTexture2D()->PlatformData->Mips[0].BulkData.Unlock();
	//end my stuff due

The compiler tells me that FRHITexture2D does not contain any member callded “Platform Data”.

Now I will study the target buffer to solve the vertex shader issue. thanks you.

maybe should I execute that code in Render thread?
I see also from your example that I should use
ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER macro.
but I dont understand the params I should pass to this macro for apply these operation.

Ok, maybe I'm near,

I use this code

	//MY STUFF
		ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(void, FTexture2DRHIRef, InputTexture, InputTexture ,
			{	
				FRHIResourceCreateInfo CreateInfo;
				InputTexture = RHICreateTexture2D(960, 540, PF_R32_UINT, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
				// Write the contents of the texture.
				uint32 DestStride;
				uint32* DestBuffer = (uint32*)RHILockTexture2D(InputTexture, 0, RLM_WriteOnly, DestStride, false);
				int BufferSize = 960 * 540 * 4;
				uint8 * SourceBuffer = new uint8[BufferSize];
				for (int i = 0; i < BufferSize; i++) {
					SourceBuffer[i] = 20;
				}
				FMemory::Memcpy(DestBuffer, SourceBuffer, BufferSize);
				RHIUnlockTexture2D(InputTexture, 0, false);
			}
		);

I'm not sure about the macro parameter.
after this code I exectute

       PixelShading->ExecutePixelShader(RenderTarget, InputTexture,
                                         FColor(EndColorBuildup * 255, 0, 0, 255), ComputeShaderBlend);

My Pixel shader is


void MainPixelShader(
	in float2 uv : TEXCOORD0,
	out float4 OutColor : SV_Target0
	)
{
	//First we need to unpack the uint material and retrieve the underlying R8G8B8A8_UINT values.
	float sizeX, sizeY;
	TextureParameter.GetDimensions(sizeX, sizeY);
	uint packedValue = TextureParameter.Load(int3(sizeX * uv.x, sizeY * uv.y, 0));
	uint r = (packedValue & 0x000000FF);
	uint g = (packedValue & 0x0000FF00) >> 8;
	uint b = (packedValue & 0x00FF0000) >> 16;
	uint a = (packedValue & 0xFF000000) >> 24;
	
    OutColor =  float4(r,g,b,a) ;
	}

So I'm sampling from the texture I wrote right?
unfortunatly is not working because I can see only black cubes whatever values I put inside texture elements...

Well,
Onestly I'm quite disoriented,
I'm creating the texture like I wrote above. So I have this 960*540 resolution texture where each textel is 4 bytes.

I tried to sample in this way in the hlsl shader
OutColor = TextureParameter.Sample(mySampler, float2(sizeX * uv.x, sizeY * uv.y));
having the foresight to change the input from
Texture2D <uint> TextureParameter;
to
Texture2D TextureParameter;

unfortunatly I still see black cubes.

I've asket another method to write into the texture, I received help in the forum, here is my code now, as you can see after I modify the texture I call the pixel shader.

 //MY STUFF
			 //Create Texture
			ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(FCreateActorsTexure,
				FTexture2DRHIRef, TexurePtr, InputTexture,
				{
					FRHIResourceCreateInfo CreateInfo;
					TexurePtr = RHICreateTexture2D(960, 540, PF_R32_UINT, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
					//FRHICommandListImmediate& RHICmdList = GRHICommandList.GetImmediateCommandList();
					//RHICmdList.ClearColorTexture(TexurePtr, FLinearColor::Red, FIntRect());
				}
			);

			//Update Texture
			uint32 BufferSize = 960 * 540 * 4;
			uint8 * SourceBuffer = new uint8[BufferSize];

			for (uint32 i = 0; i < BufferSize; i++)
			{
				SourceBuffer[i] = 20;
			}

			ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(FUpdateActorsTexure,
				FTexture2DRHIRef, TexurePtr, InputTexture,
				uint8*, NewData, SourceBuffer,
				uint32, Size, BufferSize,
				{
					uint32 DestStride;
					uint32* DestBuffer = (uint32*)RHILockTexture2D(TexurePtr, 0, RLM_WriteOnly, DestStride, false);
					FMemory::Memcpy(DestBuffer, NewData, Size);
					RHIUnlockTexture2D(TexurePtr, 0, false);
					delete[] NewData;
				}
			);

			PixelShading->ExecutePixelShader(RenderTarget, InputTexture, FColor(EndColorBuildup * 255, 0, 0, 255), ComputeShaderBlend);

Hello,
As promised I'll put something working hoping that can be usefull to someone. the code is not clean. This Is the original one in the Demo + some lines that load a custom texture to the pixel shader.

 FTexture2DRHIRef InputTexture = NULL;

		if (ComputeShading) {
			ComputeShading->ExecuteComputeShader(TotalElapsedTime);
			InputTexture =
				ComputeShading->GetTexture(); //This is the output texture from the compute shader that we will pass to the pixel shader.
		}

		ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(FCreateActorsTexure,
		FTexture2DRHIRef, TexurePtr, InputTexture,
			{
				FRHIResourceCreateInfo CreateInfo;
		TexurePtr = RHICreateTexture2D(960, 540, PF_R8G8B8A8, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
			}
		);

		//Update Texture
		uint32 BufferSize = 960 * 540 * 4;
		uint8 * SourceBuffer = new uint8[BufferSize];
		uint8 myrand = (FMath::RandRange(0, 255));
		for (uint32 i = 0; i < BufferSize; i=i+4)
		{
		SourceBuffer[i] = 0;
		SourceBuffer[i+1] = 255;
		SourceBuffer[i+2] = 0;
		SourceBuffer[i+3] = 255;
		}

		ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(FUpdateActorsTexure,
		FTexture2DRHIRef, TexurePtr, InputTexture,
		uint8*, NewData, SourceBuffer,
		uint32, Size, BufferSize,
		{
		uint32 DestStride;
		uint8* DestBuffer = (uint8*)RHILockTexture2D(TexurePtr, 0, RLM_WriteOnly, DestStride, false);
		FMemory::Memcpy(DestBuffer, NewData, Size);
		RHIUnlockTexture2D(TexurePtr, 0, false);
		delete[] NewData;
		}
		);




        ComputeShaderBlend = FMath::Clamp(ComputeShaderBlend +
                                          ComputeShaderBlendScalar * DeltaSeconds, 0.0f, 1.0f);
        PixelShading->ExecutePixelShader(RenderTarget, InputTexture,
                                         FColor(EndColorBuildup * 255, 0, 0, 255), ComputeShaderBlend);
    }

for example above I create a green texture (0, 255, 0,255)

here the modified pixel shader

Texture2D <uint> TextureParameter;

SamplerState mySampler
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

void MainPixelShader(
	in float2 uv : TEXCOORD0,
	out float4 OutColor : SV_Target0
	)
{
	//First we need to unpack the uint material and retrieve the underlying R8G8B8A8_UINT values.
	float sizeX, sizeY;
	TextureParameter.GetDimensions(sizeX, sizeY);
	uint packedValue = TextureParameter.Load(int3(uv.x,uv.y, 0));
	uint r = (packedValue & 0x000000FF);
	uint g = (packedValue & 0x0000FF00) >> 8;
	uint b = (packedValue & 0x00FF0000) >> 16;
	uint a = (packedValue & 0xFF000000) >> 24;
    
    //sampling
   // OutColor = TextureParameter.Sample(mySampler, float2(sizeX * uv.x, sizeY * uv.y));

    
	OutColor = float4(r,g,b,a); 
    //OutColor = float4(255,255,0,255);	 //yellow
}

thanks for the help temaran.


I have a lot of doubts,
why if I execute

		ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(FCreateActorsTexure,
		FTexture2DRHIRef, TexurePtr, InputTexture,
			{
				FRHIResourceCreateInfo CreateInfo;
		TexurePtr = RHICreateTexture2D(960, 540, PF_R8G8B8A8, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
			}
		);

whitout before executing this:

		if (ComputeShading) {
			ComputeShading->ExecuteComputeShader(TotalElapsedTime);
			InputTexture =
				ComputeShading->GetTexture(); //This is the output texture from the compute shader that we will pass to the pixel shader.
		}

It crashes?

Then, How to bind new parameters to the shaders?