New light gizmos.

This commit is contained in:
Leonardo Zide 2023-08-26 12:41:16 -07:00
parent 2f5594b5f6
commit 3942156acf
4 changed files with 526 additions and 351 deletions

View file

@ -1991,6 +1991,125 @@ inline bool lcSphereRayMinIntersectDistance(const lcVector3& Center, float Radiu
}
}
inline bool lcConeRayMinIntersectDistance(const lcVector3& Tip, const lcVector3& Direction, float Radius, float Height, const lcVector3& Start, const lcVector3& End, float* Dist)
{
const lcVector3 v = End - Start;
const lcVector3 h = Direction;
const lcVector3 w = Start - Tip;
const float vh = lcDot(v, h);
const float wh = lcDot(w, h);
const float m = (Radius * Radius) / (Height * Height);
const float a = lcDot(v, v) - m * vh * vh - vh * vh;
const float b = 2 * (lcDot(v, w) - m * vh * wh - vh * wh);
const float c = lcDot(w, w) - m * wh * wh - wh * wh;
const float delta = b * b - 4 * a * c;
if (delta < 0.0f)
return false;
float ts[2] = { (-b - sqrtf(delta)) / (2 * a), (-b + sqrtf(delta)) / (2 * a) };
for (int ti = 0; ti < 2; ti++)
{
float t = ts[ti];
lcVector3 Intersection = Start + v * t;
float ConeD = lcDot(Intersection - Tip, Direction);
if (ConeD < 0.0f)
continue;
if (ConeD < Height)
{
*Dist = lcLength(Intersection - Start);
return true;
}
lcVector3 Center(Tip + Direction * Height);
lcVector4 Plane(Direction, -lcDot(Direction, Center));
if (lcLineSegmentPlaneIntersection(&Intersection, Start, End, Plane))
{
if (lcLengthSquared(Center - Intersection) < Radius * Radius)
{
*Dist = lcLength(Intersection - Start);
return true;
}
}
}
return false;
}
inline bool lcCylinderRayMinIntersectDistance(float Radius, float Height, const lcVector3& Start, const lcVector3& End, float* Dist)
{
lcVector4 BottomPlane(0.0f, 0.0f, 1.0f, 0.0f);
lcVector3 Intersection;
float MinDistance = FLT_MAX;
if (lcLineSegmentPlaneIntersection(&Intersection, Start, End, BottomPlane))
{
if (Intersection.x * Intersection.x + Intersection.y * Intersection.y < Radius * Radius)
{
float Distance = lcLength(Intersection - Start);
if (Distance < MinDistance)
MinDistance = Distance;
}
}
lcVector4 TopPlane(0.0f, 0.0f, 1.0f, -Height);
if (lcLineSegmentPlaneIntersection(&Intersection, Start, End, TopPlane))
{
if (Intersection.x * Intersection.x + Intersection.y * Intersection.y < Radius * Radius)
{
float Distance = lcLength(Intersection - Start);
if (Distance < MinDistance)
MinDistance = Distance;
}
}
lcVector3 Direction = End - Start;
float a = (Direction.x * Direction.x) + (Direction.y * Direction.y);
float b = 2 * (Direction.x * Start.x + Direction.y * Start.y);
float c = (Start.x * Start.x) + (Start.y * Start.y) - (Radius * Radius);
float delta = b * b - 4 * (a * c);
if (delta > 0.0f)
{
float ts[2] = { (-b - sqrtf(delta)) / (2 * a), (-b + sqrtf(delta)) / (2 * a) };
for (int ti = 0; ti < 2; ti++)
{
float t = ts[ti];
Intersection = Start + Direction * t;
if (Intersection.z < 0.0f || Intersection.z > Height)
continue;
float Distance = lcLength(Intersection - Start);
if (Distance < MinDistance)
MinDistance = Distance;
}
}
if (MinDistance == FLT_MAX)
return false;
*Dist = MinDistance;
return true;
}
inline lcVector3 lcRayPointClosestPoint(const lcVector3& Point, const lcVector3& Start, const lcVector3& End)
{
const lcVector3 Dir = Point - Start;

View file

@ -8,11 +8,14 @@
#include "lc_application.h"
#include "lc_context.h"
#define LC_LIGHT_POSITION_EDGE 7.5f
#define LC_LIGHT_TARGET_EDGE 5.0f
#define LC_LIGHT_SPHERE_RADIUS 5.0f
#define LC_LIGHT_SUN_RADIUS 8.5f
#define LC_LIGHT_SPOT_BASE_EDGE 12.5f
#define LC_LIGHT_TARGET_EDGE 5.0f
#define LC_LIGHT_SPOT_CONE_HEIGHT 10.0f
#define LC_LIGHT_SPOT_CONE_RADIUS 7.5f
#define LC_LIGHT_DIRECTIONAL_RADIUS 5.0f
#define LC_LIGHT_DIRECTIONAL_HEIGHT 7.5f
#define LC_LIGHT_POSITION_EDGE 7.5f
static const std::array<QLatin1String, 4> gLightTypes = { QLatin1String("POINT"), QLatin1String("SPOT"), QLatin1String("DIRECTIONAL"), QLatin1String("AREA") };
@ -597,7 +600,7 @@ void lcLight::RayTest(lcObjectRayTest& ObjectRayTest) const
{
float Distance;
if (lcSphereRayMinIntersectDistance(mPosition, LC_LIGHT_SPHERE_RADIUS, ObjectRayTest.Start, ObjectRayTest.End, &Distance))
if (lcSphereRayMinIntersectDistance(mPosition, LC_LIGHT_SPHERE_RADIUS, ObjectRayTest.Start, ObjectRayTest.End, &Distance) && (Distance < ObjectRayTest.Distance))
{
ObjectRayTest.ObjectSection.Object = const_cast<lcLight*>(this);
ObjectRayTest.ObjectSection.Section = LC_LIGHT_SECTION_POSITION;
@ -607,8 +610,63 @@ void lcLight::RayTest(lcObjectRayTest& ObjectRayTest) const
return;
}
lcVector3 Min = lcVector3(-LC_LIGHT_POSITION_EDGE, -LC_LIGHT_POSITION_EDGE, -LC_LIGHT_POSITION_EDGE);
lcVector3 Max = lcVector3(LC_LIGHT_POSITION_EDGE, LC_LIGHT_POSITION_EDGE, LC_LIGHT_POSITION_EDGE);
if (mLightType == lcLightType::Spot)
{
float Distance;
lcVector3 Direction = lcNormalize(mTargetPosition - mPosition);
if (lcConeRayMinIntersectDistance(mPosition - Direction * LC_LIGHT_SPOT_CONE_HEIGHT, Direction, LC_LIGHT_SPOT_CONE_RADIUS, LC_LIGHT_SPOT_CONE_HEIGHT, ObjectRayTest.Start, ObjectRayTest.End, &Distance) && (Distance < ObjectRayTest.Distance))
{
ObjectRayTest.ObjectSection.Object = const_cast<lcLight*>(this);
ObjectRayTest.ObjectSection.Section = LC_LIGHT_SECTION_POSITION;
ObjectRayTest.Distance = Distance;
}
}
else if (mLightType == lcLightType::Area)
{
lcVector3 FrontVector = mTargetPosition - mPosition;
lcVector4 Plane(FrontVector, -lcDot(FrontVector, mPosition));
lcVector3 Intersection;
if (lcLineSegmentPlaneIntersection(&Intersection, ObjectRayTest.Start, ObjectRayTest.End, Plane))
{
lcVector3 UpVector(1, 1, 1);
if (fabs(FrontVector[0]) < fabs(FrontVector[1]))
{
if (fabs(FrontVector[0]) < fabs(FrontVector[2]))
UpVector[0] = -(UpVector[1] * FrontVector[1] + UpVector[2] * FrontVector[2]);
else
UpVector[2] = -(UpVector[0] * FrontVector[0] + UpVector[1] * FrontVector[1]);
}
else
{
if (fabs(FrontVector[1]) < fabs(FrontVector[2]))
UpVector[1] = -(UpVector[0] * FrontVector[0] + UpVector[2] * FrontVector[2]);
else
UpVector[2] = -(UpVector[0] * FrontVector[0] + UpVector[1] * FrontVector[1]);
}
lcVector3 XAxis = lcNormalize(lcCross(FrontVector, UpVector));
lcVector3 YAxis = lcNormalize(lcCross(FrontVector, XAxis));
lcVector3 IntersectionDirection = Intersection - mPosition;
float x = lcDot(IntersectionDirection, XAxis);
float y = lcDot(IntersectionDirection, YAxis);
if (fabsf(x) < mAreaSize.x / 2.0f && fabsf(y) < mAreaSize.y / 2.0f)
{
float Distance = lcLength(Intersection - ObjectRayTest.Start);
if (Distance < ObjectRayTest.Distance)
{
ObjectRayTest.ObjectSection.Object = const_cast<lcLight*>(this);
ObjectRayTest.ObjectSection.Section = LC_LIGHT_SECTION_POSITION;
ObjectRayTest.Distance = Distance;
}
}
}
}
lcVector3 Start = lcMul31(ObjectRayTest.Start, mWorldLight);
lcVector3 End = lcMul31(ObjectRayTest.End, mWorldLight);
@ -616,16 +674,19 @@ void lcLight::RayTest(lcObjectRayTest& ObjectRayTest) const
float Distance;
lcVector3 Plane;
if (lcBoundingBoxRayIntersectDistance(Min, Max, Start, End, &Distance, nullptr, &Plane) && (Distance < ObjectRayTest.Distance))
if (mLightType == lcLightType::Directional)
{
ObjectRayTest.ObjectSection.Object = const_cast<lcLight*>(this);
ObjectRayTest.ObjectSection.Section = LC_LIGHT_SECTION_POSITION;
ObjectRayTest.Distance = Distance;
ObjectRayTest.PieceInfoRayTest.Plane = Plane;
if (lcCylinderRayMinIntersectDistance(LC_LIGHT_DIRECTIONAL_RADIUS, LC_LIGHT_DIRECTIONAL_HEIGHT, Start, End, &Distance) && (Distance < ObjectRayTest.Distance))
{
ObjectRayTest.ObjectSection.Object = const_cast<lcLight*>(this);
ObjectRayTest.ObjectSection.Section = LC_LIGHT_SECTION_POSITION;
ObjectRayTest.Distance = Distance;
ObjectRayTest.PieceInfoRayTest.Plane = Plane;
}
}
Min = lcVector3(-LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE);
Max = lcVector3(LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE);
lcVector3 Min = lcVector3(-LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE);
lcVector3 Max = lcVector3( LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE);
lcMatrix44 WorldTarget = mWorldLight;
WorldTarget.SetTranslation(lcMul30(-mTargetPosition, WorldTarget));
@ -654,7 +715,7 @@ void lcLight::BoxTest(lcObjectBoxTest& ObjectBoxTest) const
return;
}
lcVector3 Min(-LC_LIGHT_POSITION_EDGE, -LC_LIGHT_POSITION_EDGE, -LC_LIGHT_POSITION_EDGE);
lcVector3 Min(-LC_LIGHT_POSITION_EDGE, -LC_LIGHT_POSITION_EDGE, -LC_LIGHT_POSITION_EDGE); // todo: fix light box test
lcVector3 Max(LC_LIGHT_POSITION_EDGE, LC_LIGHT_POSITION_EDGE, LC_LIGHT_POSITION_EDGE);
lcVector4 LocalPlanes[6];
@ -798,13 +859,175 @@ void lcLight::DrawInterface(lcContext* Context, const lcScene& Scene) const
Q_UNUSED(Scene);
Context->SetMaterial(lcMaterialType::UnlitColor);
if (IsPointLight())
switch (mLightType)
{
case lcLightType::Point:
DrawPointLight(Context);
else
break;
case lcLightType::Spot:
DrawSpotLight(Context);
break;
case lcLightType::Directional:
DrawDirectionalLight(Context);
break;
case lcLightType::Area:
DrawAreaLight(Context);
break;
}
}
void lcLight::DrawPointLight(lcContext* Context) const
{
Context->SetWorldMatrix(lcMatrix44Translation(mPosition));
const lcPreferences& Preferences = lcGetPreferences();
if (IsFocused(LC_LIGHT_SECTION_POSITION))
{
const lcVector4 FocusedColor = lcVector4FromColor(Preferences.mObjectFocusedColor);
Context->SetColor(FocusedColor);
}
else if (IsSelected(LC_LIGHT_SECTION_POSITION))
{
const lcVector4 SelectedColor = lcVector4FromColor(Preferences.mObjectSelectedColor);
Context->SetColor(SelectedColor);
}
else
{
const lcVector4 LightColor = lcVector4FromColor(Preferences.mLightColor);
Context->SetColor(LightColor);
}
DrawSphere(Context, LC_LIGHT_SPHERE_RADIUS);
}
void lcLight::DrawSpotLight(lcContext* Context) const
{
constexpr int ConeEdges = 8;
float TargetDistance = SetupLightMatrix(Context);
float Verts[(ConeEdges + 1) * 3];
float* CurVert = Verts;
for (int EdgeIndex = 0; EdgeIndex < ConeEdges; EdgeIndex++)
{
float c = cosf((float)EdgeIndex / ConeEdges * LC_2PI) * LC_LIGHT_SPOT_CONE_RADIUS;
float s = sinf((float)EdgeIndex / ConeEdges * LC_2PI) * LC_LIGHT_SPOT_CONE_RADIUS;
*CurVert++ = c;
*CurVert++ = s;
*CurVert++ = 0.0f;
}
*CurVert++ = 0.0f;
*CurVert++ = 0.0f;
*CurVert++ = LC_LIGHT_SPOT_CONE_HEIGHT;
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
const GLushort Indices[(ConeEdges + 4) * 2] =
{
0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 0,
0, 8, 2, 8, 4, 8, 6, 8,
};
Context->SetIndexBufferPointer(Indices);
Context->DrawIndexedPrimitives(GL_LINES, (ConeEdges + 4) * 2, GL_UNSIGNED_SHORT, 0);
DrawTarget(Context, TargetDistance);
if (IsSelected())
DrawCone(Context, TargetDistance);
}
void lcLight::DrawDirectionalLight(lcContext* Context) const
{
float TargetDistance = SetupLightMatrix(Context);
DrawCylinder(Context, LC_LIGHT_DIRECTIONAL_RADIUS, LC_LIGHT_DIRECTIONAL_HEIGHT);
DrawTarget(Context, TargetDistance);
}
void lcLight::DrawAreaLight(lcContext* Context) const
{
float TargetDistance = SetupLightMatrix(Context);
if (mLightShape == LC_LIGHT_SHAPE_SQUARE || mLightShape == LC_LIGHT_SHAPE_RECTANGLE)
{
float Verts[4 * 3];
float* CurVert = Verts;
*CurVert++ = -mAreaSize.x / 2.0f;
*CurVert++ = -mAreaSize.y / 2.0f;
*CurVert++ = 0.0f;
*CurVert++ = mAreaSize.x / 2.0f;
*CurVert++ = -mAreaSize.y / 2.0f;
*CurVert++ = 0.0f;
*CurVert++ = mAreaSize.x / 2.0f;
*CurVert++ = mAreaSize.y / 2.0f;
*CurVert++ = 0.0f;
*CurVert++ = -mAreaSize.x / 2.0f;
*CurVert++ = mAreaSize.y / 2.0f;
*CurVert++ = 0.0f;
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
const GLushort Indices[(4 + 2) * 2] =
{
0, 1, 1, 2, 2, 3, 3, 0,
0, 2, 1, 3,
};
Context->SetIndexBufferPointer(Indices);
Context->DrawIndexedPrimitives(GL_LINES, (4 + 2) * 2, GL_UNSIGNED_SHORT, 0);
}
else
{
constexpr int CircleEdges = 16;
float Verts[CircleEdges * 3];
float* CurVert = Verts;
for (int EdgeIndex = 0; EdgeIndex < CircleEdges; EdgeIndex++)
{
float c = cosf((float)EdgeIndex / CircleEdges * LC_2PI) * mAreaSize.x / 2.0f;
float s = sinf((float)EdgeIndex / CircleEdges * LC_2PI) * mAreaSize.y / 2.0f;
*CurVert++ = c;
*CurVert++ = s;
*CurVert++ = 0.0f;
}
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
const GLushort Indices[(CircleEdges + 2) * 2] =
{
0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 0,
0, 8, 4, 12
};
Context->SetIndexBufferPointer(Indices);
Context->DrawIndexedPrimitives(GL_LINES, (CircleEdges + 2) * 2, GL_UNSIGNED_SHORT, 0);
}
DrawTarget(Context, TargetDistance);
}
float lcLight::SetupLightMatrix(lcContext* Context) const
{
lcVector3 FrontVector(mTargetPosition - mPosition);
lcVector3 UpVector(1, 1, 1);
@ -831,324 +1054,37 @@ void lcLight::DrawDirectionalLight(lcContext* Context) const
const lcMatrix44 LightViewMatrix = lcMul(LightMatrix, lcMatrix44Translation(mPosition));
Context->SetWorldMatrix(LightViewMatrix);
float Length = FrontVector.Length();
float Verts[(20 + 8 + 2 + 16) * 3];
float* CurVert = Verts;
if (mLightType != lcLightType::Directional)
{
if (mLightType == lcLightType::Spot)
{
for (int EdgeIdx = 0; EdgeIdx < 8; EdgeIdx++)
{
float c = cosf((float)EdgeIdx / 4 * LC_PI) * LC_LIGHT_POSITION_EDGE;
float s = sinf((float)EdgeIdx / 4 * LC_PI) * LC_LIGHT_POSITION_EDGE;
*CurVert++ = c;
*CurVert++ = s;
*CurVert++ = LC_LIGHT_POSITION_EDGE;
*CurVert++ = c;
*CurVert++ = s;
*CurVert++ = -LC_LIGHT_POSITION_EDGE;
}
*CurVert++ = -LC_LIGHT_SPOT_BASE_EDGE; *CurVert++ = -LC_LIGHT_SPOT_BASE_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
*CurVert++ = LC_LIGHT_SPOT_BASE_EDGE; *CurVert++ = -LC_LIGHT_SPOT_BASE_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
*CurVert++ = LC_LIGHT_SPOT_BASE_EDGE; *CurVert++ = LC_LIGHT_SPOT_BASE_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
*CurVert++ = -LC_LIGHT_SPOT_BASE_EDGE; *CurVert++ = LC_LIGHT_SPOT_BASE_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
}
else if (mLightType == lcLightType::Area)
{
const float LC_LIGHT_AREA_EDGE = 5.0f;
const float LC_LIGHT_AREA_H_EDGE = 8.5f;
const float LC_LIGHT_AREA_W_EDGE = 17.0f;
*CurVert++ = LC_LIGHT_AREA_EDGE; *CurVert++ = LC_LIGHT_AREA_EDGE; *CurVert++ = LC_LIGHT_POSITION_EDGE;
*CurVert++ = -LC_LIGHT_AREA_EDGE; *CurVert++ = LC_LIGHT_AREA_EDGE; *CurVert++ = LC_LIGHT_POSITION_EDGE;
*CurVert++ = -LC_LIGHT_AREA_EDGE; *CurVert++ = -LC_LIGHT_AREA_EDGE; *CurVert++ = LC_LIGHT_POSITION_EDGE;
*CurVert++ = LC_LIGHT_AREA_EDGE; *CurVert++ = -LC_LIGHT_AREA_EDGE; *CurVert++ = LC_LIGHT_POSITION_EDGE;
*CurVert++ = LC_LIGHT_AREA_EDGE; *CurVert++ = LC_LIGHT_AREA_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
*CurVert++ = -LC_LIGHT_AREA_EDGE; *CurVert++ = LC_LIGHT_AREA_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
*CurVert++ = -LC_LIGHT_AREA_EDGE; *CurVert++ = -LC_LIGHT_AREA_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
*CurVert++ = LC_LIGHT_AREA_EDGE; *CurVert++ = -LC_LIGHT_AREA_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
*CurVert++ = -LC_LIGHT_AREA_H_EDGE; *CurVert++ = -LC_LIGHT_AREA_W_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
*CurVert++ = LC_LIGHT_AREA_H_EDGE; *CurVert++ = -LC_LIGHT_AREA_W_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
*CurVert++ = LC_LIGHT_AREA_H_EDGE; *CurVert++ = LC_LIGHT_AREA_W_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
*CurVert++ = -LC_LIGHT_AREA_H_EDGE; *CurVert++ = LC_LIGHT_AREA_W_EDGE; *CurVert++ = -LC_LIGHT_POSITION_EDGE;
}
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - Length;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - Length;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - Length;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - Length;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - Length;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - Length;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - Length;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - Length;
*CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = 0.0f;
*CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = -Length;
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
}
int BaseIndices = 0;
if (mLightType == lcLightType::Spot)
{
BaseIndices = 56;
const GLushort Indices[56 + 24 + 2 + 40] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14, 0,
1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15, 1,
16, 17, 17, 18, 18, 19, 19, 16,
20, 21, 21, 22, 22, 23, 23, 20,
24, 25, 25, 26, 26, 27, 27, 24,
20, 24, 21, 25, 22, 26, 23, 27,
28, 29,
30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38,
38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 30,
28, 30, 28, 34, 28, 38, 28, 42
};
Context->SetIndexBufferPointer(Indices);
}
else if (mLightType == lcLightType::Area)
{
BaseIndices = 32;
const GLushort Indices[32 + 24 + 2] =
{
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7,
8, 9, 9, 10, 10, 11, 11, 8,
12, 13, 13, 14, 14, 15, 15, 12,
16, 17, 17, 18, 18, 19, 19, 16,
12, 16, 13, 17, 14, 18, 15, 19,
20, 21
};
Context->SetIndexBufferPointer(Indices);
}
else if (mLightType == lcLightType::Directional)
{
constexpr float Radius = LC_LIGHT_SUN_RADIUS;
constexpr int Slices = 9; // longitude
constexpr int Stacks = 9; // latitude
constexpr int NumSphereVertices = 918; // Slices * 2 * 3 * 3 + (Stacks - 2) * Slices * 4 * 3
constexpr int NumSphereIndices = 306; // Slices * 2 + (Stacks - 1) * Slices * 2 * 2
BaseIndices = NumSphereIndices;
float Vertices[NumSphereVertices + 24 + 6];
float *Vert = Vertices;
quint16 Indices[NumSphereIndices + 24 + 2];
quint16 *Indx = Indices;
auto AddVertex = [&](float x, float y, float z)
{
*Vert++ = x;
*Vert++ = y;
*Vert++ = z;
};
auto AddLineIndex = [&](quint16 v1, quint16 v2)
{
*Indx++ = v1;
*Indx++ = v2;
};
std::vector<lcVector3> WrkVertices;
float Slice = LC_2PI / Slices;
float Stack = LC_PI / Stacks;
float SliceAngle, StackAngle;
for(int i = 0; i <= Stacks; ++i)
{
StackAngle = LC_PI / 2 - i * Stack; // starting from pi/2 to -pi/2
float xy = Radius * cosf(StackAngle);
float z = Radius * sinf(StackAngle);
for(int j = 0; j <= Slices; ++j) // add (Slices+1) vertices per stack
{
SliceAngle = j * Slice;
lcVector3 Vertex;
Vertex.x = xy * cosf(SliceAngle);
Vertex.y = xy * sinf(SliceAngle);
Vertex.z = z;
WrkVertices.push_back(Vertex);
}
}
int Index = 0;
lcVector3 v1, v2, v3, v4;
for(int i = 0; i < Stacks; ++i)
{
int vi1 = i * (Slices + 1);
int vi2 = (i + 1) * (Slices + 1);
for(int j = 0; j < Slices; ++j, ++vi1, ++vi2)
{
// 4 vertices per slice
// v1--v3
// | |
// v2--v4
v1 = WrkVertices[vi1];
v2 = WrkVertices[vi2];
v3 = WrkVertices[vi1 + 1];
v4 = WrkVertices[vi2 + 1];
// if first stack or last stack, store 1 triangle per slice else, store 2 triangles (1 quad) per slice
if(i == 0)
{
// first stack triangle v1-v2-v4
AddVertex(v1.x, v1.y, v1.z);
AddVertex(v2.x, v2.y, v2.z);
AddVertex(v4.x, v4.y, v4.z);
// only vertical lines for first stack)
AddLineIndex(Index, Index+1);
Index += 3;
}
else if(i == (Stacks-1))
{
// last stack inverted triangle v1-v2-v3
AddVertex(v1.x, v1.y, v1.z);
AddVertex(v2.x, v2.y, v2.z);
AddVertex(v3.x, v3.y, v3.z);
// both vertical and horizontal lines for last stack
AddLineIndex(Index, Index+1);
AddLineIndex(Index, Index+2);
Index += 3;
}
else
{
// 2 triangles (quad vertices v1-v2-v3-v4) for other stacks
AddVertex(v1.x, v1.y, v1.z);
AddVertex(v2.x, v2.y, v2.z);
AddVertex(v3.x, v3.y, v3.z);
AddVertex(v4.x, v4.y, v4.z);
// both vertical and horizontal lines for other stacks
AddLineIndex(Index, Index+1);
AddLineIndex(Index, Index+2);
Index += 4;
}
}
}
AddVertex( LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE - Length);
AddVertex(-LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE - Length);
AddVertex(-LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE - Length);
AddVertex( LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE - Length);
AddVertex( LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE - Length);
AddVertex(-LC_LIGHT_TARGET_EDGE, LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE - Length);
AddVertex(-LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE - Length);
AddVertex( LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE, -LC_LIGHT_TARGET_EDGE - Length);
AddVertex(0.0f, 0.0f, 0.0f);
AddVertex(0.0f, 0.0f, -Length);
const int Idx[10] = { Index++, Index++, Index++, Index++, Index++, Index++, Index++, Index++, Index++, Index++ };
AddLineIndex(Idx[0], Idx[1]); AddLineIndex(Idx[1], Idx[2]); AddLineIndex(Idx[2], Idx[3]); AddLineIndex(Idx[3], Idx[0]);
AddLineIndex(Idx[4], Idx[5]); AddLineIndex(Idx[5], Idx[6]); AddLineIndex(Idx[6], Idx[7]); AddLineIndex(Idx[7], Idx[4]);
AddLineIndex(Idx[0], Idx[4]); AddLineIndex(Idx[1], Idx[5]); AddLineIndex(Idx[2], Idx[6]); AddLineIndex(Idx[3], Idx[7]);
AddLineIndex(Idx[8], Idx[9]);
Context->SetVertexBufferPointer(Vertices);
Context->SetVertexFormatPosition(3);
Context->SetIndexBufferPointer(Indices);
}
const lcPreferences& Preferences = lcGetPreferences();
const float LineWidth = Preferences.mLineWidth;
const lcVector4 SelectedColor = lcVector4FromColor(Preferences.mObjectSelectedColor);
const lcVector4 FocusedColor = lcVector4FromColor(Preferences.mObjectFocusedColor);
const lcVector4 LightColor = lcVector4FromColor(Preferences.mLightColor);
if (!IsSelected())
if (IsSelected(LC_LIGHT_SECTION_POSITION))
{
Context->SetLineWidth(LineWidth);
Context->SetColor(LightColor);
const lcVector4 SelectedColor = lcVector4FromColor(Preferences.mObjectSelectedColor);
const lcVector4 FocusedColor = lcVector4FromColor(Preferences.mObjectFocusedColor);
Context->DrawIndexedPrimitives(GL_LINES, BaseIndices + 24 + 2, GL_UNSIGNED_SHORT, 0);
Context->SetLineWidth(2.0f * LineWidth);
if (IsFocused(LC_LIGHT_SECTION_POSITION))
Context->SetColor(FocusedColor);
else
Context->SetColor(SelectedColor);
}
else
{
if (IsSelected(LC_LIGHT_SECTION_POSITION))
{
Context->SetLineWidth(2.0f * LineWidth);
if (IsFocused(LC_LIGHT_SECTION_POSITION))
Context->SetColor(FocusedColor);
else
Context->SetColor(SelectedColor);
}
else
{
Context->SetLineWidth(LineWidth);
Context->SetColor(LightColor);
}
Context->DrawIndexedPrimitives(GL_LINES, BaseIndices, GL_UNSIGNED_SHORT, 0);
if (IsSelected(LC_LIGHT_SECTION_TARGET))
{
Context->SetLineWidth(2.0f * LineWidth);
if (IsFocused(LC_LIGHT_SECTION_TARGET))
Context->SetColor(FocusedColor);
else
Context->SetColor(SelectedColor);
}
else
{
Context->SetLineWidth(LineWidth);
Context->SetColor(LightColor);
}
Context->DrawIndexedPrimitives(GL_LINES, 24, GL_UNSIGNED_SHORT, BaseIndices * 2);
const lcVector4 LightColor = lcVector4FromColor(Preferences.mLightColor);
Context->SetLineWidth(LineWidth);
Context->SetColor(LightColor);
int SpotCone = 0;
if (mLightType == lcLightType::Spot)
{
SpotCone = 40;
float Radius = tanf(LC_DTOR * mSpotCutoff) * Length;
for (int EdgeIdx = 0; EdgeIdx < 16; EdgeIdx++)
{
*CurVert++ = cosf((float)EdgeIdx / 16 * LC_2PI) * Radius;
*CurVert++ = sinf((float)EdgeIdx / 16 * LC_2PI) * Radius;
*CurVert++ = -Length;
}
}
Context->DrawIndexedPrimitives(GL_LINES, 2 + SpotCone, GL_UNSIGNED_SHORT, (BaseIndices + 24) * 2);
}
return FrontVector.Length();
}
void lcLight::DrawPointLight(lcContext* Context) const
void lcLight::DrawSphere(lcContext* Context, float Radius) const
{
constexpr int Slices = 6;
constexpr int NumIndices = 3 * Slices + 6 * Slices * (Slices - 2) + 3 * Slices;
constexpr int NumVertices = (Slices - 1) * Slices + 2;
constexpr float Radius = LC_LIGHT_SPHERE_RADIUS;
lcVector3 Vertices[NumVertices];
quint16 Indices[NumIndices];
@ -1157,7 +1093,7 @@ void lcLight::DrawPointLight(lcContext* Context) const
*Vertex++ = lcVector3(0, 0, Radius);
for (int i = 1; i < Slices; i++ )
for (int i = 1; i < Slices; i++)
{
const float r0 = Radius * sinf(i * (LC_PI / Slices));
const float z0 = Radius * cosf(i * (LC_PI / Slices));
@ -1173,7 +1109,7 @@ void lcLight::DrawPointLight(lcContext* Context) const
*Vertex++ = lcVector3(0, 0, -Radius);
for (quint16 i = 0; i < Slices - 1; i++ )
for (quint16 i = 0; i < Slices - 1; i++)
{
*Index++ = 0;
*Index++ = 1 + i;
@ -1184,12 +1120,12 @@ void lcLight::DrawPointLight(lcContext* Context) const
*Index++ = 1;
*Index++ = 1 + Slices - 1;
for (quint16 i = 0; i < Slices - 2; i++ )
for (quint16 i = 0; i < Slices - 2; i++)
{
quint16 Row1 = 1 + i * Slices;
quint16 Row2 = 1 + (i + 1) * Slices;
for (quint16 j = 0; j < Slices - 1; j++ )
for (quint16 j = 0; j < Slices - 1; j++)
{
*Index++ = Row1 + j;
*Index++ = Row2 + j + 1;
@ -1209,7 +1145,7 @@ void lcLight::DrawPointLight(lcContext* Context) const
*Index++ = Row1 + 0;
}
for (quint16 i = 0; i < Slices - 1; i++ )
for (quint16 i = 0; i < Slices - 1; i++)
{
*Index++ = (Slices - 1) * Slices + 1;
*Index++ = (Slices - 1) * (Slices - 1) + i;
@ -1220,32 +1156,144 @@ void lcLight::DrawPointLight(lcContext* Context) const
*Index++ = (Slices - 1) * (Slices - 1) + (Slices - 2) + 1;
*Index++ = (Slices - 1) * (Slices - 1);
Context->SetWorldMatrix(lcMatrix44Translation(mPosition));
const lcPreferences& Preferences = lcGetPreferences();
if (IsFocused(LC_LIGHT_SECTION_POSITION))
{
const lcVector4 FocusedColor = lcVector4FromColor(Preferences.mObjectFocusedColor);
Context->SetColor(FocusedColor);
}
else if (IsSelected(LC_LIGHT_SECTION_POSITION))
{
const lcVector4 SelectedColor = lcVector4FromColor(Preferences.mObjectSelectedColor);
Context->SetColor(SelectedColor);
}
else
{
const lcVector4 LightColor = lcVector4FromColor(Preferences.mLightColor);
Context->SetColor(LightColor);
}
Context->SetVertexBufferPointer(Vertices);
Context->SetVertexFormatPosition(3);
Context->SetIndexBufferPointer(Indices);
Context->DrawIndexedPrimitives(GL_TRIANGLES, NumIndices, GL_UNSIGNED_SHORT, 0);
}
void lcLight::DrawCylinder(lcContext* Context, float Radius, float Height) const
{
constexpr int Slices = 8;
float Verts[(Slices * 2) * 3];
float* CurVert = Verts;
for (int EdgeIndex = 0; EdgeIndex < Slices; EdgeIndex++)
{
float c = cosf((float)EdgeIndex / Slices * LC_2PI) * Radius;
float s = sinf((float)EdgeIndex / Slices * LC_2PI) * Radius;
*CurVert++ = c;
*CurVert++ = s;
*CurVert++ = Height;
*CurVert++ = c;
*CurVert++ = s;
*CurVert++ = 0.0f;
}
const GLushort Indices[48] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14, 0,
1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15, 1,
};
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
Context->SetIndexBufferPointer(Indices);
Context->DrawIndexedPrimitives(GL_LINES, 48, GL_UNSIGNED_SHORT, 0);
}
void lcLight::DrawTarget(lcContext* Context, float TargetDistance) const
{
float Verts[10 * 3];
float* CurVert = Verts;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE; *CurVert++ = -LC_LIGHT_TARGET_EDGE - TargetDistance;
*CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = 0.0f;
*CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = -TargetDistance;
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
const GLushort Indices[(12 + 1) * 2] =
{
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7,
8, 9
};
Context->SetIndexBufferPointer(Indices);
const lcPreferences& Preferences = lcGetPreferences();
const float LineWidth = Preferences.mLineWidth;
const lcVector4 LightColor = lcVector4FromColor(Preferences.mLightColor);
if (IsSelected(LC_LIGHT_SECTION_TARGET))
{
const lcVector4 SelectedColor = lcVector4FromColor(Preferences.mObjectSelectedColor);
const lcVector4 FocusedColor = lcVector4FromColor(Preferences.mObjectFocusedColor);
Context->SetLineWidth(2.0f * LineWidth);
if (IsFocused(LC_LIGHT_SECTION_TARGET))
Context->SetColor(FocusedColor);
else
Context->SetColor(SelectedColor);
}
else
{
Context->SetLineWidth(LineWidth);
Context->SetColor(LightColor);
}
Context->DrawIndexedPrimitives(GL_LINES, 12 * 2, GL_UNSIGNED_SHORT, 0);
Context->SetLineWidth(LineWidth);
Context->SetColor(LightColor);
Context->DrawIndexedPrimitives(GL_LINES, 2, GL_UNSIGNED_SHORT, 12 * 2 * 2);
}
void lcLight::DrawCone(lcContext* Context, float TargetDistance) const
{
constexpr int ConeEdges = 16;
const float Radius = tanf(LC_DTOR * mSpotCutoff) * TargetDistance;
float Verts[(ConeEdges + 1) * 3];
float* CurVert = Verts;
for (int EdgeIndex = 0; EdgeIndex < ConeEdges; EdgeIndex++)
{
float c = cosf((float)EdgeIndex / ConeEdges * LC_2PI) * Radius;
float s = sinf((float)EdgeIndex / ConeEdges * LC_2PI) * Radius;
*CurVert++ = c;
*CurVert++ = s;
*CurVert++ = -TargetDistance;
}
*CurVert++ = 0.0f;
*CurVert++ = 0.0f;
*CurVert++ = 0.0f;
Context->SetVertexBufferPointer(Verts);
Context->SetVertexFormatPosition(3);
const GLushort Indices[(ConeEdges + 4) * 2] =
{
0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 0,
16, 0, 16, 4, 16, 8, 16, 12
};
Context->SetIndexBufferPointer(Indices);
Context->DrawIndexedPrimitives(GL_LINES, (ConeEdges + 4) * 2, GL_UNSIGNED_SHORT, 0);
}
void lcLight::RemoveKeyFrames()
{
mPositionKeys.RemoveAll();

View file

@ -331,8 +331,16 @@ protected:
lcObjectKeyArray<float> mSpotExponentKeys;
lcObjectKeyArray<float> mSpotTightnessKeys;
void DrawDirectionalLight(lcContext* Context) const;
void DrawPointLight(lcContext* Context) const;
void DrawSpotLight(lcContext* Context) const;
void DrawDirectionalLight(lcContext* Context) const;
void DrawAreaLight(lcContext* Context) const;
float SetupLightMatrix(lcContext* Context) const;
void DrawSphere(lcContext* Context, float Radius) const;
void DrawCylinder(lcContext* Context, float Radius, float Height) const;
void DrawTarget(lcContext* Context, float TargetDistance) const;
void DrawCone(lcContext* Context, float TargetDistance) const;
quint32 mState;
lcLightType mLightType;

View file

@ -983,7 +983,7 @@ void lcQPropertiesTree::slotReturnPressed()
{
QString Value = Editor->text();
Model->SetLightName(Light, Value.toLocal8Bit().data());
Model->SetLightName(Light, Value);
}
}
}
@ -1513,14 +1513,14 @@ void lcQPropertiesTree::SetLight(lcObject* Focus)
{
Factor = Light->mAreaSize;
FactorALabel = tr("Width");
FactorAToolTip = tr("The width (X direction) of the area light in units.");
FactorBToolTip = tr("The height (Y direction) of the area light in units.");
FactorAToolTip = tr("The width (X direction) of the area light.");
FactorBToolTip = tr("The height (Y direction) of the area light.");
}
else
{
FactorALabel = tr("Width (m)");
FactorAToolTip = tr("The width (X direction) of the area light in metres.");
FactorBToolTip = tr("The height (Y direction) of the area light in units.");
FactorALabel = tr("Width");
FactorAToolTip = tr("The width (X direction) of the area light.");
FactorBToolTip = tr("The height (Y direction) of the area light.");
}
break;
default:
@ -1623,7 +1623,7 @@ void lcQPropertiesTree::SetLight(lcObject* Focus)
lightSpotTightness = addProperty(lightProperties, tr("Spot Tightness"), PropertyFloat);
}
}
else if (LightType == lcLightType::Area)
else if (LightType == lcLightType::Area)
{
lightShape = addProperty(lightProperties, tr("Shape"), PropertyLightShape);
lightFactorA = addProperty(lightProperties, FactorALabel, PropertyFloat);
@ -1631,7 +1631,7 @@ void lcQPropertiesTree::SetLight(lcObject* Focus)
if (ShapeIndex == LC_LIGHT_SHAPE_RECTANGLE || ShapeIndex == LC_LIGHT_SHAPE_ELLIPSE || POVRayLight)
lightFactorB = addProperty(lightProperties, tr("Height"), PropertyFloat);
else
FactorAToolTip = tr("The size of the area light grid in metres.");
FactorAToolTip = tr("The size of the area light grid.");
if (POVRayLight)
{