Download

Function is not declared in header file but is present in source file?HELP!!

Header file of Pointlightcomponent

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.  


#pragma once  
#include "PointLightComponent.generated.h"  

/**  
 * A light component which emits light from a single point equally in all directions.  
 */  
UCLASS(ClassGroup=Lights, hidecategories=(Object, LightShafts), editinlinenew, meta=(BlueprintSpawnableComponent))  
class ENGINE_API UPointLightComponent : public ULightComponent  
{  
    GENERATED_UCLASS_BODY()  

    UPROPERTY()  
    float Radius_DEPRECATED;  

    /**  
     * Bounds the light's visible influence.    
     * This clamping of the light's influence is not physically correct but very important for performance, larger lights cost more.  
     */  
    UPROPERTY(interp, BlueprintReadOnly, Category=Light, meta=(UIMin = "8.0", UIMax = "16384.0", SliderExponent = "5.0"))  
    float AttenuationRadius;  

    /**   
     * Whether to use physically based inverse squared distance falloff, where AttenuationRadius is only clamping the light's contribution.    
     * Disabling inverse squared falloff can be useful when placing fill lights (don't want a super bright spot near the light).  
     * When enabled, the light's Intensity is in units of lumens, where 1700 lumens is a 100W lightbulb.  
     * When disabled, the light's Intensity is a brightness scale.  
     */  
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Light, AdvancedDisplay)  
    uint32 bUseInverseSquaredFalloff:1;  

    /**  
     * Controls the radial falloff of the light when UseInverseSquaredFalloff is disabled.   
     * 2 is almost linear and very unrealistic and around 8 it looks reasonable.  
     * With large exponents, the light has contribution to only a small area of its influence radius but still costs the same as low exponents.  
     */  
    UPROPERTY(interp, BlueprintReadOnly, Category=Light, AdvancedDisplay, meta=(UIMin = "2.0", UIMax = "16.0"))  
    float LightFalloffExponent;  

    /**   
     * Radius of light source shape.  
     * Note that light sources shapes which intersect shadow casting geometry can cause shadowing artifacts.  
     */  
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Light)  
    float SourceRadius;  

    /**   
     * Length of light source shape.  
     * Note that light sources shapes which intersect shadow casting geometry can cause shadowing artifacts.  
     */  
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Light)  
    float SourceLength;  

    /** The Lightmass settings for this object. */  
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Light, meta=(ShowOnlyInnerProperties))  
    struct FLightmassPointLightSettings LightmassSettings;  

    UFUNCTION(BlueprintCallable, Category="Rendering|Lighting")  
    void SetAttenuationRadius(float NewRadius);  

    UFUNCTION(BlueprintCallable, Category="Rendering|Lighting")  
    void SetLightFalloffExponent(float NewLightFalloffExponent);  

    UFUNCTION(BlueprintCallable, Category="Rendering|Lighting")  
    void SetSourceRadius(float bNewValue);  

protected:  
    // Begin UActorComponent Interface  
    virtual void SendRenderTransform_Concurrent() override;  
    // End UActorComponent Interface  

public:  

    // ULightComponent interface.  
    virtual bool AffectsBounds(const FBoxSphereBounds& Bounds) const;  
    virtual FVector4 GetLightPosition() const;  
    virtual FBox GetBoundingBox() const;  
    virtual FSphere GetBoundingSphere() const;  
    virtual ELightComponentType GetLightType() const;  
    virtual FLightSceneProxy* CreateSceneProxy() const override;  

    // Begin UObject Interface  
    virtual void Serialize(FArchive& Ar) override;  
    virtual void PostLoad() override;  
#if WITH_EDITOR  
    virtual bool CanEditChange(const UProperty* InProperty) const override;  
    virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;  
#endif // WITH_EDITOR  
    // End UObject Interface  

    /**   
     * This is called when property is modified by InterpPropertyTracks  
     *  
     * @param PropertyThatChanged    Property that changed  
     */  
    virtual void PostInterpChange(UProperty* PropertyThatChanged);  

private:  

    /** Pushes the value of radius to the rendering thread. */  
    void PushRadiusToRenderThread();  
};  

Source file of Pointlightcomponent

