void InitializeForms() { // build color table: for (unsigned int i = 0; i < 256; i++) { float rr, gg, bb; // // generic Hue profile as deduced from true-color imaging for spirals // Hue in degrees float hue = (i < 28)? 25 * tanh(0.0615f * (27 - i)): 25 * tanh(0.0615f * (27 - i)) + 220; //convert Hue to RGB DeepSkyObject::hsv2rgb(&rr, &gg, &bb, hue, 0.20f, 1.0f); colorTable[i] = Color(rr, gg, bb); } // Spiral Galaxies, 7 classical Hubble types spiralForms = new GalacticForm*[7]; spiralForms[Galaxy::S0] = buildGalacticForms("models/S0.png"); spiralForms[Galaxy::Sa] = buildGalacticForms("models/Sa.png"); spiralForms[Galaxy::Sb] = buildGalacticForms("models/Sb.png"); spiralForms[Galaxy::Sc] = buildGalacticForms("models/Sc.png"); spiralForms[Galaxy::SBa] = buildGalacticForms("models/SBa.png"); spiralForms[Galaxy::SBb] = buildGalacticForms("models/SBb.png"); spiralForms[Galaxy::SBc] = buildGalacticForms("models/SBc.png"); // Elliptical Galaxies , 8 classical Hubble types, E0..E7, // // To save space: generate spherical E0 template from S0 disk // via rescaling by (1.0f, 3.8f, 1.0f). ellipticalForms = new GalacticForm*[8]; for (unsigned int eform = 0; eform <= 7; ++eform) { float ell = 1.0f - (float) eform / 8.0f; // note the correct x,y-alignment of 'ell' scaling!! // build all elliptical templates from rescaling E0 ellipticalForms[eform] = buildGalacticForms("models/E0.png"); if (*ellipticalForms) ellipticalForms[eform]->scale = Vec3f(ell, ell, 1.0f); // account for reddening of ellipticals rel.to spirals if (*ellipticalForms) { unsigned int nPoints = (unsigned int) (ellipticalForms[eform]->blobs->size()); for (unsigned int i = 0; i < nPoints; ++i) { (*ellipticalForms[eform]->blobs)[i].colorIndex = (unsigned int) ceil(0.76f * (*ellipticalForms[eform]->blobs)[i].colorIndex); } } } //Irregular Galaxies unsigned int galaxySize = GALAXY_POINTS, ip = 0; Blob b; Point3f p; vector<Blob>* irregularPoints = new vector<Blob>; irregularPoints->reserve(galaxySize); while (ip < galaxySize) { p = Point3f(Mathf::sfrand(), Mathf::sfrand(), Mathf::sfrand()); float r = p.distanceFromOrigin(); if (r < 1) { float prob = (1 - r) * (fractalsum(Point3f(p.x + 5, p.y + 5, p.z + 5), 8) + 1) * 0.5f; if (Mathf::frand() < prob) { b.position = p; b.brightness = 64u; unsigned int rr = (unsigned int) (r * 511); b.colorIndex = rr < 256? rr: 255; irregularPoints->push_back(b); ++ip; } } } irregularForm = new GalacticForm(); irregularForm->blobs = irregularPoints; irregularForm->scale = Vec3f(0.5f, 0.5f, 0.5f); formsInitialized = true; }
void Galaxy::renderGalaxyPointSprites(const GLContext&, const Vec3f& offset, const Quatf& viewerOrientation, float brightness, float pixelSize) { if (form == NULL) return; /* We'll first see if the galaxy's apparent size is big enough to be noticeable on screen; if it's not we'll break right here, avoiding all the overhead of the matrix transformations and GL state changes: */ float distanceToDSO = offset.length() - getRadius(); if (distanceToDSO < 0) distanceToDSO = 0; float minimumFeatureSize = pixelSize * distanceToDSO; float size = 2 * getRadius(); if (size < minimumFeatureSize) return; if (galaxyTex == NULL) { galaxyTex = CreateProceduralTexture(width, height, GL_RGBA, GalaxyTextureEval); } assert(galaxyTex != NULL); glEnable(GL_TEXTURE_2D); galaxyTex->bind(); Mat3f viewMat = viewerOrientation.toMatrix3(); Vec3f v0 = Vec3f(-1, -1, 0) * viewMat; Vec3f v1 = Vec3f( 1, -1, 0) * viewMat; Vec3f v2 = Vec3f( 1, 1, 0) * viewMat; Vec3f v3 = Vec3f(-1, 1, 0) * viewMat; //Mat4f m = (getOrientation().toMatrix4() * // Mat4f::scaling(form->scale) * // Mat4f::scaling(getRadius())); Mat3f m = Mat3f::scaling(form->scale)*getOrientation().toMatrix3()*Mat3f::scaling(size); // Note: fixed missing factor of 2 in getRadius() scaling of galaxy diameter! // Note: fixed correct ordering of (non-commuting) operations! int pow2 = 1; vector<Blob>* points = form->blobs; unsigned int nPoints = (unsigned int) (points->size() * clamp(getDetail())); // corrections to avoid excessive brightening if viewed e.g. edge-on float brightness_corr = 1.0f; float cosi; if (type < E0 || type > E3) //all galaxies, except ~round elliptics { cosi = Vec3f(0,1,0) * getOrientation().toMatrix3() * offset/offset.length(); brightness_corr = (float) sqrt(abs(cosi)); if (brightness_corr < 0.2f) brightness_corr = 0.2f; } if (type > E3) // only elliptics with higher ellipticities { cosi = Vec3f(1,0,0) * getOrientation().toMatrix3() * offset/offset.length(); brightness_corr = brightness_corr * (float) abs((cosi)); if (brightness_corr < 0.45f) brightness_corr = 0.45f; } glBegin(GL_QUADS); for (unsigned int i = 0; i < nPoints; ++i) { if ((i & pow2) != 0) { pow2 <<= 1; size /= 1.55f; if (size < minimumFeatureSize) break; } Blob b = (*points)[i]; Point3f p = b.position * m; float br = b.brightness / 255.0f; Color c = colorTable[b.colorIndex]; // lookup static color table Point3f relPos = p + offset; float screenFrac = size / relPos.distanceFromOrigin(); if (screenFrac < 0.1f) { float btot = ((type > SBc) && (type < Irr))? 2.5f: 5.0f; float a = btot * (0.1f - screenFrac) * brightness_corr * brightness * br; glColor4f(c.red(), c.green(), c.blue(), (4.0f*lightGain + 1.0f)*a); glTexCoord2f(0, 0); glVertex(p + (v0 * size)); glTexCoord2f(1, 0); glVertex(p + (v1 * size)); glTexCoord2f(1, 1); glVertex(p + (v2 * size)); glTexCoord2f(0, 1); glVertex(p + (v3 * size)); } } glEnd(); }