group2 0.1.0
CSE 125 Group 2
Loading...
Searching...
No Matches
GlowCylinder.hpp
Go to the documentation of this file.
1
3
4#pragma once
5
6#include "ModelLoader.hpp"
7
8#include <cmath>
9#include <glm/ext/matrix_transform.hpp>
10#include <glm/glm.hpp>
11#include <numbers>
12
23inline LoadedModel createGlowCylinder(int slices = 24, int segments = 1, glm::vec3 emissiveColor = {8.0f, 2.0f, 10.0f})
24{
25 LoadedModel model;
26 MeshData mesh;
27
28 const float pi2 = 2.0f * std::numbers::pi_v<float>;
29
30 // ── Side vertices ──
31 // (segments+1) rings of (slices+1) vertices each.
32 for (int i = 0; i <= segments; ++i) {
33 const float y = static_cast<float>(i) / static_cast<float>(segments) - 0.5f;
34 const float v = static_cast<float>(i) / static_cast<float>(segments);
35
36 for (int j = 0; j <= slices; ++j) {
37 const float theta = pi2 * static_cast<float>(j) / static_cast<float>(slices);
38 const float ct = std::cos(theta);
39 const float st = std::sin(theta);
40
41 const glm::vec3 pos{ct, y, st};
42 const glm::vec3 normal{ct, 0.0f, st};
43 const glm::vec2 uv{static_cast<float>(j) / static_cast<float>(slices), v};
44 // Tangent runs along the height (Y axis).
45 const glm::vec4 tangent{0.0f, 1.0f, 0.0f, 1.0f};
46
47 mesh.vertices.push_back(ModelVertex{
48 .position = pos,
49 .normal = normal,
50 .texCoord = uv,
51 .tangent = tangent,
52 });
53 }
54 }
55
56 // ── Side indices ──
57 for (int i = 0; i < segments; ++i) {
58 for (int j = 0; j < slices; ++j) {
59 const uint32_t a = static_cast<uint32_t>(i * (slices + 1) + j);
60 const uint32_t b = a + static_cast<uint32_t>(slices + 1);
61
62 mesh.indices.push_back(a);
63 mesh.indices.push_back(b);
64 mesh.indices.push_back(a + 1);
65
66 mesh.indices.push_back(a + 1);
67 mesh.indices.push_back(b);
68 mesh.indices.push_back(b + 1);
69 }
70 }
71
72 // ── Cap vertices & indices ──
73 // Top cap (y = +0.5) and bottom cap (y = -0.5).
74 for (int cap = 0; cap < 2; ++cap) {
75 const float y = (cap == 0) ? 0.5f : -0.5f;
76 const glm::vec3 capNormal{0.0f, (cap == 0) ? 1.0f : -1.0f, 0.0f};
77 const auto centerIdx = static_cast<uint32_t>(mesh.vertices.size());
78
79 // Centre vertex.
80 mesh.vertices.push_back(ModelVertex{
81 .position = {0.0f, y, 0.0f},
82 .normal = capNormal,
83 .texCoord = {0.5f, 0.5f},
84 .tangent = {1.0f, 0.0f, 0.0f, 1.0f},
85 });
86
87 // Ring vertices.
88 const auto ringStart = static_cast<uint32_t>(mesh.vertices.size());
89 for (int j = 0; j <= slices; ++j) {
90 const float theta = pi2 * static_cast<float>(j) / static_cast<float>(slices);
91 const float ct = std::cos(theta);
92 const float st = std::sin(theta);
93
94 mesh.vertices.push_back(ModelVertex{
95 .position = {ct, y, st},
96 .normal = capNormal,
97 .texCoord = {ct * 0.5f + 0.5f, st * 0.5f + 0.5f},
98 .tangent = {1.0f, 0.0f, 0.0f, 1.0f},
99 });
100 }
101
102 // Fan triangles.
103 for (int j = 0; j < slices; ++j) {
104 const uint32_t r0 = ringStart + static_cast<uint32_t>(j);
105 const uint32_t r1 = r0 + 1;
106 if (cap == 0) {
107 // Top cap: wind CCW from outside (looking down +Y).
108 mesh.indices.push_back(centerIdx);
109 mesh.indices.push_back(r0);
110 mesh.indices.push_back(r1);
111 } else {
112 // Bottom cap: wind CCW from outside (looking up -Y).
113 mesh.indices.push_back(centerIdx);
114 mesh.indices.push_back(r1);
115 mesh.indices.push_back(r0);
116 }
117 }
118 }
119
120 // ── Material ──
121 mesh.material.baseColorFactor = {1.0f, 1.0f, 1.0f, 1.0f};
122 mesh.material.emissiveFactor = glm::vec4(emissiveColor, 0.0f);
123 mesh.material.metallicFactor = 0.0f;
124 mesh.material.roughnessFactor = 0.2f;
125 mesh.material.aoStrength = 1.0f;
126 mesh.material.normalScale = 1.0f;
128
129 // 1x1 white emissive texture (same trick as GlowSphere).
130 TextureData whiteTex;
131 whiteTex.pixels = {255, 255, 255, 255};
132 whiteTex.width = 1;
133 whiteTex.height = 1;
134 whiteTex.isSRGB = true;
135
136 model.textures.push_back(std::move(whiteTex));
137 mesh.emissiveTexIndex = 0;
138
139 model.meshes.push_back(std::move(mesh));
140 return model;
141}
142
147inline glm::mat4 cylinderTransform(glm::vec3 start, glm::vec3 end, float radius)
148{
149 const glm::vec3 mid = (start + end) * 0.5f;
150 const glm::vec3 delta = end - start;
151 const float len = glm::length(delta);
152
153 if (len < 1e-6f)
154 return glm::translate(glm::mat4(1.0f), mid);
155
156 const glm::vec3 dir = delta / len;
157
158 // Build a rotation that maps +Y to `dir`.
159 // Find a perpendicular axis via cross product with Y.
160 const glm::vec3 up{0.0f, 1.0f, 0.0f};
161 glm::vec3 axis = glm::cross(up, dir);
162 const float sinAngle = glm::length(axis);
163 const float cosAngle = glm::dot(up, dir);
164
165 glm::mat4 rot(1.0f);
166 if (sinAngle > 1e-6f) {
167 axis /= sinAngle; // normalise
168 const float angle = std::atan2(sinAngle, cosAngle);
169 rot = glm::rotate(glm::mat4(1.0f), angle, axis);
170 } else if (cosAngle < 0.0f) {
171 // dir ≈ -Y → 180° around any perpendicular axis.
172 rot = glm::rotate(glm::mat4(1.0f), std::numbers::pi_v<float>, glm::vec3{1.0f, 0.0f, 0.0f});
173 }
174
175 // Translate → rotate → scale(radius, length, radius).
176 glm::mat4 m = glm::translate(glm::mat4(1.0f), mid);
177 m *= rot;
178 m = glm::scale(m, glm::vec3(radius, len, radius));
179 return m;
180}
LoadedModel createGlowCylinder(int slices=24, int segments=1, glm::vec3 emissiveColor={8.0f, 2.0f, 10.0f})
Generate a procedural unit cylinder as a LoadedModel.
Definition GlowCylinder.hpp:23
glm::mat4 cylinderTransform(glm::vec3 start, glm::vec3 end, float radius)
Build a world transform that places a unit cylinder (Y-axis, height 1, radius 1) so it connects start...
Definition GlowCylinder.hpp:147
Assimp-based model loading and CPU-side mesh/texture data types.
Everything returned by loadModel().
Definition ModelLoader.hpp:76
std::vector< MeshData > meshes
Definition ModelLoader.hpp:77
std::vector< TextureData > textures
Definition ModelLoader.hpp:78
float aoStrength
Definition ModelLoader.hpp:45
float metallicFactor
Default dielectric (non-metal).
Definition ModelLoader.hpp:43
glm::vec4 emissiveFactor
rgb in xyz, w unused.
Definition ModelLoader.hpp:47
AlphaMode alphaMode
Definition ModelLoader.hpp:48
glm::vec4 baseColorFactor
Definition ModelLoader.hpp:42
float roughnessFactor
Default mid-roughness.
Definition ModelLoader.hpp:44
float normalScale
Definition ModelLoader.hpp:46
CPU-side mesh data ready for GPU upload.
Definition ModelLoader.hpp:54
std::vector< uint32_t > indices
Definition ModelLoader.hpp:56
int emissiveTexIndex
Emissive texture.
Definition ModelLoader.hpp:61
std::vector< ModelVertex > vertices
Definition ModelLoader.hpp:55
MaterialData material
Scalar PBR factors.
Definition ModelLoader.hpp:62
One vertex in a loaded 3-D model (PBR-ready).
Definition ModelLoader.hpp:19
glm::vec3 position
Definition ModelLoader.hpp:20
RGBA pixel data for one texture (decoded from embedded PNG/JPEG).
Definition ModelLoader.hpp:67
int height
Definition ModelLoader.hpp:70
std::vector< uint8_t > pixels
Row-major RGBA, 4 bytes per pixel.
Definition ModelLoader.hpp:68
bool isSRGB
True for color textures (albedo, emissive); false for data (normal, MR).
Definition ModelLoader.hpp:71
int width
Definition ModelLoader.hpp:69