Skip to content

Commit f7c29c8

Browse files
committed
Draw the round endpoints and the line body at the same time.
1 parent 1e89e6f commit f7c29c8

File tree

7 files changed

+157
-21
lines changed

7 files changed

+157
-21
lines changed

src/apps/ch10_area_lights/ch10_area_lights/Scene.cpp

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ void validateVertexAttributes(const renderer::IntrospectProgram & aProgram)
8282
}
8383

8484

85+
const unsigned int gCircleResolution = 32;
8586
const std::filesystem::path gProgramPath = "programs/ch10_area_lights_TessellateSphere.prog";
8687
//const std::filesystem::path gProgramPath = "programs/WrapLighting.prog";
8788
const std::filesystem::path gLightProgramPath = "programs/TessSphere_PlainColor.prog";
@@ -105,6 +106,20 @@ void describe(T_witness aWitness, Scene::TessellationControl & aValue)
105106
aValue.mInnerLevel = math::min(aValue.mInnerLevel, maxTess.xy());
106107
}
107108

109+
LineDrawer::LineDrawer(renderer::IntrospectProgram aLineProgram) :
110+
mProgram{std::move(aLineProgram)}
111+
{
112+
auto vertices = renderer::makeRoundSegment(gCircleResolution);
113+
auto verticesSpan = std::span{vertices};
114+
mVerticesCount = vertices.size();
115+
glBindBuffer(mVertices.GLTarget_v, mVertices);
116+
glBufferData(mVertices.GLTarget_v, verticesSpan.size_bytes(), verticesSpan.data(), GL_STATIC_DRAW);
117+
118+
glBindVertexArray(mVao);
119+
glEnableVertexAttribArray(0);
120+
glBindBuffer(mVertices.GLTarget_v, mVertices);
121+
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
122+
}
108123

109124
Scene::Scene(graphics::AppInterface & aAppInterface, const imguiui::ImguiUi & aImgui) :
110125
mVertexSpecification{},
@@ -115,7 +130,7 @@ Scene::Scene(graphics::AppInterface & aAppInterface, const imguiui::ImguiUi & aI
115130
graphics::BufferHint::StaticDraw)},
116131
mSurfaceProgram{mEngine.loadProgram(renderer::ReferencePath{gProgramPath})},
117132
mLightProgram{mEngine.loadProgram(renderer::ReferencePath{gLightProgramPath})},
118-
mLineProgram{mEngine.loadProgram(renderer::ReferencePath{gLineProgramPath})}
133+
mLineDrawer{mEngine.loadProgram(renderer::ReferencePath{gLineProgramPath})}
119134
{
120135
graphics::attachIndexBuffer(mIndexBuffer, mVertexSpecification.mVertexArray);
121136

@@ -159,7 +174,7 @@ void Scene::loadPrograms()
159174
mEngine.loadProgram(renderer::ReferencePath{ gProgramPath });
160175
mLightProgram =
161176
mEngine.loadProgram(renderer::ReferencePath{ gLightProgramPath });
162-
mLineProgram =
177+
mLineDrawer.mProgram =
163178
mEngine.loadProgram(renderer::ReferencePath{ gLineProgramPath });
164179
}
165180

@@ -279,29 +294,33 @@ void Scene::render(math::Size<2, int> aRenderResolution)
279294
sphereCount,
280295
0);
281296

282-
// Render point lights as sphere
283-
validateVertexAttributes(mLightProgram);
284-
glUseProgram(mLightProgram);
285-
glDrawElementsInstancedBaseInstance(
286-
GL_PATCHES,
287-
mIndicesCount,
288-
graphics::MappedGL_v<scenic::Index>,
289-
0,
290-
mLights.mPointCount,
291-
sphereCount);
297+
if (mFrameControl.mShowPunctualLights)
298+
{
299+
// Render point lights as sphere
300+
validateVertexAttributes(mLightProgram);
301+
glUseProgram(mLightProgram);
302+
glDrawElementsInstancedBaseInstance(
303+
GL_PATCHES,
304+
mIndicesCount,
305+
graphics::MappedGL_v<scenic::Index>,
306+
0,
307+
mLights.mPointCount,
308+
sphereCount);
309+
}
292310

