public Winding addBackface() { if (verts.isEmpty()) { return this; } List<Vector3f> vertsNew = new ArrayList<>(); final int size = verts.size(); for (int i = 0; i < size; i++) { if (i != 0) { vertsNew.add(verts.get(i)); } if (i != size) { vertsNew.add(verts.get(i)); } } return new Winding(vertsNew); }
/** * Clips this winding to a plane defined by a normal and distance, removing all vertices in front * or behind it. * * <p>Equals ClipWindingEpsilon() in polylib.cpp * * @param normal plane normal * @param dist plane distance to origin * @param eps clipping epsilon * @param back keep vertices behind the plane? */ public Winding clipEpsilon(Vector3f normal, float dist, float eps, boolean back) { // counts number of front, back and on vertices int[] counts = new int[] {0, 0, 0}; final int size = verts.size(); float[] dists = new float[size + 1]; int[] sides = new int[size + 1]; // determine sides for each point for (int i = 0; i < size; i++) { // distance along norm-dirn from origin to vertex float dot = verts.get(i).dot(normal); // distance along norm-dirn from clip plane to vertex dot -= dist; // store it dists[i] = dot; if (dot > eps) { // vertex in front of plane sides[i] = SIDE_FRONT; } else if (dot < -eps) { // vertex behind plane sides[i] = SIDE_BACK; } else { // vertex on plane (within epsilon) sides[i] = SIDE_ON; } // count relative vertex positions counts[sides[i]]++; } sides[size] = sides[0]; // loop around to 0'th dists[size] = dists[0]; if (counts[SIDE_FRONT] == 0) { // no vertices in front - all behind clip plane if (!back) { return EMPTY; } else { return this; } } if (counts[SIDE_BACK] == 0) { // no vertices in back - all in front of clip plane if (back) { return EMPTY; } else { return this; } } List<Vector3f> vertsNew = new ArrayList<Vector3f>(); for (int i = 0; i < size; i++) { // get i'th vertex Vector3f p1 = verts.get(i); if (sides[i] == SIDE_ON) { vertsNew.add(p1); continue; } if (sides[i] == SIDE_FRONT && !back) { // add copy the current vertex vertsNew.add(p1); } if (sides[i] == SIDE_BACK && back) { // add copy the current vertex vertsNew.add(p1); } if (sides[i + 1] == SIDE_ON) { // next vertex is on the plane, so go to next vertex stat continue; } if (sides[i + 1] == sides[i]) { // next vertex does not change side, so go to next vertex stat continue; } // otherwise, we are crossing the clip plane between this vertex and the next // so generate a split point // will contain the next vertex position Vector3f p2; if (i == size - 1) { // we're the last vertex in the winding // next vertex is the 0'th one p2 = verts.get(0); } else { // else get the next vertex p2 = verts.get(i + 1); } // dot is fractional position of clip plane between // this vertex and the next float dot = dists[i] / (dists[i] - dists[i + 1]); // vector of the split vertex Vector3f mv = Vector3f.NULL; for (int j = 0; j < normal.size; j++) { // avoid round off error when possible if (normal.get(j) == 1) { mv = mv.set(j, dist); } else if (normal.get(j) == -1) { mv = mv.set(j, -dist); } else { // check it! MSH mv = mv.set(j, p1.get(j) + dot * (p2.get(j) - p1.get(j))); } } // write the output vertex vertsNew.add(mv); } return new Winding(vertsNew); }