unsigned int getPixel(GCamera& camera, int x, int y, double* pZ) { // Compute the ray vector G3DVector ray; camera.computeRayDirection(x, y, &ray); // Compute the intersection with the billboard plane double denom = m_face.dotProduct(&ray); if(std::abs(denom) < 1e-12) { *pZ = -1e200; return 0; // ray runs parallel to the plane } G3DVector t(m_pCorners[0]); t.subtract(camera.lookFromPoint()); double d = m_face.dotProduct(&t) / denom; *pZ = d; if(d < 0) return 0; // the intersection is behind the camera ray.multiply(d); ray.add(camera.lookFromPoint()); ray.subtract(m_pCorners[0]); // Compute the image coordinates int xx = (int)floor(ray.dotProduct(&m_bb.m_x) * m_pixelsX / m_squaredMagX + 0.5); int yy = (int)floor(ray.dotProduct(&m_bb.m_y) * m_pixelsY / m_squaredMagY + 0.5); // Get the pixel if(xx < 0 || yy < 0 || xx >= m_pixelsX || yy >= m_pixelsY) return 0; return m_bb.m_pImage->pixel(xx % m_bb.m_pImage->width(), m_bb.m_pImage->height() - 1 - (yy % m_bb.m_pImage->height())); }
void GBillboardWorld::draw(GImage* pImage, double* pDepthMap, GCamera& camera) { G3DVector coords[VERTEX_COUNT + 1]; int coordMap[VERTEX_COUNT + 1]; for(size_t i = 0; i < pImage->width() * pImage->height(); i++) pDepthMap[i] = 1e200; for(vector<GBillboard*>::iterator it = m_billboards.begin(); it != m_billboards.end(); it++) { // Project each of the corners onto the view GBBAugmented bb(**it); int gap = -1; int coordCount = 0; for(int i = 0; i < VERTEX_COUNT; i++) { camera.project(bb.m_pCorners[i], &coords[coordCount]); if(coords[coordCount].m_vals[2] > 0.0) coordMap[coordCount++] = i; else if(gap < 0) { gap = coordCount; coordCount = gap + 2; } } // Fudge the gap due to vertices that are behind the camera if(gap >= 0) { if(coordCount == 0) continue; // Nothing to draw // Fudge the vertex that follows the chain of valid vertices G3DVector tmp; G3DVector tmp2; int indexValid = coordMap[(gap + coordCount - 1) % coordCount]; // The corner just before the gap int indexFudge = (indexValid + 1) % VERTEX_COUNT; // The first corner that was behind the camera tmp.copy(bb.m_pCorners[indexValid]); tmp.subtract(bb.m_pCorners[indexFudge]); tmp2.copy(camera.lookFromPoint()); tmp2.subtract(bb.m_pCorners[indexFudge]); double d = (1e-6 + tmp2.dotProduct(camera.lookDirection())) / tmp.dotProduct(camera.lookDirection()); tmp.multiply(d); tmp.add(bb.m_pCorners[indexFudge]); camera.project(&tmp, &coords[gap]); // Fudge the vertex that precedes the chain of valid vertices indexValid = coordMap[(gap + 2) % coordCount]; // The corner just after the gap indexFudge = (indexValid + VERTEX_COUNT - 1) % VERTEX_COUNT; // The last corner that was behind the camera tmp.copy(bb.m_pCorners[indexValid]); tmp.subtract(bb.m_pCorners[indexFudge]); tmp2.copy(camera.lookFromPoint()); tmp2.subtract(bb.m_pCorners[indexFudge]); d = (1e-6 + tmp2.dotProduct(camera.lookDirection())) / tmp.dotProduct(camera.lookDirection()); tmp.multiply(d); tmp.add(bb.m_pCorners[indexFudge]); camera.project(&tmp, &coords[gap + 1]); } // Find the starting point (which is the lowest coordinate in the view) int a = 0; for(int i = 1; i < coordCount; i++) { if(coords[i].m_vals[1] < coords[a].m_vals[1]) a = i; } int b = a; // Find the left and right order in which the corners will be visted (bottom to top) while(true) { int c = (b + 1) % coordCount; if(a == c) break; int d = (a + coordCount - 1) % coordCount; drawSection(pImage, pDepthMap, camera, bb, &coords[a], &coords[b], &coords[c], &coords[d]); if(coords[d].m_vals[1] < coords[c].m_vals[1]) a = d; else b = c; } } }