293311
// Render tube lights as fat lines
294312
{
295313
glDisable(GL_CULL_FACE);
296-
graphics::setUniform(mLineProgram, "u_FramebufferSize", aRenderResolution);
314+
graphics::setUniform(mLineDrawer.mProgram, "u_FramebufferSize", aRenderResolution);
297315
{
298316
// Binds to the general binding point, in addition to binding index 8
299-
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 8, mLinesSsbo);
317+
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 8, mLineDrawer.mLinesSsbo);
300318
std::span<renderer::LineSegment_glsl> lines{ mLines.mSegments };
301319
glBufferData(GL_SHADER_STORAGE_BUFFER, lines.size_bytes(), lines.data(), GL_STREAM_DRAW);
302320
}
303-
glUseProgram(mLineProgram);
304-
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
321+
glBindVertexArray(mLineDrawer.mVao);
322+
glUseProgram(mLineDrawer.mProgram);
323+
glDrawArrays(GL_TRIANGLES, 0, mLineDrawer.mVerticesCount);
305324
glEnable(GL_CULL_FACE);
306325
}
307326
}
@@ -330,6 +349,8 @@ void Scene::presentUi(bool * aOpen)
330349
FrameControl::gPolygonModes.end(),
331350
[](auto aModeIt){return graphics::to_string(*aModeIt);});
332351

352+
ImGui::Checkbox("Show Punctual Lights", &mFrameControl.mShowPunctualLights);
353+
333354
DearImguiWitness witness;
334355

335356
ImGui::Spacing();

