static float4 CurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, int curvekey) { const float3 ickey_loc = CData->curvekey_co[curvekey]; const float curve_time = CData->curvekey_time[curvekey]; const float curve_length = CData->curve_length[curve]; float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f; float radius = shaperadius( CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); if (CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) radius = 0.0f; /* curve motion keys store both position and radius in float4 */ float4 mP = float3_to_float4(ickey_loc); mP.w = radius; return mP; }
static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) { int num_keys = 0; int num_curves = 0; if (mesh->num_curves()) return; Attribute *attr_intercept = NULL; Attribute *attr_random = NULL; if (mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT); if (mesh->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) attr_random = mesh->curve_attributes.add(ATTR_STD_CURVE_RANDOM); /* compute and reserve size of arrays */ for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { for (int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { num_keys += CData->curve_keynum[curve]; num_curves++; } } if (num_curves > 0) { VLOG(1) << "Exporting curve segments for mesh " << mesh->name; } mesh->reserve_curves(mesh->num_curves() + num_curves, mesh->curve_keys.size() + num_keys); num_keys = 0; num_curves = 0; /* actually export */ for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { for (int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { size_t num_curve_keys = 0; for (int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) { const float3 ickey_loc = CData->curvekey_co[curvekey]; const float curve_time = CData->curvekey_time[curvekey]; const float curve_length = CData->curve_length[curve]; const float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f; float radius = shaperadius( CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); if (CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) { radius = 0.0f; } mesh->add_curve_key(ickey_loc, radius); if (attr_intercept) attr_intercept->add(time); num_curve_keys++; } if (attr_random != NULL) { attr_random->add(hash_int_01(num_curves)); } mesh->add_curve(num_keys, CData->psys_shader[sys]); num_keys += num_curve_keys; num_curves++; } } /* check allocation */ if ((mesh->curve_keys.size() != num_keys) || (mesh->num_curves() != num_curves)) { VLOG(1) << "Allocation failed, clearing data"; mesh->clear(); } }
static void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, float3 RotCam, bool is_ortho) { int vertexno = mesh->verts.size(); int vertexindex = vertexno; int numverts = 0, numtris = 0; /* compute and reserve size of arrays */ for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { for (int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { numverts += 2 + (CData->curve_keynum[curve] - 1) * 2; numtris += (CData->curve_keynum[curve] - 1) * 2; } } mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); /* actually export */ for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { for (int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { float3 xbasis; float3 v1; float time = 0.0f; float3 ickey_loc = CData->curvekey_co[CData->curve_firstkey[curve]]; float radius = shaperadius( CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.0f); v1 = CData->curvekey_co[CData->curve_firstkey[curve] + 1] - CData->curvekey_co[CData->curve_firstkey[curve]]; if (is_ortho) xbasis = normalize(cross(RotCam, v1)); else xbasis = normalize(cross(RotCam - ickey_loc, v1)); float3 ickey_loc_shfl = ickey_loc - radius * xbasis; float3 ickey_loc_shfr = ickey_loc + radius * xbasis; mesh->add_vertex(ickey_loc_shfl); mesh->add_vertex(ickey_loc_shfr); vertexindex += 2; for (int curvekey = CData->curve_firstkey[curve] + 1; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) { ickey_loc = CData->curvekey_co[curvekey]; if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 1, CData->curve_firstkey[curve])]; else v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1]; time = CData->curvekey_time[curvekey] / CData->curve_length[curve]; radius = shaperadius( CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f); if (CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); if (is_ortho) xbasis = normalize(cross(RotCam, v1)); else xbasis = normalize(cross(RotCam - ickey_loc, v1)); float3 ickey_loc_shfl = ickey_loc - radius * xbasis; float3 ickey_loc_shfr = ickey_loc + radius * xbasis; mesh->add_vertex(ickey_loc_shfl); mesh->add_vertex(ickey_loc_shfr); mesh->add_triangle( vertexindex - 2, vertexindex, vertexindex - 1, CData->psys_shader[sys], true); mesh->add_triangle( vertexindex + 1, vertexindex - 1, vertexindex, CData->psys_shader[sys], true); vertexindex += 2; } } } mesh->resize_mesh(mesh->verts.size(), mesh->num_triangles()); mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); mesh->attributes.remove(ATTR_STD_FACE_NORMAL); mesh->add_face_normals(); mesh->add_vertex_normals(); mesh->attributes.remove(ATTR_STD_FACE_NORMAL); /* texture coords still needed */ }
static void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution) { int vertexno = mesh->verts.size(); int vertexindex = vertexno; int numverts = 0, numtris = 0; /* compute and reserve size of arrays */ for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { for (int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { numverts += (CData->curve_keynum[curve] - 1) * resolution + resolution; numtris += (CData->curve_keynum[curve] - 1) * 2 * resolution; } } mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); /* actually export */ for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { for (int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { float3 firstxbasis = cross(make_float3(1.0f, 0.0f, 0.0f), CData->curvekey_co[CData->curve_firstkey[curve] + 1] - CData->curvekey_co[CData->curve_firstkey[curve]]); if (!is_zero(firstxbasis)) firstxbasis = normalize(firstxbasis); else firstxbasis = normalize(cross(make_float3(0.0f, 1.0f, 0.0f), CData->curvekey_co[CData->curve_firstkey[curve] + 1] - CData->curvekey_co[CData->curve_firstkey[curve]])); for (int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { float3 xbasis = firstxbasis; float3 v1; float3 v2; if (curvekey == CData->curve_firstkey[curve]) { v1 = CData->curvekey_co[min( curvekey + 2, CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey + 1]; v2 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; } else if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; v2 = CData->curvekey_co[curvekey - 1] - CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])]; } else { v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; } xbasis = cross(v1, v2); if (len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { firstxbasis = normalize(xbasis); break; } } for (int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { int subv = 1; float3 xbasis; float3 ybasis; float3 v1; float3 v2; if (curvekey == CData->curve_firstkey[curve]) { subv = 0; v1 = CData->curvekey_co[min( curvekey + 2, CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey + 1]; v2 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; } else if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; v2 = CData->curvekey_co[curvekey - 1] - CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])]; } else { v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; } xbasis = cross(v1, v2); if (len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { xbasis = normalize(xbasis); firstxbasis = xbasis; } else xbasis = firstxbasis; ybasis = normalize(cross(xbasis, v2)); for (; subv <= 1; subv++) { float3 ickey_loc = make_float3(0.0f, 0.0f, 0.0f); float time = 0.0f; InterpolateKeySegments(subv, 1, curvekey, curve, &ickey_loc, &time, CData); float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); if ((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == 1)) radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f); if (CData->psys_closetip[sys] && (subv == 1) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)) radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); float angle = M_2PI_F / (float)resolution; for (int section = 0; section < resolution; section++) { float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis); mesh->add_vertex(ickey_loc_shf); } if (subv != 0) { for (int section = 0; section < resolution - 1; section++) { mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], true); mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], true); } mesh->add_triangle(vertexindex - 1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], true); mesh->add_triangle(vertexindex, vertexindex - resolution, vertexindex + resolution - 1, CData->psys_shader[sys], true); } vertexindex += resolution; } } } } mesh->resize_mesh(mesh->verts.size(), mesh->num_triangles()); mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); mesh->attributes.remove(ATTR_STD_FACE_NORMAL); mesh->add_face_normals(); mesh->add_vertex_normals(); mesh->attributes.remove(ATTR_STD_FACE_NORMAL); /* texture coords still needed */ }
static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int motion_step) { VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name << ", motion step " << motion_step; /* find attribute */ Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); bool new_attribute = false; /* add new attribute if it doesn't exist already */ if(!attr_mP) { VLOG(1) << "Creating new motion vertex position attribute"; attr_mP = mesh->curve_attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); new_attribute = true; } /* export motion vectors for curve keys */ size_t numkeys = mesh->curve_keys.size(); float4 *mP = attr_mP->data_float4() + motion_step*numkeys; bool have_motion = false; int i = 0; for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { if(CData->psys_curvenum[sys] == 0) continue; for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f) continue; for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) { if(i < mesh->curve_keys.size()) { float3 ickey_loc = CData->curvekey_co[curvekey]; float time = CData->curvekey_time[curvekey]/CData->curve_length[curve]; float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) radius = 0.0f; /* curve motion keys store both position and radius in float4 */ mP[i] = float3_to_float4(ickey_loc); mP[i].w = radius; /* unlike mesh coordinates, these tend to be slightly different * between frames due to particle transforms into/out of object * space, so we use an epsilon to detect actual changes */ float4 curve_key = float3_to_float4(mesh->curve_keys[i]); curve_key.w = mesh->curve_radius[i]; if(len_squared(mP[i] - curve_key) > 1e-5f*1e-5f) have_motion = true; } i++; } } } /* in case of new attribute, we verify if there really was any motion */ if(new_attribute) { if(i != numkeys || !have_motion) { /* No motion or hair "topology" changed, remove attributes again. */ if(i != numkeys) { VLOG(1) << "Hair topology changed, removing attribute."; } else { VLOG(1) << "No motion, removing attribute."; } mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); } else if(motion_step > 0) { VLOG(1) << "Filling in new motion vertex position for motion_step " << motion_step; /* motion, fill up previous steps that we might have skipped because * they had no motion, but we need them anyway now */ for(int step = 0; step < motion_step; step++) { float4 *mP = attr_mP->data_float4() + step*numkeys; for(int key = 0; key < numkeys; key++) { mP[key] = float3_to_float4(mesh->curve_keys[key]); mP[key].w = mesh->curve_radius[key]; } } } } }