Hello folks,
I’m trying to blur a cubemap that I’m projecting into the world in a post process material. Projecting the cubemap from a specific position in world space is easy, but I’m struggling to figure out a decent method of blurring it. The cubemap is sourced from a low resolution render target that gets updated every set interval in game.
Here is an example of the world space projection working as intended. The SceneCaptureCube component updates the render target, then I update parameters for it’s location in a post process material to project it in the same location.
I’ve been able to get a modified SpiralBlur custom node working using code found here: Vector Math? Coding?! HLSL! (Cubemap Blur) - Real Time VFX
Code:
float TwoPi = 6.283185; //So pseudo code modifications. This is the principle, if not the exact code. //Take the Reflection vector, or the CameraVector, whichever is more appropriate for your code. //Convert it into to Spherical Coordinates. //Z is unimportant once it is in Spherical Coordinates the radius is unimportant. Infact because you know //the camera vectors or the reflection vectors are normalized you know the the radius is 1, so you can save some caluclations there. //The conversion from normalized cartesian vector to spherical is found here: https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions //Input CameraVector as float3 (or float4, doesn't matter.) //float radius = 1; //Unneeded because we know it will be 1. If you want you can use it. float theta = atan2( CameraVector.y, CameraVector.x ); float phi = acos( CameraVector.z ); //Then almost everything is the same. float3 CurColor; float2 UV = float2( theta, phi ); //So now we are perturbing the spherical coordinates (excluding radius). float2 NewUV = UV; //So now we are perturbing the spherical coordinates (excluding radius). float3 NewCameraVector = 0; //We will use this to store the resultant cameravector for each sample. int i; float StepSize = Distance / (int)DistanceSteps; float CurDistance; float2 CurOffset; float SubOffset = 0; float accumdist = 0; if (DistanceSteps < 1) { return ProcessMaterialColorTextureLookup(TextureCubeSample(Tex, TexSampler, CameraVector)); //Just sample the texCUBE with the camera vector. } else { while (i < (int)DistanceSteps) { CurDistance += StepSize; for (int j = 0; j < (int)RadialSteps; j++) { SubOffset += 1; CurOffset.x = cos(TwoPi * (SubOffset / RadialSteps)); CurOffset.y = sin(TwoPi * (SubOffset / RadialSteps)); NewUV.x = UV.x + CurOffset.x * CurDistance; NewUV.y = UV.y + CurOffset.y * CurDistance; float distpow = pow(CurDistance, KernelPower); //Convert back before sampling. //The conversion can be found here: https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions //Like before since we know the radius is always 1, no need to include it. //NewUV.x stores the offsetted theta, and NewUV.y stores the offsetted phi. NewCameraVector = float3( cos(NewUV.x) * sin(NewUV.y), sin(NewUV.x) * sin(NewUV.y), cos(NewUV.y) ); CurColor += ProcessMaterialColorTextureLookup(TextureCubeSample(Tex, TexSampler, NewCameraVector)) * distpow; accumdist += distpow; } SubOffset += RadialOffset; i++; } CurColor = CurColor; CurColor /= accumdist; return CurColor; }
The issue is that while the spiral blur produces a great result, I lose the world space projection in the process of converting from Cartesian to Spherical coordinates and back.
I’m not well-versed in HLSL, but I did try adding the position offset at the end of the blur steps in the function. The result simply negated the blur effect and left me with what I had originally.
Any ideas on a solution? I thought about sampling the texture with world space offsets and blending them together, but wasn’t sure if that was really the best way to go.