Component: Light
Light play a role in rendering. On the one hand, lights provide lighting for objects in the scene. On the other hand, they also generate shadow maps for objects that receive shadows. Arche provides four types of light:
- Ambient Light (
AmbientLight
) is not a component, because it does not need to set a specific attitude, so it does not need to be attached toEntity
, but is directly built intoScene
. - Point Light (
PointLight
): emit light in all directions from a single point. - Spotlight (
SpotLight
): Starting from a single point, it emits light within an angular range in a specific direction. - Directed Light (
DirectLight
): Light directed in a specific direction.
The base class of the light component Light
In addition to being the basis for the three light
components, it also provides the parameters required for shadow rendering:
bool enableShadow();
void setEnableShadow(bool enabled);
/**
* Shadow bias.
*/
float shadowBias();
void setShadowBias(float value);
/**
* Shadow intensity, the larger the value, the clearer and darker the shadow.
*/
float shadowIntensity();
void setShadowIntensity(float value);
/**
* Pixel range used for shadow PCF interpolation.
*/
float shadowRadius();
void setShadowRadius(float value);
virtual Matrix4x4F shadowProjectionMatrix() = 0;
When Arche renders shadows, there are three aspects to describe whether shadows occur:
Light
usesenableShadow
to determine whether a specific shadow map needs to be rendered according to the light.Renderer
usescastShadow
to determine whether it needs to be rendered when rendering shadow maps.Renderer
usesreceiveShadow
to determine whether it is necessary to consider the influence of shadows when rendering.
AmbientLightâ
Ambient light is not a component, because it does not need any information about the pose, but Global
Illumination. So it's built directly into Scene
. Global illumination is a very complex problem, currently ambient
light provides a uniform diffuse light for the entire scene:
struct EnvMapLight {
Vector3F diffuse;
uint32_t mipMapLevel;
float diffuseIntensity;
float specularIntensity;
float _pad1, _pad2;
};
In addition to this, the main role is to provide IBL lighting for PBR materials, i.e. image-based lighting. IBL lighting requires pre-computing for diffuse and specular, and some PBR algorithms also require a look-up table for BRDF calculations (LUT), these pre-computed data can be set by the type of ambient light:
/**
* Diffuse reflection spherical harmonics 3.
* @remarks Effective when diffuse reflection mode is `DiffuseMode.SphericalHarmonics`.
*/
const SphericalHarmonics3 &diffuseSphericalHarmonics();
void setDiffuseSphericalHarmonics(const SphericalHarmonics3 &value);
/**
* Diffuse reflection texture.
* @remarks This texture must be baked from MetalLoader::createIrradianceTexture
*/
std::shared_ptr<SampledTexture> diffuseTexture();
void setDiffuseTexture(std::shared_ptr<SampledTexture> value);
/**
* Specular reflection texture.
* @remarks This texture must be baked from MetalLoader::createSpecularTexture
*/
std::shared_ptr<SampledTexture> specularTexture();
void setSpecularTexture(std::shared_ptr<SampledTexture> value);
/**
* brdf loopup texture.
* @remarks This texture must be baked from MetalLoader::createBRDFLookupTable
*/
std::shared_ptr<SampledTexture> brdfTexture();
void setBRDFTexture(std::shared_ptr<SampledTexture> value);
tip
IBL's diffuse reflection can be pre-computed to obtain diffuse reflection cube maps, and pre-computed spherical harmonic parameters, including specular pre-computing and BRDF maps, can be obtained through the pre-computing tools provided by Arche.
PointLightâ
A point light represents a light that emits light in all directions from a single point, so the direction of the
light is not important, the position of the light is important, which can be seen from the structure
of PointLightData
:
struct PointLightData {
Vector3F color;
float _colorPad; // for align
Vector3F position;
float distance;
};
tip
Structures as UniformBuffers all require four-byte alignment.
When rendering shadow maps, point lights need to render a "universal" shadow map, that is, a shadow cube map, so it needs to be rendered in six directions, each of which is parallel to the coordinate axis, and rendered using perspective projection:
Matrix4x4F PointLight::shadowProjectionMatrix() {
return makepPerspective<float>(degreesToRadians(120), 1, 0.1, 100);
}
SpotLightâ
Spotlight means starting from a single point and emitting light in a specific direction and angle range, so in addition to the position of the light, the direction of the light and the angle that can be illuminated are also required:
struct SpotLightData {
Vector3F color;
float _colorPad; // for align
Vector3F position;
float _positionPad; // for align
Vector3F direction;
float distance;
float angleCos;
float penumbraCos;
float _pad; // for align
float _pad2; // for align
};
When rendering shadow maps, the spotlight corresponds to the simplest shadow map, and only needs to be rendered once, and the angle of the light provides various parameters needed to calculate the perspective projection:
Matrix4x4F SpotLight::shadowProjectionMatrix() {
const auto fov = std::min(M_PI / 2, angle * 2 * std::sqrt(2));
return makepPerspective<float>(fov, 1, 0.1, distance + 5);
}
DirectLightâ
Directional light means light directed in a specific direction, so the direction of the light is more important
than the position. In the Transform
component, you can get the direction worldForward
in world coordinates as the
direction of the light:
struct DirectLightData {
Vector3F color;
float _colorPad; // for align
Vector3F direction;
float _directionPad; // for align
};
When rendering shadows, since the directional light is not a light in a specific range, it is difficult to directly
write the perspective matrix required to render the shadow map. Reduced quality of shadow rendering due to precision
issues. In order to deal with this problem, the method of cascading shadows is generally used to cut the frustum, and
different perspective matrix parameters are set according to the distance. Therefore, shadowProjectionMatrix
is not
directly implemented in DirectLight
. The specific implementation method will be explained in detail when introducing
the shadow system.
Matrix4x4F DirectLight::shadowProjectionMatrix() {
assert(false && "cascade shadow don't use this projection");
}