/**  
     * Sets up a projected shadow initializer for shadows from the entire scene.  
     * @return True if the whole-scene projected shadow should be used.  
     */  
    virtual bool GetWholeSceneProjectedShadowInitializer(const FSceneViewFamily& ViewFamily, TArray<FWholeSceneProjectedShadowInitializer, TInlineAllocator<6> >& OutInitializers) const  
    {  
        if (ViewFamily.GetFeatureLevel() >= ERHIFeatureLevel::SM4  
            && GAllowPointLightCubemapShadows != 0)  
        {  
            FWholeSceneProjectedShadowInitializer& OutInitializer = *new(OutInitializers) FWholeSceneProjectedShadowInitializer;  
            OutInitializer.bDirectionalLight = false;  
            OutInitializer.bOnePassPointLightShadow = true;  
            OutInitializer.PreShadowTranslation = -GetLightToWorld().GetOrigin();  
            OutInitializer.WorldToLight = GetWorldToLight().RemoveTranslation();  
            OutInitializer.Scales = FVector(1, 1, 1);  
            OutInitializer.FaceDirection = FVector(0,0,1);  
            OutInitializer.SubjectBounds = FBoxSphereBounds(FVector(0, 0, 0),FVector(Radius,Radius,Radius),Radius);  
            OutInitializer.WAxis = FVector4(0,0,1,0);  
            OutInitializer.MinLightW = 0.1f;  
            OutInitializer.MaxDistanceToCastInLightW = Radius;  
            OutInitializer.SplitIndex = INDEX_NONE;  
            OutInitializer.bRayTracedDistanceFieldShadow = UseRayTracedDistanceFieldShadows() && DoesPlatformSupportDistanceFieldShadowing(ViewFamily.GetShaderPlatform());  
          
            return true;  
        }  
          
        return false;  
    }  

    FPointLightSceneProxy(const UPointLightComponent* Component)  
    :    TPointLightSceneProxy<FPointLightPolicy>(Component)  
    {}  
};  

I have two questions

  1. GetWholeSceneProjectedShadowInitializer() function is not defined in header file and how this function is present in source file?
  2. And when OutInitializer object is being created using new operator the argument (OutInitializers) is passed before FWholeSceneProjectedShadowInitializer why not after?
    Please help!!

Look at the rest of the scope. That function isn’t in the header because it’s part of the FPointLightSceneProxy class which exists only in the source file. Scene proxies and render proxies are render thread concepts that game code normally doesn’t have to deal with, so Epic chose to hide them in this fashion.

The “argument” in OutInitializers is what is called a placement new. Normally, the C++ operator new does two things: Allocate enough memory for an instance of the object, then call the constructor. Providing a pointer to the new operator in this fashion removes the first step and basically tells the new operator “Hey, here is the address to a block of memory I’ve already allocated, use that instead of allocating memory on your own”. It’s a fairly advanced memory management concept and you shouldn’t often have to use it.

-Camille

Can you please explain me answer to first question in detail?

But i still cant find that function in FPointLightSceneProxy class.

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.

/*=============================================================================
	PointLightSceneProxy.h: Point light scene info definition.
=============================================================================*/

#ifndef __PointLightSceneProxy_H__
#define __PointLightSceneProxy_H__

/**
 * Compute the screen bounds of a point light along one axis.
 * Based on http://www.gamasutra.com/features/20021011/lengyel_06.htm
 * and http://sourceforge.net/mailarchive/message.php?msg_id=10501105
 */
static bool GetPointLightBounds(
	float LightX,
	float LightZ,
	float Radius,
	const FVector& Axis,
	float AxisSign,
	const FSceneView& View,
	float ViewX,
	float ViewSizeX,
	int32& OutMinX,
	int32& OutMaxX
	)
{
	// Vertical planes: T = <Nx, 0, Nz, 0>
	float Discriminant = (FMath::Square(LightX) - FMath::Square(Radius) + FMath::Square(LightZ)) * FMath::Square(LightZ);
	if(Discriminant >= 0)
	{
		float SqrtDiscriminant = FMath::Sqrt(Discriminant);
		float InvLightSquare = 1.0f / (FMath::Square(LightX) + FMath::Square(LightZ));

		float Nxa = (Radius * LightX - SqrtDiscriminant) * InvLightSquare;
		float Nxb = (Radius * LightX + SqrtDiscriminant) * InvLightSquare;
		float Nza = (Radius - Nxa * LightX) / LightZ;
		float Nzb = (Radius - Nxb * LightX) / LightZ;
		float Pza = LightZ - Radius * Nza;
		float Pzb = LightZ - Radius * Nzb;

		// Tangent a
		if(Pza > 0)
		{
			float Pxa = -Pza * Nza / Nxa;
			FVector4 P = View.ViewMatrices.ProjMatrix.TransformFVector4(FVector4(Axis.X * Pxa,Axis.Y * Pxa,Pza,1));
			float X = (Dot3(P,Axis) / P.W + 1.0f * AxisSign) / 2.0f * AxisSign;
			if(FMath::IsNegativeFloat(Nxa) ^ FMath::IsNegativeFloat(AxisSign))
			{
				OutMaxX = FMath::Min<int64>(FMath::CeilToInt(ViewSizeX * X + ViewX),OutMaxX);
			}
			else
			{
				OutMinX = FMath::Max<int64>(FMath::FloorToInt(ViewSizeX * X + ViewX),OutMinX);
			}
		}

		// Tangent b
		if(Pzb > 0)
		{
			float Pxb = -Pzb * Nzb / Nxb;
			FVector4 P = View.ViewMatrices.ProjMatrix.TransformFVector4(FVector4(Axis.X * Pxb,Axis.Y * Pxb,Pzb,1));
			float X = (Dot3(P,Axis) / P.W + 1.0f * AxisSign) / 2.0f * AxisSign;
			if(FMath::IsNegativeFloat(Nxb) ^ FMath::IsNegativeFloat(AxisSign))
			{
				OutMaxX = FMath::Min<int64>(FMath::CeilToInt(ViewSizeX * X + ViewX),OutMaxX);
			}
			else
			{
				OutMinX = FMath::Max<int64>(FMath::FloorToInt(ViewSizeX * X + ViewX),OutMinX);
			}
		}
	}

	return OutMinX <= OutMaxX;
}

