added area lights

This commit is contained in:
turanszkij
2017-01-23 23:49:57 +01:00
parent 46d6dbd048
commit 0bdae65cbc
15 changed files with 589 additions and 11 deletions
+4
View File
@@ -691,6 +691,7 @@ void EditorComponent::Load()
pointLightTex = *(Texture2D*)Content.add("images/pointlight.dds");
spotLightTex = *(Texture2D*)Content.add("images/spotlight.dds");
dirLightTex = *(Texture2D*)Content.add("images/directional_light.dds");
areaLightTex = *(Texture2D*)Content.add("images/arealight.dds");
}
void EditorComponent::Start()
{
@@ -1162,6 +1163,9 @@ void EditorComponent::Compose()
case Light::DIRECTIONAL:
wiImage::Draw(&dirLightTex, fx, GRAPHICSTHREAD_IMMEDIATE);
break;
default:
wiImage::Draw(&areaLightTex, fx, GRAPHICSTHREAD_IMMEDIATE);
break;
}
}
}
+1 -1
View File
@@ -29,7 +29,7 @@ class EditorComponent
: public TiledForwardRenderableComponent
{
private:
wiGraphicsTypes::Texture2D pointLightTex, spotLightTex, dirLightTex;
wiGraphicsTypes::Texture2D pointLightTex, spotLightTex, dirLightTex, areaLightTex;
public:
MaterialWindow* materialWnd;
PostprocessWindow* postprocessWnd;
+73 -5
View File
@@ -10,7 +10,7 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr)
float screenH = (float)wiRenderer::GetDevice()->GetScreenHeight();
lightWindow = new wiWindow(GUI, "Light Window");
lightWindow->SetSize(XMFLOAT2(400, 420));
lightWindow->SetSize(XMFLOAT2(400, 500));
//lightWindow->SetEnabled(false);
GUI->AddWidget(lightWindow);
@@ -44,6 +44,45 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr)
distanceSlider->SetTooltip("Adjust the maximum range the light can affect.");
lightWindow->AddWidget(distanceSlider);
radiusSlider = new wiSlider(0.01f, 100, 0, 100000, "Radius: ");
radiusSlider->SetSize(XMFLOAT2(100, 30));
radiusSlider->SetPos(XMFLOAT2(x, y += step));
radiusSlider->OnSlide([&](wiEventArgs args) {
if (light != nullptr)
{
light->radius = args.fValue;
}
});
radiusSlider->SetEnabled(false);
radiusSlider->SetTooltip("Adjust the radius of an area light.");
lightWindow->AddWidget(radiusSlider);
widthSlider = new wiSlider(1, 100, 0, 100000, "Width: ");
widthSlider->SetSize(XMFLOAT2(100, 30));
widthSlider->SetPos(XMFLOAT2(x, y += step));
widthSlider->OnSlide([&](wiEventArgs args) {
if (light != nullptr)
{
light->width = args.fValue;
}
});
widthSlider->SetEnabled(false);
widthSlider->SetTooltip("Adjust the width of an area light.");
lightWindow->AddWidget(widthSlider);
heightSlider = new wiSlider(1, 100, 0, 100000, "Height: ");
heightSlider->SetSize(XMFLOAT2(100, 30));
heightSlider->SetPos(XMFLOAT2(x, y += step));
heightSlider->OnSlide([&](wiEventArgs args) {
if (light != nullptr)
{
light->height = args.fValue;
}
});
heightSlider->SetEnabled(false);
heightSlider->SetTooltip("Adjust the height of an area light.");
lightWindow->AddWidget(heightSlider);
fovSlider = new wiSlider(0.1f, XM_PI - 0.01f, 0, 100000, "FOV: ");
fovSlider->SetSize(XMFLOAT2(100, 30));
fovSlider->SetPos(XMFLOAT2(x, y += step));
@@ -133,6 +172,7 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr)
if (light != nullptr && args.iValue >= 0)
{
light->type = (Light::LightType)args.iValue;
light->UpdateLight();
SetLightType(light->type); // for the gui changes to apply to the new type
}
});
@@ -140,6 +180,10 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr)
typeSelectorComboBox->AddItem("Directional");
typeSelectorComboBox->AddItem("Point");
typeSelectorComboBox->AddItem("Spot");
typeSelectorComboBox->AddItem("Sphere");
typeSelectorComboBox->AddItem("Disc");
typeSelectorComboBox->AddItem("Rectangle");
typeSelectorComboBox->AddItem("Tube");
typeSelectorComboBox->SetTooltip("Choose the light source type...");
lightWindow->AddWidget(typeSelectorComboBox);
@@ -156,6 +200,9 @@ LightWindow::~LightWindow()
SAFE_DELETE(lightWindow);
SAFE_DELETE(energySlider);
SAFE_DELETE(distanceSlider);
SAFE_DELETE(radiusSlider);
SAFE_DELETE(widthSlider);
SAFE_DELETE(heightSlider);
SAFE_DELETE(fovSlider);
SAFE_DELETE(biasSlider);
SAFE_DELETE(shadowCheckBox);
@@ -175,6 +222,9 @@ void LightWindow::SetLight(Light* light)
energySlider->SetEnabled(true);
energySlider->SetValue(light->enerDis.x);
distanceSlider->SetValue(light->enerDis.y);
radiusSlider->SetValue(light->radius);
widthSlider->SetValue(light->width);
heightSlider->SetValue(light->height);
fovSlider->SetValue(light->enerDis.z);
biasSlider->SetEnabled(true);
biasSlider->SetValue(light->shadowBias);
@@ -191,6 +241,9 @@ void LightWindow::SetLight(Light* light)
else
{
distanceSlider->SetEnabled(false);
radiusSlider->SetEnabled(false);
widthSlider->SetEnabled(false);
heightSlider->SetEnabled(false);
fovSlider->SetEnabled(false);
biasSlider->SetEnabled(false);
shadowCheckBox->SetEnabled(false);
@@ -210,14 +263,29 @@ void LightWindow::SetLightType(Light::LightType type)
}
else
{
distanceSlider->SetEnabled(true);
if (type == Light::SPOT)
if (type == Light::SPHERE || type == Light::DISC || type == Light::RECTANGLE || type == Light::TUBE)
{
fovSlider->SetEnabled(true);
distanceSlider->SetEnabled(false);
radiusSlider->SetEnabled(true);
widthSlider->SetEnabled(true);
heightSlider->SetEnabled(true);
fovSlider->SetEnabled(false);
}
else
{
fovSlider->SetEnabled(false);
distanceSlider->SetEnabled(true);
radiusSlider->SetEnabled(false);
widthSlider->SetEnabled(false);
heightSlider->SetEnabled(false);
if (type == Light::SPOT)
{
fovSlider->SetEnabled(true);
}
else
{
fovSlider->SetEnabled(false);
}
}
}
}
+3
View File
@@ -28,6 +28,9 @@ public:
wiWindow* lightWindow;
wiSlider* energySlider;
wiSlider* distanceSlider;
wiSlider* radiusSlider;
wiSlider* widthSlider;
wiSlider* heightSlider;
wiSlider* fovSlider;
wiSlider* biasSlider;
wiCheckBox* shadowCheckBox;
+1
View File
@@ -203,6 +203,7 @@
</ItemGroup>
<ItemGroup>
<Image Include="fonts\basic.dds" />
<Image Include="images\arealight.dds" />
<Image Include="images\blood1.png" />
<Image Include="images\directional_light.dds" />
<Image Include="images\leaf.png">
@@ -233,6 +233,9 @@
<Image Include="images\blood1.png">
<Filter>images</Filter>
</Image>
<Image Include="images\arealight.dds">
<Filter>images</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="WickedEngineEditor.rc">
Binary file not shown.
+4 -2
View File
@@ -247,9 +247,11 @@ void main(ComputeShaderInput IN)
}
break;
case 0/*DIRECTIONAL_LIGHT*/:
case 3/*SPHERE_LIGHT*/:
case 4/*DISC_LIGHT*/:
case 5/*RECTANGLE_LIGHT*/:
case 6/*TUBE_LIGHT*/:
{
// Directional lights always get added to our light list.
// (Hopefully there are not too many directional lights!)
t_AppendLight(i);
o_AppendLight(i);
}
+441
View File
@@ -71,6 +71,7 @@ inline float shadowCascade(float4 shadowPos, float2 ShTex, float shadowKernel, f
return retVal;
}
inline LightingResult DirectionalLight(in LightArrayType light, in float3 N, in float3 V, in float3 P, in float roughness, in float3 f0)
{
LightingResult result;
@@ -224,4 +225,444 @@ inline LightingResult SpotLight(in LightArrayType light, in float3 N, in float3
return result;
}
// AREA LIGHTS
// Based on the Frostbite presentation:
// Moving Frostbite to Physically Based Rendering by Sebastien Lagarde, Charles de Rousiers, Siggraph 2014
// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
float cot(float x) { return cos(x) / sin(x); }
float acot(float x) { return atan(1 / x); }
// Return the closest point on the line (without limit)
float3 ClosestPointOnLine(float3 a, float3 b, float3 c)
{
float3 ab = b - a;
float t = dot(c - a, ab) / dot(ab, ab);
return a + t * ab;
}
// Return the closest point on the segment (with limit)
float3 ClosestPointOnSegment(float3 a, float3 b, float3 c)
{
float3 ab = b - a;
float t = dot(c - a, ab) / dot(ab, ab);
return a + saturate(t) * ab;
}
float RightPyramidSolidAngle(float dist, float halfWidth, float halfHeight)
{
float a = halfWidth;
float b = halfHeight;
float h = dist;
return 4 * asin(a * b / sqrt((a * a + h * h) * (b * b + h * h)));
}
float RectangleSolidAngle(float3 worldPos,
float3 p0, float3 p1,
float3 p2, float3 p3)
{
float3 v0 = p0 - worldPos;
float3 v1 = p1 - worldPos;
float3 v2 = p2 - worldPos;
float3 v3 = p3 - worldPos;
float3 n0 = normalize(cross(v0, v1));
float3 n1 = normalize(cross(v1, v2));
float3 n2 = normalize(cross(v2, v3));
float3 n3 = normalize(cross(v3, v0));
float g0 = acos(dot(-n0, n1));
float g1 = acos(dot(-n1, n2));
float g2 = acos(dot(-n2, n3));
float g3 = acos(dot(-n3, n0));
return g0 + g1 + g2 + g3 - 2 * PI;
}
// o : ray origin
// d : ray direction
// center : sphere center
// radius : sphere radius
// returns distance on the ray to the object if hit, 0 otherwise
float Trace_sphere(float3 o, float3 d, float3 center, float radius)
{
float3 rc = o - center;
float c = dot(rc, rc) - (radius*radius);
float b = dot(d, rc);
float dd = b*b - c;
float t = -b - sqrt(abs(dd));
float st = step(0.0, min(t, dd));
return lerp(-1.0, t, st);
}
// o : ray origin
// d : ray direction
// returns distance on the ray to the object if hit, 0 otherwise
float Trace_plane(float3 o, float3 d, float3 planeOrigin, float3 planeNormal)
{
return dot(planeNormal, (planeOrigin - o) / dot(planeNormal, d));
}
// o : ray origin
// d : ray direction
// A,B,C : traingle corners
// returns distance on the ray to the object if hit, 0 otherwise
float Trace_triangle(float3 o, float3 d, float3 A, float3 B, float3 C)
{
float3 planeNormal = normalize(cross(B - A, C - B));
float t = Trace_plane(o, d, A, planeNormal);
float3 p = o + d*t;
float3 N1 = normalize(cross(B - A, p - B));
float3 N2 = normalize(cross(C - B, p - C));
float3 N3 = normalize(cross(A - C, p - A));
float d0 = dot(N1, N2);
float d1 = dot(N2, N3);
float threshold = 1.0f - 0.001f;
return (d0 > threshold && d1 > threshold) ? 1.0f : 0.0f;
}
// o : ray origin
// d : ray direction
// A,B,C,D : rectangle corners
// returns distance on the ray to the object if hit, 0 otherwise
float Trace_rectangle(float3 o, float3 d, float3 A, float3 B, float3 C, float3 D)
{
return max(Trace_triangle(o, d, A, B, C), Trace_triangle(o, d, C, D, A));
}
// o : ray origin
// d : ray direction
// diskNormal : disk facing direction
// returns distance on the ray to the object if hit, 0 otherwise
float Trace_disk(float3 o, float3 d, float3 diskCenter, float diskRadius, float3 diskNormal)
{
float t = Trace_plane(o, d, diskCenter, diskNormal);
float3 p = o + d*t;
float3 diff = p - diskCenter;
return dot(diff, diff)<sqr(diskRadius);
}
inline float3 getDiffuseDominantDir(float3 N, float3 V, float NdotV, float roughness)
{
float a = 1.02341f * roughness - 1.51174f;
float b = -0.511705f * roughness + 0.755868f;
float lerpFactor = saturate((NdotV * a + b) * roughness);
return normalize(lerp(N, V, lerpFactor));
}
inline float3 getSpecularDominantDirArea(float3 N, float3 R, float roughness)
{
// Simple linear approximation
float lerpFactor = (1 - roughness);
return normalize(lerp(N, R, lerpFactor));
}
float illuminanceSphereOrDisk(float cosTheta, float sinSigmaSqr)
{
float sinTheta = sqrt(1.0f - cosTheta * cosTheta);
float illuminance = 0.0f;
// Note: Following test is equivalent to the original formula.
// There is 3 phase in the curve: cosTheta > sqrt(sinSigmaSqr),
// cosTheta > -sqrt(sinSigmaSqr) and else it is 0
// The two outer case can be merge into a cosTheta * cosTheta > sinSigmaSqr
// and using saturate(cosTheta) instead.
if (cosTheta * cosTheta > sinSigmaSqr)
{
illuminance = PI * sinSigmaSqr * saturate(cosTheta);
}
else
{
float x = sqrt(1.0f / sinSigmaSqr - 1.0f); // For a disk this simplify to x = d / r
float y = -x * (cosTheta / sinTheta);
float sinThetaSqrtY = sinTheta * sqrt(1.0f - y * y);
illuminance = (cosTheta * acos(y) - x * sinThetaSqrtY) * sinSigmaSqr + atan(sinThetaSqrtY / x);
}
return max(illuminance, 0.0f);
}
inline float3 _GetLeft(LightArrayType light) { return light.directionWS; }
inline float3 _GetUp(LightArrayType light) { return light.directionVS; }
inline float3 _GetFront(LightArrayType light) { return light.positionVS; }
inline float _GetRadius(LightArrayType light) { return light.texMulAdd.x; }
inline float _GetWidth(LightArrayType light) { return light.texMulAdd.y; }
inline float _GetHeight(LightArrayType light) { return light.texMulAdd.z; }
inline LightingResult SphereLight(in LightArrayType light, in float3 N, in float3 V, in float3 P, in float roughness, in float3 f0)
{
LightingResult result = (LightingResult)0;
float3 Lunormalized = light.positionWS - P;
float dist = length(Lunormalized);
float3 L = Lunormalized / dist;
float sqrDist = dot(Lunormalized, Lunormalized);
float cosTheta = clamp(dot(N, L), -0.999, 0.999); // Clamp to avoid edge case
// We need to prevent the object penetrating into the surface
// and we must avoid divide by 0, thus the 0.9999f
float sqrLightRadius = _GetRadius(light) * _GetRadius(light);
float sinSigmaSqr = min(sqrLightRadius / sqrDist, 0.9999f);
float fLight = illuminanceSphereOrDisk(cosTheta, sinSigmaSqr);
// We approximate L by the closest point on the reflection ray to the light source (representative point technique) to achieve a nice looking specular reflection
{
float3 r = reflect(V, N);
r = getSpecularDominantDirArea(N, r, roughness);
float3 centerToRay = dot(Lunormalized, r) * r - Lunormalized;
float3 closestPoint = Lunormalized + centerToRay * saturate(_GetRadius(light) / length(centerToRay));
L = normalize(closestPoint);
}
float3 lightColor = light.color.rgb*light.energy;
BRDF_MAKE(N, L, V);
result.specular = lightColor * BRDF_SPECULAR(roughness, f0) * fLight;
result.diffuse = lightColor * fLight / PI;
result.diffuse = max(0.0f, result.diffuse);
result.specular = max(0.0f, result.specular);
return result;
}
inline LightingResult DiscLight(in LightArrayType light, in float3 N, in float3 V, in float3 P, in float roughness, in float3 f0)
{
LightingResult result = (LightingResult)0;
float3 Lunormalized = light.positionWS - P;
float dist = length(Lunormalized);
float3 L = Lunormalized / dist;
float sqrDist = dot(Lunormalized, Lunormalized);
float3 lightPlaneNormal = _GetFront(light);
float cosTheta = clamp(dot(N, L), -0.999, 0.999);
float sqrLightRadius = _GetRadius(light) * _GetRadius(light);
// Do not let the surface penetrate the light
float sinSigmaSqr = sqrLightRadius / (sqrLightRadius + max(sqrLightRadius, sqrDist));
// Multiply by saturate(dot(planeNormal , -L)) to better match ground truth.
float fLight = illuminanceSphereOrDisk(cosTheta, sinSigmaSqr)
* saturate(dot(lightPlaneNormal, -L));
// We approximate L by the closest point on the reflection ray to the light source (representative point technique) to achieve a nice looking specular reflection
{
float3 r = reflect(V, N);
r = getSpecularDominantDirArea(N, r, roughness);
float t = Trace_plane(P, r, light.positionWS, lightPlaneNormal);
float3 p = P + r*t;
float3 centerToRay = p - light.positionWS;
float3 closestPoint = Lunormalized + centerToRay * saturate(_GetRadius(light) / length(centerToRay));
L = normalize(closestPoint);
}
float3 lightColor = light.color.rgb*light.energy;
BRDF_MAKE(N, L, V);
result.specular = lightColor * BRDF_SPECULAR(roughness, f0) * fLight;
result.diffuse = lightColor * fLight / PI;
result.diffuse = max(0.0f, result.diffuse);
result.specular = max(0.0f, result.specular);
return result;
}
inline LightingResult RectangleLight(in LightArrayType light, in float3 N, in float3 V, in float3 P, in float roughness, in float3 f0)
{
LightingResult result = (LightingResult)0;
float3 L = light.positionWS - P;
float dist = length(L);
L /= dist;
float3 lightPlaneNormal = _GetFront(light);
float3 lightLeft = _GetLeft(light);
float3 lightUp = _GetUp(light);
float lightWidth = _GetWidth(light);
float lightHeight = _GetHeight(light);
float3 worldPos = P;
float3 worldNormal = N;
float fLight = 0;
float halfWidth = lightWidth * 0.5;
float halfHeight = lightHeight * 0.5;
float3 p0 = light.positionWS + lightLeft * -halfWidth + lightUp * halfHeight;
float3 p1 = light.positionWS + lightLeft * -halfWidth + lightUp * -halfHeight;
float3 p2 = light.positionWS + lightLeft * halfWidth + lightUp * -halfHeight;
float3 p3 = light.positionWS + lightLeft * halfWidth + lightUp * halfHeight;
float solidAngle = RectangleSolidAngle(worldPos, p0, p1, p2, p3);
if (dot(worldPos - light.positionWS, lightPlaneNormal) > 0)
{
fLight = solidAngle * 0.2 * (
saturate(dot(normalize(p0 - worldPos), worldNormal)) +
saturate(dot(normalize(p1 - worldPos), worldNormal)) +
saturate(dot(normalize(p2 - worldPos), worldNormal)) +
saturate(dot(normalize(p3 - worldPos), worldNormal)) +
saturate(dot(normalize(light.positionWS - worldPos), worldNormal)));
}
fLight = max(0, fLight);
// We approximate L by the closest point on the reflection ray to the light source (representative point technique) to achieve a nice looking specular reflection
{
float3 r = reflect(-V, N);
r = getSpecularDominantDirArea(N, r, roughness);
float traced = Trace_rectangle(P, r, p0, p1, p2, p3);
[branch]
if (traced > 0)
{
// Trace succeeded so the light vector L is the reflection vector itself
L = r;
}
else
{
// The trace didn't succeed, so we need to find the closest point to the ray on the rectangle
// We find the intersection point on the plane of the rectangle
float3 tracedPlane = P + r * Trace_plane(P, r, light.positionWS, lightPlaneNormal);
// Then find the closest point along the edges of the rectangle (edge = segment)
float3 PC[4] = {
ClosestPointOnSegment(p0, p1, tracedPlane),
ClosestPointOnSegment(p1, p2, tracedPlane),
ClosestPointOnSegment(p2, p3, tracedPlane),
ClosestPointOnSegment(p3, p0, tracedPlane),
};
float dist[4] = {
distance(PC[0], tracedPlane),
distance(PC[1], tracedPlane),
distance(PC[2], tracedPlane),
distance(PC[3], tracedPlane),
};
float3 min = PC[0];
float minDist = dist[0];
[unroll]
for (uint iLoop = 1; iLoop < 4; iLoop++)
{
if (dist[iLoop] < minDist)
{
minDist = dist[iLoop];
min = PC[iLoop];
}
}
L = min - P;
}
L = normalize(L); // TODO: Is it necessary?
}
float3 lightColor = light.color.rgb*light.energy;
BRDF_MAKE(N, L, V);
result.specular = lightColor * BRDF_SPECULAR(roughness, f0) * fLight;
result.diffuse = lightColor * fLight / PI;
result.diffuse = max(0.0f, result.diffuse);
result.specular = max(0.0f, result.specular);
return result;
}
inline LightingResult TubeLight(in LightArrayType light, in float3 N, in float3 V, in float3 P, in float roughness, in float3 f0)
{
LightingResult result = (LightingResult)0;
float3 Lunormalized = light.positionWS - P;
float dist = length(Lunormalized);
float3 L = Lunormalized / dist;
float sqrDist = dot(Lunormalized, Lunormalized);
float3 lightLeft = _GetLeft(light);
float lightWidth = _GetWidth(light);
float3 worldPos = P;
float3 worldNormal = N;
float3 P0 = light.positionWS - lightLeft*lightWidth*0.5f;
float3 P1 = light.positionWS + lightLeft*lightWidth*0.5f;
// The sphere is placed at the nearest point on the segment.
// The rectangular plane is define by the following orthonormal frame:
float3 forward = normalize(ClosestPointOnLine(P0, P1, worldPos) - worldPos);
float3 left = lightLeft;
float3 up = cross(lightLeft, forward);
float3 p0 = light.positionWS - left * (0.5 * lightWidth) + _GetRadius(light) * up;
float3 p1 = light.positionWS - left * (0.5 * lightWidth) - _GetRadius(light) * up;
float3 p2 = light.positionWS + left * (0.5 * lightWidth) - _GetRadius(light) * up;
float3 p3 = light.positionWS + left * (0.5 * lightWidth) + _GetRadius(light) * up;
float solidAngle = RectangleSolidAngle(worldPos, p0, p1, p2, p3);
float fLight = solidAngle * 0.2 * (
saturate(dot(normalize(p0 - worldPos), worldNormal)) +
saturate(dot(normalize(p1 - worldPos), worldNormal)) +
saturate(dot(normalize(p2 - worldPos), worldNormal)) +
saturate(dot(normalize(p3 - worldPos), worldNormal)) +
saturate(dot(normalize(light.positionWS - worldPos), worldNormal)));
// We then add the contribution of the sphere
float3 spherePosition = ClosestPointOnSegment(P0, P1, worldPos);
float3 sphereUnormL = spherePosition - worldPos;
float3 sphereL = normalize(sphereUnormL);
float sqrSphereDistance = dot(sphereUnormL, sphereUnormL);
float fLightSphere = PI * saturate(dot(sphereL, worldNormal)) *
((_GetRadius(light) * _GetRadius(light)) / sqrSphereDistance);
fLight += fLightSphere;
fLight = max(0, fLight);
// We approximate L by the closest point on the reflection ray to the light source (representative point technique) to achieve a nice looking specular reflection
{
float3 r = reflect(V, N);
r = getSpecularDominantDirArea(N, r, roughness);
// First, the closest point to the ray on the segment
float3 L0 = P0 - P;
float3 L1 = P1 - P;
float3 Ld = L1 - L0;
float t = dot(r, L0) * dot(r, Ld) - dot(L0, Ld);
t /= dot(Ld, Ld) - sqr(dot(r, Ld));
L = (L0 + saturate(t) * Ld);
// Then I place a sphere on that point and calculate the lisght vector like for sphere light.
float3 centerToRay = dot(L, r) * r - L;
float3 closestPoint = L + centerToRay * saturate(_GetRadius(light) / length(centerToRay));
L = normalize(closestPoint);
}
float3 lightColor = light.color.rgb*light.energy;
BRDF_MAKE(N, L, V);
result.specular = lightColor * BRDF_SPECULAR(roughness, f0) * fLight;
result.diffuse = lightColor * fLight / PI;
result.diffuse = max(0.0f, result.diffuse);
result.specular = max(0.0f, result.specular);
return result;
}
#endif // _LIGHTING_HF_
+21 -1
View File
@@ -154,6 +154,26 @@ inline void TiledLighting(in float2 pixel, in float3 N, in float3 V, in float3 P
result = SpotLight(light, N, V, P, roughness, f0);
}
break;
case 3/*SPHERE*/:
{
result = SphereLight(light, N, V, P, roughness, f0);
}
break;
case 4/*DISC*/:
{
result = DiscLight(light, N, V, P, roughness, f0);
}
break;
case 5/*RECTANGLE*/:
{
result = RectangleLight(light, N, V, P, roughness, f0);
}
break;
case 6/*TUBE*/:
{
result = TubeLight(light, N, V, P, roughness, f0);
}
break;
#ifndef DISABLE_DECALS
case 100/*DECAL*/:
{
@@ -186,7 +206,7 @@ inline void TiledLighting(in float2 pixel, in float3 N, in float3 V, in float3 P
////////////
#define OBJECT_PS_MAKE_COMMON \
float3 N = input.nor; \
float3 N = normalize(input.nor); \
float3 P = input.pos3D; \
float3 V = g_xCamera_CamPos - P; \
float dist = length(V); \
+1 -1
View File
@@ -2,7 +2,7 @@
#include "wiHelper.h"
// this should always be only INCREMENTED and only if a new serialization is implemeted somewhere!
uint64_t __archiveVersion = 5;
uint64_t __archiveVersion = 6;
// this is the version number of which below the archive is not compatible with the current version
uint64_t __archiveVersionBarrier = 1;
+17
View File
@@ -3926,6 +3926,9 @@ Light::Light():Transform() {
shadowMap_index = -1;
lightArray_index = 0;
shadowBias = 0.0001f;
radius = 1.0f;
width = 1.0f;
height = 1.0f;
}
Light::~Light() {
for (string x : lensFlareNames)
@@ -4068,6 +4071,13 @@ void Light::Serialize(wiArchive& archive)
lensFlareNames.push_back(rim);
}
}
if (archive.GetVersion() >= 6)
{
archive >> radius;
archive >> width;
archive >> height;
}
}
else
{
@@ -4082,6 +4092,13 @@ void Light::Serialize(wiArchive& archive)
{
archive << wiHelper::GetFileNameFromPath(x);
}
if (archive.GetVersion() >= 6)
{
archive << radius;
archive << width;
archive << height;
}
}
}
#pragma endregion
+7
View File
@@ -749,10 +749,17 @@ struct Light : public Cullable , public Transform
float shadowBias;
// area light props:
float radius, width, height;
enum LightType{
DIRECTIONAL,
POINT,
SPOT,
SPHERE,
DISC,
RECTANGLE,
TUBE,
LIGHTTYPE_COUNT,
};
LightType type;
+12
View File
@@ -1715,6 +1715,18 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID)
lightArray[lightCounter].shadowKernel = 1.0f / SHADOWRES_CUBE;
}
break;
case Light::SPHERE:
case Light::DISC:
case Light::RECTANGLE:
case Light::TUBE:
{
XMMATRIX lightMat = XMLoadFloat4x4(&l->world);
XMStoreFloat3(&lightArray[lightCounter].directionWS, XMVector3TransformNormal(XMVectorSet(-1, 0, 0, 0), lightMat)); // left dir
XMStoreFloat3(&lightArray[lightCounter].directionVS, XMVector3TransformNormal(XMVectorSet(0, 1, 0, 0), lightMat)); // up dir
XMStoreFloat3(&lightArray[lightCounter].posVS, XMVector3TransformNormal(XMVectorSet(0, 0, -1, 0), lightMat)); // front dir
lightArray[lightCounter].texMulAdd = XMFLOAT4(l->radius, l->width, l->height, 0);
}
break;
default:
break;
}
+1 -1
View File
@@ -7,7 +7,7 @@ namespace wiVersion
// minor features, major updates
const int minor = 9;
// minor bug fixes, alterations, refactors, updates
const int revision = 53;
const int revision = 54;
long GetVersion()