src/apps/ch10_area_lights/ch10_area_lights/Scene.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ constexpr graphics::AttributeDescriptionList gInstanceDescription{
6161
// 1,
6262
//};
6363

64+
struct LineDrawer
65+
{
66+
LineDrawer(renderer::IntrospectProgram aLineProgram);
67+
68+
graphics::Buffer<graphics::BufferType::Array> mVertices;
69+
GLuint mVerticesCount;
70+
graphics::BufferAny mLinesSsbo;
71+
graphics::VertexArrayObject mVao;
72+
renderer::IntrospectProgram mProgram;
73+
};
6474

6575
struct Scene
6676
{
@@ -83,13 +93,14 @@ struct Scene
8393

8494
struct FrameControl
8595
{
86-
inline static constexpr std::array<GLenum, 3> gPolygonModes{
96+
inline static constexpr std::array<GLenum, 3> gPolygonModes{
8797
GL_POINT,
8898
GL_LINE,
8999
GL_FILL,
90100
};
91101

92-
decltype(gPolygonModes)::const_iterator mPolygonMode = gPolygonModes.begin() + 2;
102+
decltype(gPolygonModes)::const_iterator mPolygonMode = gPolygonModes.begin() + 2;
103+
bool mShowPunctualLights = true;
93104
};
94105

95106
Scene(graphics::AppInterface & aAppInterface, const imguiui::ImguiUi & aImgui);
@@ -115,10 +126,9 @@ struct Scene
115126
graphics::UniformBufferObject mViewProjectionBuffer;
116127
graphics::UniformBufferObject mMaterialsBlockBuffer;
117128
graphics::UniformBufferObject mLightsBlockBuffer;
118-
graphics::BufferAny mLinesSsbo;
119129
renderer::IntrospectProgram mSurfaceProgram;
120130
renderer::IntrospectProgram mLightProgram;
121-
renderer::IntrospectProgram mLineProgram;
131+
LineDrawer mLineDrawer;
122132

123133
renderer::EntitiesBlock_glsl mEntities{
124134
.mEntities = {

src/libs/engine/engine/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ set(${TARGET_NAME}_HEADERS
2222

2323
set(${TARGET_NAME}_SOURCES
2424
IntrospectProgram.cpp
25+
Lines.cpp
2526
Resources.cpp
2627
ShaderConstants.cpp
2728
ShaderProgramManager.cpp

src/libs/engine/engine/Lines.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#pragma once
2+
3+
4+
#include "Lines.h"
5+
6+
#include <math/Angle.h>
7+
8+
9+
namespace ad::renderer {
10+
11+
12+
std::vector<math::Position<3, GLfloat>> makeRoundSegment(unsigned int aCircleResolution)
13+
{
14+
std::vector<math::Position<3, GLfloat>> result = {
15+
{0.0f, -0.5f, 0.0f},
16+
{0.0f, -0.5f, 1.0f},
17+
{0.0f, 0.5f, 1.0f},
18+
{0.0f, -0.5f, 0.0f},
19+
{0.0f, 0.5f, 1.0f},
20+
{0.0f, 0.5f, 0.0f},
21+
};
22+
23+
const math::Radian<GLfloat> pi{ math::pi<GLfloat> };
24+
math::Radian<GLfloat> step{ 2 * pi / aCircleResolution };
25+
26+
auto pushCircle = [&](GLfloat aSide)
27+
{
28+
math::Position<3, GLfloat> center{0.f, 0.f, aSide};
29+
for (unsigned int i = 0; i != aCircleResolution; ++i)
30+
{
31+
result.push_back(center);
32+
result.push_back({0.5f * cos(i * step), 0.5f * sin(i * step), aSide});
33+
result.push_back({0.5f * cos((i + 1) * step), 0.5f * sin((i + 1) * step), aSide});
34+
}
35+
};
36+
37+
pushCircle(0.f);
38+
pushCircle(1.f);
39+
40+
return result;
41+
}
42+
43+
} // namespace ad::renderer

src/libs/engine/engine/Lines.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,7 @@ struct LinesSsbo_glsl
2525
};
2626

2727

28+
std::vector<math::Position<3, GLfloat>> makeRoundSegment(unsigned int aCircleResolution);
29+
30+
2831
} // namespace ad::renderer
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"vertex": "shaders/Line.vert",
2+
"vertex": "shaders/LineRound.vert",
33
"fragment": "shaders/PlainColor.frag"
44
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#version 460
2+
3+
4+
#include "Constants.glsl"
5+
#include "ViewProjectionBlock.glsl"
6+
7+
8+
layout(location = 0) in vec3 v_Position;
9+
10+
out vec4 ex_Color;
11+
12+
uniform ivec2 u_FramebufferSize;
13+
14+
struct LineSegment
15+
{
16+
// We never use vec3 in buffer-backed interface blocks due to alignment complications
17+
// We could use the last float for a per-point width
18+
vec4 pointA;
19+
vec4 pointB;
20+
float width;
21+
};
22+
23+
24+
layout(std140, binding = 8) readonly buffer LinesSsbo
25+
{
26+
LineSegment ub_Segments[];
27+
};
28+
29+
30+
// Note: the idea to use a special pattern of positions to draw the line and the round endpoints
31+
// was inspired by: https://wwwtyro.net/2019/11/18/instanced-lines.html
32+
void main()
33+
{
34+
ex_Color = vec4(1);
35+
36+
LineSegment segment = ub_Segments[gl_InstanceID];
37+
float width = segment.width;
38+
vec3 point = v_Position;
39+
40+
// Use a billboarding technique, and does not requires any extra transformation
41+
// while giving equivalent results to the screen-space computation
42+
vec4 A_world = vec4(segment.pointA.xyz, 1);
43+
vec4 B_world = vec4(segment.pointB.xyz, 1);
44+
vec4 selectedPoint_world = (point.z == 1 ? B_world : A_world);
45+
46+
vec3 xBasis_world = normalize((B_world - A_world).xyz);
47+
// Extract the camera position (last column of the cameraToWorld matrix)
48+
vec3 camera_world = ub_cameraToWorld[3].xyz;
49+
vec3 quadNormal_world = camera_world - selectedPoint_world.xyz;
50+
51+
vec3 yBasis_world = normalize(cross(quadNormal_world, xBasis_world));
52+
xBasis_world = normalize(cross(yBasis_world, quadNormal_world));
53+
54+
vec3 offset_world = width * (point.x * xBasis_world + point.y * yBasis_world);
55+
vec4 vertex = selectedPoint_world + vec4(offset_world, 0);
56+
57+
gl_Position = ub_viewingProjection * vertex;
58+
}

0 commit comments

Comments
 (0)