/** * Calculates the minimum bounding sphere of 4 points. Used in welzl's algorithm. * * @param O The 1st point inside the sphere. * @param A The 2nd point inside the sphere. * @param B The 3rd point inside the sphere. * @param C The 4th point inside the sphere. * @see #calcWelzl(java.nio.FloatBuffer) */ private void setSphere(final Vector3 O, final Vector3 A, final Vector3 B, final Vector3 C) { final Vector3 a = A.subtract(O, null); final Vector3 b = B.subtract(O, null); final Vector3 c = C.subtract(O, null); final double Denominator = 2.0 * (a.getX() * (b.getY() * c.getZ() - c.getY() * b.getZ()) - b.getX() * (a.getY() * c.getZ() - c.getY() * a.getZ()) + c.getX() * (a.getY() * b.getZ() - b.getY() * a.getZ())); if (Denominator == 0) { _center.set(0, 0, 0); setRadius(0); } else { final Vector3 o = a.cross(b, null) .multiplyLocal(c.lengthSquared()) .addLocal(c.cross(a, null).multiplyLocal(b.lengthSquared())) .addLocal(b.cross(c, null).multiplyLocal(a.lengthSquared())) .divideLocal(Denominator); setRadius(o.length() * radiusEpsilon); O.add(o, _center); } }
@Override public void startWalk(final Ray3 walkRay) { // store ray _walkRay.set(walkRay); // simplify access to direction final ReadOnlyVector3 direction = _walkRay.getDirection(); // Move start point to grid space final Vector3 start = _walkRay.getOrigin().subtract(_gridOrigin, null); _gridLocation[0] = (int) MathUtils.floor(start.getX() / _gridSpacing.getX()); _gridLocation[1] = (int) MathUtils.floor(start.getY() / _gridSpacing.getY()); final double invDirX = 1.0 / direction.getX(); final double invDirY = 1.0 / direction.getY(); // Check which direction on the X world axis we are moving. if (direction.getX() > BresenhamZUpGridTracer.TOLERANCE) { _distToNextXIntersection = ((_gridLocation[0] + 1) * _gridSpacing.getX() - start.getX()) * invDirX; _distBetweenXIntersections = _gridSpacing.getX() * invDirX; _stepXDirection = 1; } else if (direction.getX() < -BresenhamZUpGridTracer.TOLERANCE) { _distToNextXIntersection = (start.getX() - _gridLocation[0] * _gridSpacing.getX()) * -direction.getX(); _distBetweenXIntersections = -_gridSpacing.getX() * invDirX; _stepXDirection = -1; } else { _distToNextXIntersection = Double.MAX_VALUE; _distBetweenXIntersections = Double.MAX_VALUE; _stepXDirection = 0; } // Check which direction on the Y world axis we are moving. if (direction.getY() > BresenhamZUpGridTracer.TOLERANCE) { _distToNextYIntersection = ((_gridLocation[1] + 1) * _gridSpacing.getY() - start.getY()) * invDirY; _distBetweenYIntersections = _gridSpacing.getY() * invDirY; _stepYDirection = 1; } else if (direction.getY() < -BresenhamZUpGridTracer.TOLERANCE) { _distToNextYIntersection = (start.getY() - _gridLocation[1] * _gridSpacing.getY()) * -direction.getY(); _distBetweenYIntersections = -_gridSpacing.getY() * invDirY; _stepYDirection = -1; } else { _distToNextYIntersection = Double.MAX_VALUE; _distBetweenYIntersections = Double.MAX_VALUE; _stepYDirection = 0; } // Reset some variables _rayLocation.set(start); _totalTravel = 0.0; _stepDirection = Direction.None; }
@Override public void applyFilter(final InteractManager manager) { final SpatialState state = manager.getSpatialState(); final ReadOnlyVector3 scale = state.getTransform().getScale(); final double x = MathUtils.clamp(scale.getX(), _minScale.getX(), _maxScale.getX()); final double y = MathUtils.clamp(scale.getY(), _minScale.getY(), _maxScale.getY()); final double z = MathUtils.clamp(scale.getZ(), _minScale.getZ(), _maxScale.getZ()); state.getTransform().setScale(x, y, z); }
/** * Calculates the minimum bounding sphere of 2 points. Used in welzl's algorithm. * * @param O The 1st point inside the sphere. * @param A The 2nd point inside the sphere. * @see #calcWelzl(java.nio.FloatBuffer) */ private void setSphere(final Vector3 O, final Vector3 A) { setRadius( Math.sqrt( ((A.getX() - O.getX()) * (A.getX() - O.getX()) + (A.getY() - O.getY()) * (A.getY() - O.getY()) + (A.getZ() - O.getZ()) * (A.getZ() - O.getZ())) / 4f) + radiusEpsilon - 1); Vector3.lerp(O, A, .5, _center); }
/** Defines the normals of each face of the pyramid. */ protected void setNormalData() { Vector3 normal = new Vector3(); Vector3 work = new Vector3(); FloatBuffer norms = BufferUtils.createVector3Buffer(12); // side 1 MathUtil.createNormal(normal, vert0, vert1, peak, work); norms.put((float) normal.getX()).put((float) normal.getY()).put((float) normal.getZ()); norms.put((float) normal.getX()).put((float) normal.getY()).put((float) normal.getZ()); norms.put((float) normal.getX()).put((float) normal.getY()).put((float) normal.getZ()); // side 2 MathUtil.createNormal(normal, vert1, vert2, peak, work); norms.put((float) normal.getX()).put((float) normal.getY()).put((float) normal.getZ()); norms.put((float) normal.getX()).put((float) normal.getY()).put((float) normal.getZ()); norms.put((float) normal.getX()).put((float) normal.getY()).put((float) normal.getZ()); // side 3 MathUtil.createNormal(normal, vert2, vert3, peak, work); norms.put((float) normal.getX()).put((float) normal.getY()).put((float) normal.getZ()); norms.put((float) normal.getX()).put((float) normal.getY()).put((float) normal.getZ()); norms.put((float) normal.getX()).put((float) normal.getY()).put((float) normal.getZ()); // side 4 MathUtil.createNormal(normal, vert3, vert0, peak, work); norms.put((float) normal.getX()).put((float) normal.getY()).put((float) normal.getZ()); norms.put((float) normal.getX()).put((float) normal.getY()).put((float) normal.getZ()); norms.put((float) normal.getX()).put((float) normal.getY()).put((float) normal.getZ()); norms.rewind(); sides.getMeshData().setNormalBuffer(norms); }
@Override public void setLocation(double x, double y, double z, boolean doEdit) { super.setLocation(x - offset.getX(), y - offset.getY(), z - offset.getZ(), doEdit); }
/** * Update the vertices for this particle, taking size, spin and viewer into consideration. In the * case of particle type ParticleType.GeomMesh, the original triangle normal is maintained rather * than rotating it to face the camera or parent vectors. * * @param cam Camera to use in determining viewer aspect. If null, or if parent is not set to * camera facing, parent's left and up vectors are used. */ public void updateVerts(final Camera cam) { final double orient = parent.getParticleOrientation() + values[VAL_CURRENT_SPIN]; final double currSize = values[VAL_CURRENT_SIZE]; if (type == ParticleSystem.ParticleType.GeomMesh || type == ParticleSystem.ParticleType.Point) {; // nothing to do } else if (cam != null && parent.isCameraFacing()) { final ReadOnlyVector3 camUp = cam.getUp(); final ReadOnlyVector3 camLeft = cam.getLeft(); final ReadOnlyVector3 camDir = cam.getDirection(); if (parent.isVelocityAligned()) { bbX.set(_velocity).normalizeLocal().multiplyLocal(currSize); camDir.cross(bbX, bbY).normalizeLocal().multiplyLocal(currSize); } else if (orient == 0) { bbX.set(camLeft).multiplyLocal(currSize); bbY.set(camUp).multiplyLocal(currSize); } else { final double cA = MathUtils.cos(orient) * currSize; final double sA = MathUtils.sin(orient) * currSize; bbX.set(camLeft) .multiplyLocal(cA) .addLocal(camUp.getX() * sA, camUp.getY() * sA, camUp.getZ() * sA); bbY.set(camLeft) .multiplyLocal(-sA) .addLocal(camUp.getX() * cA, camUp.getY() * cA, camUp.getZ() * cA); } } else { bbX.set(parent.getLeftVector()).multiplyLocal(0); bbY.set(parent.getUpVector()).multiplyLocal(0); } final Vector3 tempVec3 = Vector3.fetchTempInstance(); final FloatBuffer vertexBuffer = parent.getParticleGeometry().getMeshData().getVertexBuffer(); switch (type) { case Quad: { _position.subtract(bbX, tempVec3).subtractLocal(bbY); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 0); _position.subtract(bbX, tempVec3).addLocal(bbY); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 1); _position.add(bbX, tempVec3).addLocal(bbY); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 2); _position.add(bbX, tempVec3).subtractLocal(bbY); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 3); break; } case GeomMesh: { final Quaternion tempQuat = Quaternion.fetchTempInstance(); final ReadOnlyVector3 norm = triModel.getNormal(); if (orient != 0) { tempQuat.fromAngleNormalAxis(orient, norm); } for (int x = 0; x < 3; x++) { if (orient != 0) { tempQuat.apply(triModel.get(x), tempVec3); } else { tempVec3.set(triModel.get(x)); } tempVec3.multiplyLocal(currSize).addLocal(_position); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + x); } Quaternion.releaseTempInstance(tempQuat); break; } case Triangle: { _position .subtract(3 * bbX.getX(), 3 * bbX.getY(), 3 * bbX.getZ(), tempVec3) .subtractLocal(bbY); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 0); _position.add(bbX, tempVec3).addLocal(3 * bbY.getX(), 3 * bbY.getY(), 3 * bbY.getZ()); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 1); _position.add(bbX, tempVec3).subtractLocal(bbY); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 2); break; } case Line: { _position.subtract(bbX, tempVec3); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex); _position.add(bbX, tempVec3); BufferUtils.setInBuffer(tempVec3, vertexBuffer, startIndex + 1); break; } case Point: { BufferUtils.setInBuffer(_position, vertexBuffer, startIndex); break; } } Vector3.releaseTempInstance(tempVec3); }
/** * Sets the vertices that make the pyramid. Where the center of the box is the origin and the base * and height are set during construction. */ protected void setVertexData() { peak = new Vector3(0, 0, 0); vert0 = new Vector3(-width / 2, -height / 2, -length); vert1 = new Vector3(width / 2, -height / 2, -length); vert2 = new Vector3(width / 2, height / 2, -length); vert3 = new Vector3(-width / 2, height / 2, -length); FloatBuffer verts = BufferUtils.createVector3Buffer(12); // side 1 verts.put((float) vert0.getX()).put((float) vert0.getY()).put((float) vert0.getZ()); verts.put((float) vert1.getX()).put((float) vert1.getY()).put((float) vert1.getZ()); verts.put((float) peak.getX()).put((float) peak.getY()).put((float) peak.getZ()); // side 2 verts.put((float) vert1.getX()).put((float) vert1.getY()).put((float) vert1.getZ()); verts.put((float) vert2.getX()).put((float) vert2.getY()).put((float) vert2.getZ()); verts.put((float) peak.getX()).put((float) peak.getY()).put((float) peak.getZ()); // side 3 verts.put((float) vert2.getX()).put((float) vert2.getY()).put((float) vert2.getZ()); verts.put((float) vert3.getX()).put((float) vert3.getY()).put((float) vert3.getZ()); verts.put((float) peak.getX()).put((float) peak.getY()).put((float) peak.getZ()); // side 4 verts.put((float) vert3.getX()).put((float) vert3.getY()).put((float) vert3.getZ()); verts.put((float) vert0.getX()).put((float) vert0.getY()).put((float) vert0.getZ()); verts.put((float) peak.getX()).put((float) peak.getY()).put((float) peak.getZ()); verts.rewind(); sides.getMeshData().setVertexBuffer(verts); }