/** The parts of the point light scene info that aren't dependent on the light policy type. */
class FPointLightSceneProxyBase : public FLightSceneProxy
{
public:

	/** The light radius. */
	float Radius;

	/** One over the light's radius. */
	float InvRadius;

	/** The light falloff exponent. */
	float FalloffExponent;

	/** Radius of light source shape */
	float SourceRadius;

	/** Length of light source shape */
	float SourceLength;

	/** Whether light uses inverse squared falloff. */
	const uint32 bInverseSquared : 1;

	/** Initialization constructor. */
	FPointLightSceneProxyBase(const UPointLightComponent* Component)
	:	FLightSceneProxy(Component)
	,	FalloffExponent(Component->LightFalloffExponent)
	,	SourceRadius(Component->SourceRadius)
	,	SourceLength(Component->SourceLength)
	,	bInverseSquared(Component->bUseInverseSquaredFalloff)
	{
		UpdateRadius(Component->AttenuationRadius);
	}

	/**
	* Called on the light scene info after it has been passed to the rendering thread to update the rendering thread's cached info when
	* the light's radius changes.
	*/
	void UpdateRadius_GameThread(UPointLightComponent* Component);

	// FLightSceneInfo interface.

	/** @return radius of the light or 0 if no radius */
	virtual float GetRadius() const 
	{ 
		return Radius; 
	}

	virtual float GetSourceRadius() const 
	{ 
		return SourceRadius; 
	}

	virtual bool IsInverseSquared() const
	{
		return bInverseSquared;
	}

	virtual bool AffectsBounds(const FBoxSphereBounds& Bounds) const
	{
		if((Bounds.Origin - GetLightToWorld().GetOrigin()).SizeSquared() > FMath::Square(Radius + Bounds.SphereRadius))
		{
			return false;
		}

		if(!FLightSceneProxy::AffectsBounds(Bounds))
		{
			return false;
		}

		return true;
	}

	virtual bool GetScissorRect(FIntRect& ScissorRect, const FSceneView& View) const override
	{
		ScissorRect = View.ViewRect;

		// Calculate a scissor rectangle for the light's radius.
		if((GetLightToWorld().GetOrigin() - View.ViewMatrices.ViewOrigin).Size() > Radius)
		{
			FVector LightVector = View.ViewMatrices.ViewMatrix.TransformPosition(GetLightToWorld().GetOrigin());

			if(!GetPointLightBounds(
				LightVector.X,
				LightVector.Z,
				Radius,
				FVector(+1,0,0),
				+1,
				View,
				View.ViewRect.Min.X,
				View.ViewRect.Width(),
				ScissorRect.Min.X,
				ScissorRect.Max.X))
			{
				return false;
			}

			int32 ScissorMinY = View.ViewRect.Min.Y;
			int32 ScissorMaxY = View.ViewRect.Max.Y;
			if(!GetPointLightBounds(
				LightVector.Y,
				LightVector.Z,
				Radius,
				FVector(0,+1,0),
				-1,
				View,
				View.ViewRect.Min.Y,
				View.ViewRect.Height(),
				ScissorRect.Min.Y,
				ScissorRect.Max.Y))
			{
				return false;
			}

			return true;
		}
		else
		{
			return false;
		}
	}

	virtual void SetScissorRect(FRHICommandList& RHICmdList, const FSceneView& View) const override
	{
		FIntRect ScissorRect;

		if (FPointLightSceneProxyBase::GetScissorRect(ScissorRect, View))
		{
			RHICmdList.SetScissorRect(true, ScissorRect.Min.X, ScissorRect.Min.Y, ScissorRect.Max.X, ScissorRect.Max.Y);
		}
		else
		{
			RHICmdList.SetScissorRect(false, 0, 0, 0, 0);
		}
	}

