How do I implement focus-based dynamic DOF?

Hi guys,
One of the features that I see used in many games and would like to use in the project I am currently working on is the DOF based on the thing you are looking at. Basically it is the simulation of an eye focus, when everything in front and behind the object your eye is focused on is being blurred. You can see this feature used in STALKER Clear Sky, for example (while you are reloading weapon, you “eye” concentrates on it, so everything in background looks blurred and unfocused).

Does anyone have ideas of how to implement this in UE4 (the simplest way)? I feel that the only way would be getting into post-process chain code and rewriting the DOF, or adding new type of DOF. Any ideas?

Here is a solution for UDK, but in UE4 we don’t have Post-process chain concept any more, and also there is no location-based DOF now, so I still don’t know, how to implement the feature.

If you want to have that effect while aiming, you can perform a line trace from the camera and calculate the distance of the hit object, then adjust the player cam’s DOF values depending on that. It would be a little complicated but nothing cant be done with Blueprints. And it should be a lot easier if you want to do it for weapon reload only.

Ok, I am assuming that I should do that in Pawn blueprint, but how do I get access to the post process, applied to the pawn, from it’s blueprint? I did not find any such function to work with.

You’ll change those values in your character blueprint’s camera. Camera actors have all of the post process settings in themselves.

Yeah, I was looking there and now I understand, what’s the problem. The camera is added to the player class via C++ (I am using C++ FPS project template), and it has ReadOnly property in C++ native class. So, I can’t edit camera properties:

But, if I go back into cpp and change the properties to BlueprintReadWrite, I get this compiling error:

Do you know a way to overcome this, or a workaround?

Sorry, i know literally nothing about the C++ side of things. :\ I was assuming you’d start with a blank or BP template.

No problem, man, still u helped quite a lot and now I clearly know, what to do. Thanks :slight_smile:
I will attempt to do all the raycasting and DOF modification in the C++ tomorrow. In any case this is much faster and optimized way. I will write to this topic, upon getting any working results.

Ok, so I found a solution that works. It requires tweaking of DOF parameters and does not give instant desired result. What it does give is an instrument to change any DOF parameters on the scene according to the distance between the player and the overlapping object.
First, in Character class we add a raytracing function (you can add it somewhere else, ofc)

/*	Raytrace from a char location to the camera dir
	Utilized for dynamic DOF functionality             *///Lordink
bool AWolfdaleCharacter::TraceViewFocus(FHitResult* hitResult)
{
	FCollisionQueryParams hitTraceParams(FName(TEXT("RV_Trace")), true, this);
	FVector CameraLoc;
	FRotator CameraRot;
	GetActorEyesViewPoint(CameraLoc, CameraRot);
	
	FVector v_Start = CameraLoc;
	//The interaction distance is best set via UPROPERTY later on.
	FVector v_End = CameraLoc + (CameraRot.Vector() * 50000); // 50k is supposed to b 50m

	hitTraceParams.bTraceComplex = true; //Maybe should be set to false later on
	hitTraceParams.bTraceAsyncScene = true; //false for later on?
	hitTraceParams.bReturnPhysicalMaterial = true; //also false later on?
	hitTraceParams.TraceTag = FName("WD_CamTrace");
	
	//RayTracing:
	//bool Trace = GetWorld()->LineTraceSingle(*hitResult, v_Start, v_End, ECC_Pawn, hitTraceParams);
	bool Trace = GetWorld()->LineTraceSingle(*hitResult, v_Start, v_End, ECC_Pawn, hitTraceParams);
	
	if (!Trace){ //Prevent code from doing anything with non-traced hit results
		hitResult = NULL;
	}
	return Trace;
}

Then we can call this function anywhere where you would like to update the DOF. E.g. in ReceiveTick() funciton, which is called every tick, as far as I understand:

void AWolfdaleCharacter::ReceiveTick(float DeltaSeconds)
{
	//Call the base class func for its own functionality
	ACharacter::ReceiveTick(DeltaSeconds);

        //Raytrace and then rework the DOF
		FHitResult tracehit(ForceInit);
		bool CamTrace = TraceViewFocus(&tracehit);
		if (CamTrace){
			FVector v_Tracehitloc = tracehit.Location;
			FVector v_CamLoc;
			FRotator v_CamRot;
			GetActorEyesViewPoint(v_CamLoc, v_CamRot);
			float distance = FVector::Dist(v_CamLoc, v_Tracehitloc);
			FirstPersonCameraComponent->PostProcessSettings.DepthOfFieldScale = 0.1f;

			FirstPersonCameraComponent->PostProcessSettings.DepthOfFieldFocalDistance = distance;
			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, FString::SanitizeFloat(distance));
		}

}

This is not very optimized code, guys. I will be working on it, and you are also free to modify and enhance the code in my post.

Awesome! Glad you figured it out and thanks for sharing. :slight_smile:

I gave it a shot with BP last night and everything worked just fine until DOF. For some reason the cam’s DOF settings are bools only, couldnt edit them as a float in the blueprint. Matinee can do that but it works for level blueprint only. I’ll have to take a better look, maybe there is something i’m missing.

As I wrote earlier, for me the same problem was appearing as I was trying to modify the camera component of Cpp parent class. If u use blueprint-only template, however, u shud have full access to post proc params.
I tried it myself in other template, and I have all the settings (first dozens of them are bools, but then go actual settings):

Hah! I thought the other half had only some of the settings as floats(that crazy long pp node…) Cheers Lordink!

No problem, mate. Here is a short vid with my current results:

Cool! I’ll try to finish mine when i have the time. I can create a Wiki page for this topic together with your code when i get the result i want with only BP.

Nice idea. We can both contribute to the page. I will put there newer version of code with smooth transition like in video.
Just send me a link to the page or post it here, whenever you make it :slight_smile:

Hey mate!

Finally i gave it some time and got to a point i’m almost happy with.

I managed to get a smooth transition on the same surface by calculating the distance myself instead of using Get Distance To node, but as you can see i cant achieve a smooth transition as your solution when the trace hits different objects in different distances. So i need your help!

Here’s my blueprint setup:

What can i do to make the focus distance values interpolate smoothly?

Hey there!

I use a very simple way without any cool math, and actually I would advance it a little bit as soon as I get time.
Every tick I look at my current focus distance and compare it to the distance I get from ray tracing. Then, based on the difference, I either add or subtract some constant value with my current distance. This constant value is small enough to make each transition smooth, and, as transition happens every tick, it eventually gets to the traced value with those additions/subtractions.

One important thing is that you should not try to compare current focus distance with exact traced distance, but rather have some kind of “hysteresis” value, in which the current focus should be in order to satisfy the comparison. If you don’t get it, let me just give a quick example (or skip to next paragraph if u get): imagine your current focus distance is 500, and traced distance to object is 923. Camera does not move. Every tick you will be adding a constant of 50 to the focus distance. After some ticks it will be 900, which is too small, so it will add again and get 950 in next tick, which is too big so it will subtract, and so on, it will be jumping all the time.To solve that, we can make a hysteresis of e.g. 30, and then it will be satisfied with value of 900 and will not raise it more.

That’s my simple way. The way to improve it is to add/subtract different values every tick, depending on the difference between current dist and traced dist. The bigger the difference, the faster should be transition. This is simple to implement, and I suggest that as a superior way to just adding a constant every frame.

Hope, that helps a little :slight_smile: I can post my cpp code, if u need.

Thanks a lot for the explanation, Lordink! It helped.

Here’s the final result:

And here’s how i handled the blend:

And it also adepts the transition speed depending on how big the distance is between the last and the current hit points, so i’m pretty happy with this. Quite an achievement for a math and programming noob like me!

I’ll post the Wiki link here when i set it up so that you can post your code too.

Cheers!

Very nice. Glad I could help :slight_smile:
I would personally suggest trying out the Gaussian blur instead of Bokeh, if u will be going to put this system into the developed game. Bokeh may look a little too crazy with some focus distances :slight_smile:

Yeah, this is the bare bones of the system so i didnt care much about the looks for now. Blur type, transition speed and dof scale should be set depending on the users needs anyway. :slight_smile: