33 const std::map<uint64_t, std::set<uint64_t>> & bonds,
34 const std::vector<Atom> & atoms,
36 uint64_t bondPad = 1024,
37 float clipCorrection = 5.0f
39 : nBonds(0), bondPadding(bondPad)
41 maximumBonds = bondPadding;
42 for (
const auto & ibonds : bonds)
44 maximumBonds += ibonds.second.size();
47 shader = std::make_unique<jGL::GL::glShader>(vertexShader, fragmentShader);
49 shader->setUniform<
float>(
"clipCorrection", clipCorrection);
50 shader->setUniform<glm::vec4>(
"lightColour", glm::vec4(1.0f,1.0f,1.0f,1.0f));
51 shader->setUniform<
float>(
"ambientLight", 0.1f);
55 for (
const auto & ibonds : bonds)
57 for (
const auto & j : ibonds.second)
59 insert({ibonds.first, j}, atoms);
84 shader->setUniform<
float>(
"clipCorrection", correction);
92 void setView(glm::mat4 v) { view = v; setProjectionView(); }
99 void setProjection(glm::mat4 p) { projection = p; setProjectionView(); }
111 glm::vec3 colour = {1.0f, 1.0f, 1.0f},
115 cameraPosition = position;
117 shader->setUniform<glm::vec4>(
"lightPos", glm::vec4(position, 1.0f));
118 shader->setUniform<glm::vec4>(
"lightColour", glm::vec4(colour, 1.0f));
119 shader->setUniform<
float>(
"ambientLight", ambient);
132 shader->setUniform<glm::vec4>(
"lightPos", glm::vec4(cameraPosition, 1.0f));
136 if (transparencySortingEnabled) { updateVertexArray(); };
146 transparencySortingEnabled = sort;
147 if (transparencySortingEnabled) { updateVertexArray(); };
159 shader->setUniform<
float>(
"bondScale", scale);
182 const std::map<uint64_t, std::set<uint64_t>> & bonds,
183 const std::vector<Atom> & atoms
187 for (
const auto & ibonds : bonds)
189 bCount += ibonds.second.size();
191 if (bCount > maximumBonds)
193 std::cout <<
"Reallocating bonds:\n"
194 <<
" New bonds size: " << bCount
195 <<
"\n Storage: " << maximumBonds
196 <<
"\n New storage: " << bCount+bondPadding
199 maximumBonds = bCount+bondPadding;
203 for (
const auto & ibonds : bonds)
205 for (
const auto & j : ibonds.second)
207 insert({ibonds.first, j}, atoms);
220 count = std::min(count, nBonds);
221 if (count == 0) {
return; }
226 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
227 glEnable(GL_DEPTH_TEST);
228 glEnable(GL_CULL_FACE);
232 glBindVertexArray(vao);
234 glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, count);
236 glBindVertexArray(0);
254 globalAlpha = std::max(0.0f, std::min(alpha, 1.0f));
256 shader->setUniform<
float>(
"globalAlpha", globalAlpha);
263 uint64_t bondPadding;
264 uint64_t maximumBonds;
265 std::unique_ptr<jGL::GL::glShader> shader;
266 glm::vec3 cameraPosition = glm::vec3(0.0f);
269 GLuint vao, a_vertices, b_vertices, a_colours, b_colours, a_quad;
270 std::vector<float> positionsAAndScale;
271 std::vector<float> positionsBAndScale;
272 std::vector<float> coloursA;
273 std::vector<float> coloursB;
275 glm::mat4 view, projection;
278 bool transparencySortingEnabled =
true;
282 const std::array<float, 8> quad =
290 const char * vertexShader =
291 "#version " GLSL_VERSION
"\n"
292 "precision lowp float; precision lowp int;\n"
293 "layout(location=0) in vec2 a_vertices;\n"
294 "layout(location=1) in vec4 a_positionsAAndScales;\n"
295 "layout(location=2) in vec4 a_positionsBAndScales;\n"
296 "layout(location=3) in vec4 a_colours;\n"
297 "layout(location=4) in vec4 b_colours;\n"
298 "out vec2 billboard;\n"
299 "uniform mat4 view;\n"
300 "uniform mat4 proj;\n"
301 "uniform float clipCorrection;\n"
302 "uniform float bondScale;\n"
303 "out vec4 aPosScale;\n"
304 "out vec3 aViewPos;\n"
305 "out vec4 bPosScale;\n"
306 "out vec3 bViewPos;\n"
307 "out vec4 a_colour;\n"
308 "out vec4 b_colour;\n"
309 "out vec3 comViewPos;\n"
312 " billboard = a_vertices * clipCorrection;\n"
313 " aViewPos = (view * vec4(a_positionsAAndScales.xyz, 1.0)).xyz;"
314 " bViewPos = (view * vec4(a_positionsBAndScales.xyz, 1.0)).xyz;"
315 " comViewPos = (aViewPos+bViewPos)*0.5;\n"
316 " gl_Position = proj * (vec4(comViewPos, 1.0)+vec4(bondScale * a_vertices * clipCorrection, 0.0, 1.0));"
317 " aPosScale = a_positionsAAndScales;\n"
318 " bPosScale = a_positionsBAndScales;\n"
319 " a_colour = a_colours;\n"
320 " b_colour = b_colours;\n"
323 const char * fragmentShader =
324 "#version " GLSL_VERSION
"\n"
325 "precision lowp float; precision lowp int;\n"
326 "in vec2 billboard;\n"
327 "in vec3 aViewPos;\n"
328 "in vec3 bViewPos;\n"
329 "in vec4 aPosScale;\n"
330 "in vec4 bPosScale;\n"
331 "in vec4 a_colour;\n"
332 "in vec4 b_colour;\n"
333 "in vec3 comViewPos;\n"
335 "uniform mat4 view;\n"
336 "uniform mat4 proj;\n"
337 "uniform vec4 lightPos;\n"
338 "uniform vec4 lightColour;\n"
339 "uniform float ambientLight;\n"
340 "uniform float bondScale;\n"
341 "uniform float globalAlpha;\n"
342 "bool sphereHit(vec3 rayDirection, vec3 centre, float radius, out vec3 pos, out vec3 normal)\n"
344 " float b = 2.0 * dot(rayDirection, -centre);\n"
345 " float r2 = radius*radius;\n"
346 " float determinant = b * b - (4.0 * (dot(centre, centre) - r2));\n"
347 " if(determinant < 0.0) { return false; }\n"
348 " determinant = sqrt(determinant);\n"
349 " pos = rayDirection * min((-b+determinant)*0.5, (-b-determinant)*0.5);\n"
350 " normal = normalize(pos - centre);\n"
370 " vec3 rayDirection,"
371 " vec3 capsuleDirection,"
377 " out vec3 viewNormal,"
378 " out vec3 projectedHitPoint,"
382 " float a = dot(capsuleA, capsuleDirection);"
383 " float b = dot(rayDirection, capsuleDirection);\n"
384 " float c = dot(capsuleA, rayDirection);\n"
385 " float l = dot(capsuleA, capsuleA);\n"
386 " float r2 = radius*radius;\n"
387 " float determinant = (a*b-c)*(a*b-c)-(1.0-b*b)*(l-a*a-r2);\n"
388 " if (determinant < 0)\n"
390 " if (sphereHit(rayDirection, capsuleA, radius, viewPos, viewNormal)){ projectedHitPoint = capsuleA; s = 0.0; return true; }\n"
391 " if (sphereHit(rayDirection, capsuleB, radius, viewPos, viewNormal)){ projectedHitPoint = capsuleB; s = midLength; return true; }\n"
394 " float d = sqrt(determinant);\n"
396 " float t = min( (-(a*b-c)+d)/(1.0-b*b), (-(a*b-c)-d)/(1.0-b*b) );"
397 " viewPos = rayDirection * t;\n"
398 " s = -dot(capsuleA-viewPos, capsuleDirection);\n"
400 " if (sphereHit(rayDirection, capsuleA, radius, viewPos, viewNormal)){ projectedHitPoint = capsuleA; s = 0.0; return true; }\n"
403 " if (s > midLength){\n"
404 " if (sphereHit(rayDirection, capsuleB, radius, viewPos, viewNormal)){ projectedHitPoint = capsuleB; s = midLength; return true; }\n"
407 " vec3 u = s*capsuleDirection;\n"
408 " projectedHitPoint = capsuleA+u;\n"
409 " viewNormal = normalize(viewPos-projectedHitPoint);\n"
414 " vec3 lightViewPos = (view*lightPos).xyz;\n"
415 " vec3 rayDirection = normalize(vec3(billboard * bondScale, 0.0) + comViewPos);"
416 " float midLength = length(bViewPos-aViewPos);\n"
417 " vec3 capsuleDirection = normalize(bViewPos-aViewPos);\n"
418 " vec3 viewPos; vec3 viewNormal; vec3 projectedHitPoint; float s;\n"
419 " bool hit = capsuleHit(rayDirection, capsuleDirection, aViewPos, bViewPos, bondScale, midLength, viewPos, viewNormal, projectedHitPoint, s);\n"
420 " if (!hit) { discard; }\n"
423 " vec4 clipPos = proj * vec4(viewPos, 1.0);\n"
424 " float ndcDepth = clipPos.z / clipPos.w;\n"
425 " gl_FragDepth = ((gl_DepthRange.diff * ndcDepth) + gl_DepthRange.near + gl_DepthRange.far) / 2.0;\n"
426 " float diff = max(dot(viewNormal, normalize(lightViewPos-projectedHitPoint)), 0.0);\n"
427 " vec4 col = a_colour;\n"
428 " if (s > 0.5*midLength) { col = b_colour; }\n"
429 " colour = vec4((ambientLight + diff)*lightColour.rgb * col.rgb, col.a*globalAlpha);\n"
435 glDeleteVertexArrays(1, &vao);
436 glDeleteBuffers(1, &a_vertices);
437 glDeleteBuffers(1, &b_vertices);
438 glDeleteBuffers(1, &a_colours);
439 glDeleteBuffers(1, &b_colours);
440 glDeleteBuffers(1, &a_quad);
443 void setProjectionView()
445 shader->setUniform<glm::mat4>(
"view", view);
446 shader->setUniform<glm::mat4>(
"proj", projection);
451 glGenVertexArrays(1, &vao);
452 glGenBuffers(1, &a_vertices);
453 glGenBuffers(1, &b_vertices);
454 glGenBuffers(1, &a_colours);
455 glGenBuffers(1, &b_colours);
456 glGenBuffers(1, &a_quad);
458 positionsAAndScale.resize(4*maximumBonds);
459 positionsBAndScale.resize(4*maximumBonds);
460 coloursA.resize(4*maximumBonds);
461 coloursB.resize(4*maximumBonds);
463 glBindVertexArray(vao);
479 positionsAAndScale.data(),
480 positionsAAndScale.size(),
490 positionsBAndScale.data(),
491 positionsBAndScale.size(),
519 glBindVertexArray(0);
526 void flip() { index = 0; nBonds = 0; }
536 const std::pair<uint64_t, uint64_t> & bond,
537 const std::vector<Atom> & atoms
540 const Atom & a = atoms[bond.first];
541 const Atom & b = atoms[bond.second];
544 positionsAAndScale[index] = a.
position.x;
545 positionsAAndScale[index+1] = a.
position.y;
546 positionsAAndScale[index+2] = a.
position.z;
547 positionsAAndScale[index+3] = a.
scale;
549 positionsBAndScale[index] = b.
position.x;
550 positionsBAndScale[index+1] = b.
position.y;
551 positionsBAndScale[index+2] = b.
position.z;
552 positionsBAndScale[index+3] = b.
scale;
554 coloursA[index] = a.
colour.r;
555 coloursA[index+1] = a.
colour.g;
556 coloursA[index+2] = a.
colour.b;
557 coloursA[index+3] = a.
colour.a;
559 coloursB[index] = b.
colour.r;
560 coloursB[index+1] = b.
colour.g;
561 coloursB[index+2] = b.
colour.b;
562 coloursB[index+3] = b.
colour.a;
572 void updateVertexArray()
575 glBindVertexArray(vao);
577 subFullBuffer(a_vertices, positionsAAndScale.data(), positionsAAndScale.size());
578 subFullBuffer(b_vertices, positionsBAndScale.data(), positionsBAndScale.size());
582 glBindVertexArray(0);
588 if (!transparencySortingEnabled || nBonds == 0) {
return; }
592 std::vector<std::pair<float, uint64_t>> order;
593 order.reserve(nBonds);
594 for (uint64_t i = 0; i < nBonds; i++)
597 float rx = 0.5f*(positionsAAndScale[i*4]+positionsBAndScale[i*4])-cameraPosition.x;
598 float ry = 0.5f*(positionsAAndScale[i*4+1]+positionsBAndScale[i*4+1])-cameraPosition.y;
599 float rz = 0.5f*(positionsAAndScale[i*4+2]+positionsBAndScale[i*4+2])-cameraPosition.z;
600 float d2 = rx*rx+ry*ry+rz*rz+scale*scale;
601 order.push_back({d2, i});
609 const std::pair<float, uint64_t> & a,
610 const std::pair<float, uint64_t> & b
613 return a.first > b.first;
618 std::vector<float> positionsAAndScale_tmp = positionsAAndScale;
619 std::vector<float> positionsBAndScale_tmp = positionsBAndScale;
620 std::vector<float> coloursA_tmp = coloursA;
621 std::vector<float> coloursB_tmp = coloursB;
622 for (
auto iter = order.begin(); iter != order.end(); iter++)
624 positionsAAndScale[index] = positionsAAndScale_tmp[iter->second*4];
625 positionsAAndScale[index+1] = positionsAAndScale_tmp[iter->second*4+1];
626 positionsAAndScale[index+2] = positionsAAndScale_tmp[iter->second*4+2];
627 positionsAAndScale[index+3] = positionsAAndScale_tmp[iter->second*4+3];
629 coloursA[index] = coloursA_tmp[iter->second*4];
630 coloursA[index+1] = coloursA_tmp[iter->second*4+1];
631 coloursA[index+2] = coloursA_tmp[iter->second*4+2];
632 coloursA[index+3] = coloursA_tmp[iter->second*4+3];
634 positionsBAndScale[index] = positionsBAndScale_tmp[iter->second*4];
635 positionsBAndScale[index+1] = positionsBAndScale_tmp[iter->second*4+1];
636 positionsBAndScale[index+2] = positionsBAndScale_tmp[iter->second*4+2];
637 positionsBAndScale[index+3] = positionsBAndScale_tmp[iter->second*4+3];
639 coloursB[index] = coloursB_tmp[iter->second*4];
640 coloursB[index+1] = coloursB_tmp[iter->second*4+1];
641 coloursB[index+2] = coloursB_tmp[iter->second*4+2];
642 coloursB[index+3] = coloursB_tmp[iter->second*4+3];