	virtual bool GetPerObjectProjectedShadowInitializer(const FBoxSphereBounds& SubjectBounds,class FPerObjectProjectedShadowInitializer& OutInitializer) const
	{
		// Use a perspective projection looking at the primitive from the light position.
		FVector LightPosition = LightToWorld.GetOrigin();
		FVector LightVector = SubjectBounds.Origin - LightPosition;
		float LightDistance = LightVector.Size();
		float SilhouetteRadius = 1.0f;
		const float SubjectRadius = SubjectBounds.SphereRadius;
		const float ShadowRadiusMultiplier = 1.1f;

		if (LightDistance > SubjectRadius)
		{
			SilhouetteRadius = FMath::Min(SubjectRadius * FMath::InvSqrt((LightDistance - SubjectRadius) * (LightDistance + SubjectRadius)), 1.0f);
		}

		if (LightDistance <= SubjectRadius * ShadowRadiusMultiplier)
		{
			// Make the primitive fit in a single < 90 degree FOV projection.
			LightVector = SubjectRadius * LightVector.SafeNormal() * ShadowRadiusMultiplier;
			LightPosition = (SubjectBounds.Origin - LightVector );
			LightDistance = SubjectRadius * ShadowRadiusMultiplier;
			SilhouetteRadius = 1.0f;
		}

		OutInitializer.bDirectionalLight = false;
		OutInitializer.PreShadowTranslation = -LightPosition;
		OutInitializer.WorldToLight = FInverseRotationMatrix((LightVector / LightDistance).Rotation());
		OutInitializer.Scales = FVector(1.0f,1.0f / SilhouetteRadius,1.0f / SilhouetteRadius);
		OutInitializer.FaceDirection = FVector(1,0,0);
		OutInitializer.SubjectBounds = FBoxSphereBounds(SubjectBounds.Origin - LightPosition,SubjectBounds.BoxExtent,SubjectBounds.SphereRadius);
		OutInitializer.WAxis = FVector4(0,0,1,0);
		OutInitializer.MinLightW = 0.1f;
		OutInitializer.MaxDistanceToCastInLightW = Radius;
		return true;
	}

private:

	/** Updates the light scene info's radius from the component. */
	void UpdateRadius(float ComponentRadius)
	{
		Radius = ComponentRadius;

		// Min to avoid div by 0 (NaN in InvRadius)
		InvRadius = 1.0f / FMath::Max(0.00001f, ComponentRadius);
	}
};

/**
 * The scene info for a point light.
 */
template<typename LightPolicyType>
class TPointLightSceneProxy : public FPointLightSceneProxyBase
{
public:

	/** Initialization constructor. */
	TPointLightSceneProxy(const UPointLightComponent* Component)
		:	FPointLightSceneProxyBase(Component)
	{
	}
};

#endif

It’s a rather lengthy subject that has to do with the way the C++ compiler works. You need to understand the difference between definition and declaration, which is something this Stack Overflow question can explain much better than me.

With that in mind, since most code is meant to be used in different places, that’s why we put declarations in header files, so any other code file can include it if they need access to this information. But as explained in the Stack Overflow answers, you can only ever have one definition. If you put a definition in a header file, then you get multiple definitions as soon as more than one file tries to include it and the compiler is unable to resolve that. (Inline functions are a special case due to the way they are compiled.) But in some uncommon cases, you might not actually need multiple files to access the same stuff, i.e.: you have a single declaration.

This is what’s happening with the FPointLightSceneProxy. It is only used in one place, which is PointLightComponent.cpp. Rather than manage this in a separate header file, Epic simply decided to merge the definition and declaration in the same place, in the file where it’s used.

The good news is you don’t really need to worry about these nitty gritty details to work with C++ (as long as you respect the compiler limitations, obviously). If you’d like to know more, this other question contains a few great books to learn about C++. I personally am a big fan of Effective C++ and actually try to reread it once every odd year to keep it fresh. But it does assume a fair proficiency with the language and I don’t know where you are in that regard.

I got it!! thanks :slight_smile:

Is this equivalent?

And if i Change code to

FWholeSceneProjectedShadowInitializer& OutInitializer = *new FWholeSceneProjectedShadowInitializer(OutInitializers);

Is this code equivalent to

FWholeSceneProjectedShadowInitializer& OutInitializer = *new(OutInitializers) FWholeSceneProjectedShadowInitializer;

??

Not at all. The first one is a regular new, for a constructor taking one argument. The second one is a placement new in the location provided by the argument, for a constructor with no arguments.