📄 opengl_renderer.cpp
字号:
phase = PI; } for (g = 0; g <= segments; ++g) { /* segment (bottom to top) */ if (g < segments/2) currentRad = startRad + (midRad - startRad) * (0.5 - 0.5 * cos(PI * g / (segments/2))); else currentRad = midRad + (startRad - midRad) * (0.5 - 0.5 * cos(PI * (g - segments/2) / (segments/2))); CR[1] = height * g / segments - height/2; if (g > 0) phase += PI * 2 / segments; CR[2] = bigRad * cos(phase); CR[0] = bigRad * sin(phase); /* make a strip around the strand circumference */ for (s = 0; s < LOGO_SIDES; ++s) { V[0] = CR[0]; V[2] = CR[2]; V[1] = 0; length = sqrt(V[0]*V[0] + V[1]*V[1] + V[2]*V[2]); for (i = 0; i < 3; ++i) V[i] /= length; H[0] = H[2] = 0; H[1] = 1; for (i = 0; i < 3; ++i) { pRingNorm[3*s + i] = V[i] * cos(PI * 2 * s / LOGO_SIDES) + H[i] * sin(PI * 2 * s / LOGO_SIDES); pRingPts[3*s + i] = CR[i] + pRingNorm[3*s + i] * currentRad; } } if (g > 0) { glBegin(GL_TRIANGLE_STRIP); for (s = 0; s < LOGO_SIDES; ++s) { glNormal3d(pPrevNorm[3*s], pPrevNorm[3*s + 1], pPrevNorm[3*s + 2]); glVertex3d(pPrevRing[3*s], pPrevRing[3*s + 1], pPrevRing[3*s + 2]); glNormal3d(pRingNorm[3*s], pRingNorm[3*s + 1], pRingNorm[3*s + 2]); glVertex3d(pRingPts[3*s], pRingPts[3*s + 1], pRingPts[3*s + 2]); } glNormal3d(pPrevNorm[0], pPrevNorm[1], pPrevNorm[2]); glVertex3d(pPrevRing[0], pPrevRing[1], pPrevRing[2]); glNormal3d(pRingNorm[0], pRingNorm[1], pRingNorm[2]); glVertex3d(pRingPts[0], pRingPts[1], pRingPts[2]); glEnd(); } /* cap the ends */ glBegin(GL_POLYGON); if ((g == 0 && n == 0) || (g == segments && n == 1)) glNormal3d(-1, 0, 0); else glNormal3d(1, 0, 0); if (g == 0) { for (s = 0; s < LOGO_SIDES; ++s) glVertex3d(pRingPts[3*s], pRingPts[3*s + 1], pRingPts[3*s + 2]); } else if (g == segments) { for (s = LOGO_SIDES - 1; s >= 0; --s) glVertex3d(pRingPts[3*s], pRingPts[3*s + 1], pRingPts[3*s + 2]); } glEnd(); /* switch pointers to store previous ring */ tmp = pPrevRing; pPrevRing = pRingPts; pRingPts = tmp; tmp = pPrevNorm; pPrevNorm = pRingNorm; pRingNorm = tmp; } } glEndList();}// stuff dealing with rendering of transparent spheresvoid OpenGLRenderer::AddTransparentSphere(const Vector& color, unsigned int name, const Vector& site, double radius, double alpha){ if (currentDisplayList == NO_LIST) { WARNINGMSG("OpenGLRenderer::AddTransparentSphere() - not called during display list creation"); return; } SphereList& spheres = transparentSphereMap[currentDisplayList]; spheres.resize(spheres.size() + 1); SphereInfo& info = spheres.back(); info.site = site; info.name = name; info.color = color; info.radius = radius; info.alpha = alpha;}// add spheres associated with this display list; calculate distance from camera to each onevoid OpenGLRenderer::AddTransparentSpheresForList(unsigned int list){ SphereMap::const_iterator sL = transparentSphereMap.find(list); if (sL == transparentSphereMap.end()) return; const SphereList& sphereList = sL->second; Matrix view; GL2Matrix(viewMatrix, &view); transparentSpheresToRender.resize(transparentSpheresToRender.size() + sphereList.size()); SpherePtrList::reverse_iterator sph = transparentSpheresToRender.rbegin(); SphereList::const_iterator i, ie=sphereList.end(); const Matrix *slaveTransform; for (i=sphereList.begin(); i!=ie; ++i, ++sph) { sph->siteGL = i->site; slaveTransform = *(structureSet->transformMap[list]); if (slaveTransform) ApplyTransformation(&(sph->siteGL), *slaveTransform); // slave->master transform ApplyTransformation(&(sph->siteGL), view); // current view transform sph->distanceFromCamera = (Vector(0,0,cameraDistance) - sph->siteGL).length() - i->radius; sph->ptr = &(*i); }}void OpenGLRenderer::RenderTransparentSpheres(void){ if (transparentSpheresToRender.size() == 0) return; // sort spheres by distance from camera, via operator < defined for SpherePtr transparentSpheresToRender.sort(); // turn on blending glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); SetColor(GL_NONE); // reset color caches in SetColor // render spheres in order (farthest first) SpherePtrList::reverse_iterator i, ie=transparentSpheresToRender.rend(); for (i=transparentSpheresToRender.rbegin(); i!=ie; ++i) { SetColor(GL_DIFFUSE, i->ptr->color[0], i->ptr->color[1], i->ptr->color[2], i->ptr->alpha); glLoadName(static_cast<GLuint>(i->ptr->name)); glPushMatrix(); glTranslated(i->siteGL.x, i->siteGL.y, i->siteGL.z); // apply a random spin so they're not all facing the same direction srand(static_cast<unsigned int>(fabs(i->ptr->site.x * 1000))); glRotated(360.0*rand()/RAND_MAX, 1.0*rand()/RAND_MAX - 0.5, 1.0*rand()/RAND_MAX - 0.5, 1.0*rand()/RAND_MAX - 0.5); gluSphere(qobj, i->ptr->radius, atomSlices, atomStacks); glPopMatrix(); } // turn off blending glDisable(GL_BLEND); // clear list; recreate it upon each Display() transparentSpheresToRender.clear();}void OpenGLRenderer::DrawAtom(const Vector& site, const AtomStyle& atomStyle){ if (atomStyle.style == StyleManager::eNotDisplayed || atomStyle.radius <= 0.0) return; if (atomStyle.style == StyleManager::eSolidAtom) { SetColor(GL_DIFFUSE, atomStyle.color[0], atomStyle.color[1], atomStyle.color[2]); glLoadName(static_cast<GLuint>(atomStyle.name)); glPushMatrix(); glTranslated(site.x, site.y, site.z); gluSphere(qobj, atomStyle.radius, atomSlices, atomStacks); glPopMatrix(); } // need to delay rendering of transparent spheres else { AddTransparentSphere(atomStyle.color, atomStyle.name, site, atomStyle.radius, atomStyle.alpha); // but can put labels on now if (atomStyle.centerLabel.size() > 0) DrawLabel(atomStyle.centerLabel, site, (atomStyle.isHighlighted ? GlobalColors()->Get(Colors::eHighlight) : Vector(1,1,1))); } displayListEmpty[currentDisplayList] = false;}/* add a thick splined curve from point 1 *halfway* to point 2 */static void DrawHalfWorm(const Vector *p0, const Vector& p1, const Vector& p2, const Vector *p3, double radius, bool cap1, bool cap2, double tension){ int i, j, k, m, offset; Vector R1, R2, Qt, p, dQt, H, V; double len, MG[4][3], T[4], t, prevlen=0.0, cosj, sinj; GLdouble *Nx = NULL, *Ny, *Nz, *Cx, *Cy, *Cz, *pNx, *pNy, *pNz, *pCx, *pCy, *pCz, *tmp; if (!p0 || !p3) { ERRORMSG("DrawHalfWorm: got NULL 0th and/or 3rd coords for worm"); return; } /* * The Hermite matrix Mh. */ static double Mh[4][4] = { { 2, -2, 1, 1}, {-3, 3, -2, -1}, { 0, 0, 1, 0}, { 1, 0, 0, 0} }; /* * Variables that affect the curve shape * a=b=0 = Catmull-Rom */ double a = tension, /* tension (adjustable) */ c = 0, /* continuity (should be 0) */ b = 0; /* bias (should be 0) */ if (wormSides % 2) { WARNINGMSG("worm sides must be an even number"); ++wormSides; } GLdouble *fblock = NULL; /* First, calculate the coordinate points of the center of the worm, * using the Kochanek-Bartels variant of the Hermite curve. */ R1 = 0.5 * (1 - a) * (1 + b) * (1 + c) * (p1 - *p0) + 0.5 * (1 - a) * (1 - b) * (1 - c) * ( p2 - p1); R2 = 0.5 * (1 - a) * (1 + b) * (1 - c) * (p2 - p1) + 0.5 * (1 - a) * (1 - b) * (1 + c) * (*p3 - p2); /* * Multiply MG=Mh.Gh, where Gh = [ P(1) P(2) R(1) R(2) ]. This * 4x1 matrix of vectors is constant for each segment. */ for (i = 0; i < 4; ++i) { /* calculate Mh.Gh */ MG[i][0] = Mh[i][0] * p1.x + Mh[i][1] * p2.x + Mh[i][2] * R1.x + Mh[i][3] * R2.x; MG[i][1] = Mh[i][0] * p1.y + Mh[i][1] * p2.y + Mh[i][2] * R1.y + Mh[i][3] * R2.y; MG[i][2] = Mh[i][0] * p1.z + Mh[i][1] * p2.z + Mh[i][2] * R1.z + Mh[i][3] * R2.z; } for (i = 0; i <= wormSegments; ++i) { /* t goes from [0,1] from P(1) to P(2) (and we want to go halfway only), and the function Q(t) defines the curve of this segment. */ t = (0.5 / wormSegments) * i; /* * Q(t)=T.(Mh.Gh), where T = [ t^3 t^2 t 1 ] */ T[0] = t * t * t; T[1] = t * t; T[2] = t; //T[3] = 1; Qt.x = T[0] * MG[0][0] + T[1] * MG[1][0] + T[2] * MG[2][0] + MG[3][0] /* *T[3] */ ; Qt.y = T[0] * MG[0][1] + T[1] * MG[1][1] + T[2] * MG[2][1] + MG[3][1] /* *T[3] */ ; Qt.z = T[0] * MG[0][2] + T[1] * MG[1][2] + T[2] * MG[2][2] + MG[3][2] /* *T[3] */ ; if (radius == 0.0) { if (i > 0) { glBegin(GL_LINES); glVertex3d(p.x, p.y, p.z); glVertex3d(Qt.x, Qt.y, Qt.z); glEnd(); } /* save to use as previous point for connecting points together */ p = Qt; } else { /* construct a circle of points centered at and in a plane normal to the curve at t - these points will be used to construct the "thick" worm */ /* allocate single block of storage for two circles of points */ if (!Nx) { fblock = new GLdouble[12 * wormSides]; Nx = fblock; Ny = &Nx[wormSides]; Nz = &Nx[wormSides * 2]; Cx = &Nx[wormSides * 3]; Cy = &Nx[wormSides * 4]; Cz = &Nx[wormSides * 5]; pNx = &Nx[wormSides * 6]; pNy = &Nx[wormSides * 7]; pNz = &Nx[wormSides * 8]; pCx = &Nx[wormSides * 9]; pCy = &Nx[wormSides * 10]; pCz = &Nx[wormSides * 11]; } /* * The first derivative of Q(t), d(Q(t))/dt, is the slope * (tangent) at point Q(t); now T = [ 3t^2 2t 1 0 ] */ T[0] = t * t * 3; T[1] = t * 2; //T[2] = 1; //T[3] = 0; dQt.x = T[0] * MG[0][0] + T[1] * MG[1][0] + MG[2][0] /* *T[2] + T[3]*MG[3][0] */ ; dQt.y = T[0] * MG[0][1] + T[1] * MG[1][1] + MG[2][1] /* *T[2] + T[3]*MG[3][1] */ ; dQt.z = T[0] * MG[0][2] + T[1] * MG[1][2] + MG[2][2] /* *T[2] + T[3]*MG[3][2] */ ; /* use cross prod't of [1,0,0] x normal as horizontal */ H.Set(0.0, -dQt.z, dQt.y); if (H.length() < 0.000001) /* nearly colinear - use [1,0.1,0] instead */ H.Set(0.1 * dQt.z, -dQt.z, dQt.y - 0.1 * dQt.x); H.normalize(); /* and a vertical vector = normal x H */ V = vector_cross(dQt, H); V.normalize(); /* finally, the worm circumference points (C) and normals (N) are simple trigonometric combinations of H and V */ for (j = 0; j < wormSides; ++j) { cosj = cos(2 * PI * j / wormSides); sinj = sin(2 * PI * j / wormSides); Nx[j] = H.x * cosj + V.x * sinj; Ny[j] = H.y * cosj + V.y * sinj; Nz[j] = H.z * cosj + V.z * sinj; Cx[j] = Qt.x + Nx[j] * radius; Cy[j] = Qt.y + Ny[j] * radius; Cz[j] = Qt.z + Nz[j] * radius; } /* figure out which points on the previous circle "match" best with these, to minimize envelope twisting */ if (i > 0) { for (m = 0; m < wormSides; ++m) { len = 0.0; for (j = 0; j < wormSides; ++j) { k = j + m; if (k >= wormSides) k -= wormSides; len += (Cx[k] - pCx[j]) * (Cx[k] - pCx[j]) + (Cy[k] - pCy[j]) * (Cy[k] - pCy[j]) + (Cz[k] - pCz[j]) * (Cz[k] - pCz[j]); } if (m == 0 || len < prevlen) { prevlen = len; offset = m; } } } /* create triangles from points along this and previous circle */ if (i > 0) { glBegin(GL_TRIANGLE_STRIP); for (j = 0; j < wormSides; ++j) { k = j + offset; if (k >= wormSides) k -= wormSides; glNormal3d(Nx[k], Ny[k], Nz[k]); glVertex3d(Cx[k], Cy[k], Cz[k]); glNormal3d(pNx[j], pNy[j], pNz[j]); glVertex3d(pCx[j], pCy[j], pCz[j]); } glNormal3d(Nx[offset], Ny[offset], Nz[offset]); glVertex3d(Cx[offset], Cy[offset], Cz[offset]); glNormal3d(pNx[0], pNy[0], pNz[0]); glVertex3d(pCx[0], pCy[0], pCz[0]); glEnd(); } /* put caps on the end */ if (cap1 && i == 0) { glBegin(GL_POLYGON); dQt.normalize(); glNormal3d(-dQt.x, -dQt.y, -dQt.z); for (j = wormSides - 1; j >= 0; --j) { glVertex3d(Cx[j], Cy[j], Cz[j]); } glEnd(); } else if (cap2 && i == wormSegments) { glBegin(GL_POLYGON); dQt.normalize();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -