void TubeRendererThread::run() { int numThreads = GLFunctions::idealThreadCount; int chunkSize = m_data.size() / numThreads; int begin = m_id * chunkSize; int end = m_id * chunkSize + chunkSize; if ( m_id == numThreads - 1 ) { end = m_data.size(); } // for all voxels: for ( int i = begin; i < end; ++i ) { QVector<float> fib = m_data[i]; QVector<float> extra = m_extraData[i]; if ( fib.size() < 9 ) { printf( "fib with size < 3 detected" ); continue; } int numFloats = fib.size(); QVector3D lineStart( fib[0], fib[1], fib[2] ); QVector3D lineEnd( fib[numFloats-3], fib[numFloats-2], fib[numFloats-1] ); QVector3D globalColor( fabs( lineStart.x() - lineEnd.x() ), fabs( lineStart.y() - lineEnd.y() ), fabs( lineStart.z() - lineEnd.z() ) ); globalColor.normalize(); // push back the first vertex, done seperately because of nomal calculation QVector3D localColor( fib[0] - fib[3], fib[1] - fib[4], fib[2] - fib[5] ); localColor.normalize(); m_verts->push_back( fib[0] ); m_verts->push_back( fib[1] ); m_verts->push_back( fib[2] ); m_verts->push_back( localColor.x() ); m_verts->push_back( localColor.y() ); m_verts->push_back( localColor.z() ); m_verts->push_back( globalColor.x() ); m_verts->push_back( globalColor.y() ); m_verts->push_back( globalColor.z() ); m_verts->push_back( extra.first() ); m_verts->push_back( 1.0 ); m_verts->push_back( fib[0] ); m_verts->push_back( fib[1] ); m_verts->push_back( fib[2] ); m_verts->push_back( localColor.x() ); m_verts->push_back( localColor.y() ); m_verts->push_back( localColor.z() ); m_verts->push_back( globalColor.x() ); m_verts->push_back( globalColor.y() ); m_verts->push_back( globalColor.z() ); m_verts->push_back( extra.first() ); m_verts->push_back( -1.0 ); for ( int k = 1; k < fib.size() / 3 - 1; ++k ) { QVector3D localColor( fib[k*3-3] - fib[k*3+3], fib[k*3-2] - fib[k*3+4], fib[k*3-1] - fib[k*3+5] ); localColor.normalize(); m_verts->push_back( fib[k*3] ); m_verts->push_back( fib[k*3+1] ); m_verts->push_back( fib[k*3+2] ); m_verts->push_back( localColor.x() ); m_verts->push_back( localColor.y() ); m_verts->push_back( localColor.z() ); m_verts->push_back( globalColor.x() ); m_verts->push_back( globalColor.y() ); m_verts->push_back( globalColor.z() ); m_verts->push_back( extra[k] ); m_verts->push_back( 1.0 ); m_verts->push_back( fib[k*3] ); m_verts->push_back( fib[k*3+1] ); m_verts->push_back( fib[k*3+2] ); m_verts->push_back( localColor.x() ); m_verts->push_back( localColor.y() ); m_verts->push_back( localColor.z() ); m_verts->push_back( globalColor.x() ); m_verts->push_back( globalColor.y() ); m_verts->push_back( globalColor.z() ); m_verts->push_back( extra[k] ); m_verts->push_back( -1.0 ); } QVector3D localColor2( fib[numFloats-6] - fib[numFloats-3], fib[numFloats-5] - fib[numFloats-2], fib[numFloats-4] - fib[numFloats-1] ); localColor.normalize(); // push back the last vertex, done seperately because of nomal calculation m_verts->push_back( fib[numFloats-3] ); m_verts->push_back( fib[numFloats-2] ); m_verts->push_back( fib[numFloats-1] ); m_verts->push_back( localColor2.x() ); m_verts->push_back( localColor2.y() ); m_verts->push_back( localColor2.z() ); m_verts->push_back( globalColor.x() ); m_verts->push_back( globalColor.y() ); m_verts->push_back( globalColor.z() ); m_verts->push_back( extra.last() ); m_verts->push_back( 1.0 ); m_verts->push_back( fib[numFloats-3] ); m_verts->push_back( fib[numFloats-2] ); m_verts->push_back( fib[numFloats-1] ); m_verts->push_back( localColor2.x() ); m_verts->push_back( localColor2.y() ); m_verts->push_back( localColor2.z() ); m_verts->push_back( globalColor.x() ); m_verts->push_back( globalColor.y() ); m_verts->push_back( globalColor.z() ); m_verts->push_back( extra.last() ); m_verts->push_back( -1.0 ); } }
void FiberRenderer::initGeometry() { if ( m_isInitialized ) { return; } qDebug() << "create fiber vbo's..."; std::vector<float>verts; try { verts.reserve( m_numPoints * 6 ); } catch ( std::bad_alloc& ) { qCritical() << "***error*** failed to allocate enough memory for vbo"; exit ( 0 ); } for ( unsigned int i = 0; i < m_fibs->size(); ++i ) { Fib fib = m_fibs->at(i); if ( fib.length() < 2 ) { printf( "fib with size < 2 detected" ); continue; } QVector3D lineStart = fib.firstVert(); QVector3D lineEnd = fib.lastVert(); // push back the first vertex, done seperately because of nomal calculation verts.push_back( lineStart.x() ); verts.push_back( lineStart.y() ); verts.push_back( lineStart.z() ); QVector3D secondVert = fib.getVert( 1 ); QVector3D localColor( lineStart.x() - secondVert.x(), lineStart.y() - secondVert.y(), lineStart.z() - secondVert.z() ); localColor.normalize(); verts.push_back( localColor.x() ); verts.push_back( localColor.y() ); verts.push_back( localColor.z() ); for ( unsigned int k = 1; k < fib.length() - 1; ++k ) { verts.push_back( fib[k].x() ); verts.push_back( fib[k].y() ); verts.push_back( fib[k].z() ); QVector3D localColor( fib[k-1].x() - fib[k+1].x(), fib[k-1].y() - fib[k+1].y(), fib[k-1].z() - fib[k+1].z() ); localColor.normalize(); verts.push_back( localColor.x() ); verts.push_back( localColor.y() ); verts.push_back( localColor.z() ); } // push back the last vertex, done seperately because of nomal calculation verts.push_back( lineEnd.x() ); verts.push_back( lineEnd.y() ); verts.push_back( lineEnd.z() ); QVector3D sec2last = fib[ fib.length() - 2 ]; QVector3D localColor2( sec2last.x() - lineEnd.x(), sec2last.y() - lineEnd.y(), sec2last.z() - lineEnd.z() ); localColor.normalize(); verts.push_back( localColor2.x() ); verts.push_back( localColor2.y() ); verts.push_back( localColor2.z() ); } glBindBuffer( GL_ARRAY_BUFFER, vbo ); glBufferData( GL_ARRAY_BUFFER, verts.size() * sizeof(GLfloat), verts.data(), GL_STATIC_DRAW ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); verts.clear(); m_pointsPerLine.resize( m_fibs->size() ); m_startIndexes.resize( m_fibs->size() ); int currentStart = 0; for ( unsigned int i = 0; i < m_fibs->size(); ++i ) { m_pointsPerLine[i] = m_fibs->at( i ).length(); m_startIndexes[i] = currentStart; currentStart += m_pointsPerLine[i]; } updateExtraData( 0 ); qDebug() << "create fiber vbo's done"; m_numPoints = verts.size() / 6; m_isInitialized = true; }
static unsigned int ray_color(const point3 e, double t, const point3 d, idx_stack *stk, const rectangular_node rectangulars, const sphere_node spheres, const light_node lights, color object_color, int bounces_left) { rectangular_node hit_rec = NULL, light_hit_rec = NULL; sphere_node hit_sphere = NULL, light_hit_sphere = NULL; double diffuse, specular; point3 l, _l, r, rr; object_fill fill; color reflection_part; color refraction_part; /* might be a reflection ray, so check how many times we've bounced */ if (bounces_left == 0) { SET_COLOR(object_color, 0.0, 0.0, 0.0); return 0; } /* check for intersection with a sphere or a rectangular */ intersection ip= ray_hit_object(e, d, t, MAX_DISTANCE, rectangulars, &hit_rec, spheres, &hit_sphere); if (!hit_rec && !hit_sphere) return 0; /* pick the fill of the object that was hit */ fill = hit_rec ? hit_rec->element.rectangular_fill : hit_sphere->element.sphere_fill; void *hit_obj = hit_rec ? (void *) hit_rec : (void *) hit_sphere; /* assume it is a shadow */ SET_COLOR(object_color, 0.0, 0.0, 0.0); for (light_node light = lights; light; light = light->next) { /* calculate the intersection vector pointing at the light */ subtract_vector(ip.point, light->element.position, l); multiply_vector(l, -1, _l); normalize(_l); /* check for intersection with an object. use ignore_me * because we don't care about this normal */ ray_hit_object(ip.point, _l, MIN_DISTANCE, length(l), rectangulars, &light_hit_rec, spheres, &light_hit_sphere); /* the light was not block by itself(lit object) */ if (light_hit_rec || light_hit_sphere) continue; compute_specular_diffuse(&diffuse, &specular, d, l, ip.normal, fill.phong_power); localColor(object_color, light->element.light_color, diffuse, specular, &fill); } reflection(r, d, ip.normal); double idx = idx_stack_top(stk).idx, idx_pass = fill.index_of_refraction; if (idx_stack_top(stk).obj == hit_obj) { idx_stack_pop(stk); idx_pass = idx_stack_top(stk).idx; } else { idx_stack_element e = { .obj = hit_obj, .idx = fill.index_of_refraction }; idx_stack_push(stk, e); } refraction(rr, d, ip.normal, idx, idx_pass); double R = (fill.T > 0.1) ? fresnel(d, rr, ip.normal, idx, idx_pass) : 1.0; /* totalColor = localColor + mix((1-fill.Kd) * fill.R * reflection, T * refraction, R) */ if (fill.R > 0) { /* if we hit something, add the color */ int old_top = stk->top; if (ray_color(ip.point, MIN_DISTANCE, r, stk, rectangulars, spheres, lights, reflection_part, bounces_left - 1)) { multiply_vector(reflection_part, R * (1.0 - fill.Kd) * fill.R, reflection_part); add_vector(object_color, reflection_part, object_color); } stk->top = old_top; } /* calculate refraction ray */ if ((length(rr) > 0.0) && (fill.T > 0.0) && (fill.index_of_refraction > 0.0)) { normalize(rr); if (ray_color(ip.point, MIN_DISTANCE, rr, stk,rectangulars, spheres, lights, refraction_part, bounces_left - 1)) { multiply_vector(refraction_part, (1 - R) * fill.T, refraction_part); add_vector(object_color, refraction_part, object_color); } } protect_color_overflow(object_color); return 1; } /* @param background_color this is not ambient light */ void raytracing(void* args) { arg *data = (arg*) args; point3 u, v, w, d; color object_color = { 0.0, 0.0, 0.0 }; const viewpoint *view = (*data).View; color back = { 0.0 , 0.1 , 0.1 }; uint8_t *pixels = data->pixels; int start_j,end_j; /* Separate to count the pixels */ if(pthread_equal(pthread_self(),THREAD[0])) { start_j = 0; end_j = 128; } else if(pthread_equal(pthread_self(),THREAD[1])) { start_j = 128; end_j = 256; } else if(pthread_equal(pthread_self(),THREAD[2])) { start_j = 256; end_j = 384; } else if(pthread_equal(pthread_self(),THREAD[3])) { start_j = 384; end_j = 512; } /* calculate u, v, w */ calculateBasisVectors(u, v, w, view); idx_stack stk; int factor = sqrt(SAMPLES); #pragma omp parallel for num_threads(64) \ private(stk), private(d), \ private(object_color) for (int j = start_j ; j < end_j; j++) { for (int i = 0 ; i < (*data).row; i++) { double r = 0, g = 0, b = 0; /* MSAA */ for (int s = 0; s < SAMPLES; s++) { idx_stack_init(&stk); rayConstruction(d, u, v, w, i * factor + s / factor, j * factor + s % factor, view, (*data).row * factor, (*data).col * factor); if (ray_color(view->vrp, 0.0, d, &stk,(*data).rectangulars, (*data).spheres, (*data).lights, object_color, MAX_REFLECTION_BOUNCES)) { r += object_color[0]; g += object_color[1]; b += object_color[2]; } else { r += back[0]; g += back[1]; b += back[2]; } pixels[((i + (j * (*data).row)) * 3) + 0] = r * 255 / SAMPLES; pixels[((i + (j * (*data).row)) * 3) + 1] = g * 255 / SAMPLES; pixels[((i + (j * (*data).row)) * 3) + 2] = b * 255 / SAMPLES; } } } }
static unsigned int ray_color(const point3 e, double t, const point3 d, idx_stack *stk, const rectangular_node rectangulars, const sphere_node spheres, const light_node lights, color object_color, int bounces_left) { rectangular_node hit_rec = NULL, light_hit_rec = NULL; sphere_node hit_sphere = NULL, light_hit_sphere = NULL; double diffuse, specular; point3 l, _l, r, rr; object_fill fill; color reflection_part; color refraction_part; /* might be a reflection ray, so check how many times we've bounced */ if (bounces_left == 0) { SET_COLOR(object_color, 0.0, 0.0, 0.0); return 0; } /* check for intersection with a sphere or a rectangular */ intersection ip= ray_hit_object(e, d, t, MAX_DISTANCE, rectangulars, &hit_rec, spheres, &hit_sphere); if (!hit_rec && !hit_sphere) return 0; /* pick the fill of the object that was hit */ fill = hit_rec ? hit_rec->element.rectangular_fill : hit_sphere->element.sphere_fill; void *hit_obj = hit_rec ? (void *) hit_rec : (void *) hit_sphere; /* assume it is a shadow */ SET_COLOR(object_color, 0.0, 0.0, 0.0); for (light_node light = lights; light; light = light->next) { /* calculate the intersection vector pointing at the light */ subtract_vector(ip.point, light->element.position, l); multiply_vector(l, -1, _l); normalize(_l); /* check for intersection with an object. use ignore_me * because we don't care about this normal */ ray_hit_object(ip.point, _l, MIN_DISTANCE, length(l), rectangulars, &light_hit_rec, spheres, &light_hit_sphere); /* the light was not block by itself(lit object) */ if (light_hit_rec || light_hit_sphere) continue; compute_specular_diffuse(&diffuse, &specular, d, l, ip.normal, fill.phong_power); localColor(object_color, light->element.light_color, diffuse, specular, &fill); } reflection(r, d, ip.normal); double idx = idx_stack_top(stk).idx, idx_pass = fill.index_of_refraction; if (idx_stack_top(stk).obj == hit_obj) { idx_stack_pop(stk); idx_pass = idx_stack_top(stk).idx; } else { idx_stack_element e = { .obj = hit_obj, .idx = fill.index_of_refraction }; idx_stack_push(stk, e); } refraction(rr, d, ip.normal, idx, idx_pass); double R = (fill.T > 0.1) ? fresnel(d, rr, ip.normal, idx, idx_pass) : 1.0; /* totalColor = localColor + mix((1-fill.Kd) * fill.R * reflection, T * refraction, R) */ if (fill.R > 0) { /* if we hit something, add the color */ int old_top = stk->top; if (ray_color(ip.point, MIN_DISTANCE, r, stk, rectangulars, spheres, lights, reflection_part, bounces_left - 1)) { multiply_vector(reflection_part, R * (1.0 - fill.Kd) * fill.R, reflection_part); add_vector(object_color, reflection_part, object_color); } stk->top = old_top; } /* calculate refraction ray */ if ((length(rr) > 0.0) && (fill.T > 0.0) && (fill.index_of_refraction > 0.0)) { normalize(rr); if (ray_color(ip.point, MIN_DISTANCE, rr, stk,rectangulars, spheres, lights, refraction_part, bounces_left - 1)) { multiply_vector(refraction_part, (1 - R) * fill.T, refraction_part); add_vector(object_color, refraction_part, object_color); } } protect_color_overflow(object_color); return 1; } static void *parallel (void* range1) { Thread_range *range = (Thread_range *)range1; point3 d; idx_stack stk; color object_color = { 0.0, 0.0, 0.0 }; for (int j = range->height1; j < range->height2; j++) { for (int i = 0; i < range->ptr->width; i++) { double r = 0, g = 0, b = 0; /* MSAA */ for (int s = 0; s < SAMPLES; s++) { idx_stack_init(&stk); rayConstruction(d, range->ptr->u, range->ptr->v, range->ptr->w, i * range->ptr->factor + s / range->ptr->factor, j * range->ptr->factor + s % range->ptr->factor, range->ptr->view, range->ptr->width * range->ptr->factor, range->ptr->height * range->ptr->factor); if (ray_color(range->ptr->view->vrp, 0.0, d, &(stk), range->ptr->rectangulars, range->ptr->spheres, range->ptr->lights, object_color, MAX_REFLECTION_BOUNCES)) { r += object_color[0]; g += object_color[1]; b += object_color[2]; } else { r += range->ptr->background_color[0]; g += range->ptr->background_color[1]; b += range->ptr->background_color[2]; } range->ptr->pixels[((i + (j * range->ptr->width)) * 3) + 0] = r * 255 / SAMPLES; range->ptr->pixels[((i + (j * range->ptr->width)) * 3) + 1] = g * 255 / SAMPLES; range->ptr->pixels[((i + (j * range->ptr->width)) * 3) + 2] = b * 255 / SAMPLES; } } } return NULL; }