diff --git a/Base/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp b/Base/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..81a3fb46f4afc02cad64f67044c688624419e33d
--- /dev/null
+++ b/Base/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.cpp
@@ -0,0 +1,279 @@
+/*=========================================================================
+
+Library: iMSTK
+
+Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+& Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0.txt
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+=========================================================================*/
+
+#include "imstkPbdConstantDensityConstraint.h"
+#include "imstkPbdModel.h"
+
+namespace imstk
+{
+
+void
+PbdConstantDensityConstraint::initConstraint(PbdModel& model, const double k)
+{
+    auto state = model.getCurrentState();
+    auto np = state->getPositions().size();
+
+    //constraint parameters
+    m_maxNumNeighbors = 100;
+    m_maxDist = 0.2;
+    m_relaxationParameter = 600.0;
+    m_restDensity = 6378.0;
+    m_wPoly6Coeff = 315.0 / (64.0 * PI * pow(m_maxDist, 9));
+    m_wSpikyCoeff = 15.0 / (PI * pow(m_maxDist, 6));
+
+    m_lambdas.resize(np);
+    m_densities.resize(np);
+    m_numNeighbors.resize(np);
+    m_deltaPositions.resize(np);
+    m_neighbors.resize(np * m_maxNumNeighbors);
+
+	m_xPosIndexes.resize(np);
+	m_yPosIndexes.resize(np);
+	m_zPosIndexes.resize(np);
+}
+
+bool
+PbdConstantDensityConstraint::solvePositionConstraint(PbdModel& model)
+{
+    auto state = model.getCurrentState();
+    auto& pos = state->getPositions();
+    auto np = pos.size();
+
+    ClearNeighbors(np);
+
+    //This loop should be replaced with parallellization
+    /*for (int index = 0; index < np; index++)
+	{
+		PointTable(pos[index], index);
+	}*/
+	for (int index = 0; index < np; index++)
+	{
+		//UpdateNeighbors(index, pos);
+		UpdateNeighborsBruteForce(pos[index], index, pos);
+	}
+    for (int index = 0; index < np; index++)
+    {
+        CalculateDensityEstimate(pos[index], index, pos);
+    }
+    for (int index = 0; index < np; index++)
+    {
+        CalculateLambdaScalingFactor(pos[index], index, pos);
+    }
+    for (int index = 0; index < np; index++)
+    {
+        DeltaPosition(pos[index], index, pos);
+    }
+
+    for (int index = 0; index < np; index++)
+    {
+        UpdatePositions(pos[index], index);
+    }
+
+    return true;
+}
+
+//Smoothing Kernal WPoly6 for density estimation
+inline double
+PbdConstantDensityConstraint::WPoly6(const Vec3d &pi, const Vec3d &pj)
+{
+    Vec3d r = pi - pj;
+    double rLength = Length(r);
+    if (rLength > m_maxDist || rLength == 0)
+    {
+        return 0;
+    }
+
+    return m_wPoly6Coeff * pow((m_maxDist * m_maxDist) - (rLength * rLength), 3);
+}
+
+//Smoothing Kernal Spiky for gradient calculation
+inline double
+PbdConstantDensityConstraint::WSpiky(const Vec3d &pi, const Vec3d &pj)
+{
+    Vec3d r = pi - pj;
+    double rLength = Length(r);
+    if (rLength > m_maxDist || rLength == 0)
+    {
+        return 0;
+    }
+
+    return m_wSpikyCoeff * pow(m_maxDist - rLength, 3);
+}
+
+inline Vec3d
+PbdConstantDensityConstraint::GradSpiky(const Vec3d &pi, const Vec3d &pj)
+{
+    Vec3d r = pi - pj;
+    Vec3d zero;
+    zero[0] = 0;
+    zero[1] = 0;
+    zero[2] = 0;
+    double rLength = Length(r);
+    if (rLength > m_maxDist || rLength == 0)
+    {
+        return zero;
+    }
+
+    return r * (m_wSpikyCoeff * (-3.0) * (m_maxDist - rLength) * (m_maxDist - rLength));
+}
+
+inline double
+PbdConstantDensityConstraint::Length(const Vec3d &p1)
+{
+    return sqrt(p1[0] * p1[0] + p1[1] * p1[1] + p1[2] * p1[2]);
+}
+
+inline void
+PbdConstantDensityConstraint::ClearNeighbors(const int &np)
+{
+	m_numNeighbors.clear();
+	m_neighbors.clear();
+	m_numNeighbors.resize(np);
+	m_neighbors.resize(np * m_maxNumNeighbors);
+}
+
+inline void 
+PbdConstantDensityConstraint::PointTable(const Vec3d &pi, const int &index)
+{
+	m_xPosIndexes[index] = (pi[0] - pi[0] * m_maxDist) / m_maxDist;
+	m_yPosIndexes[index] = (pi[1] - pi[1] * m_maxDist) / m_maxDist;
+	m_zPosIndexes[index] = (pi[2] - pi[2] * m_maxDist) / m_maxDist;
+}
+
+inline void 
+PbdConstantDensityConstraint::UpdateNeighbors(const int &index, const StdVectorOfVec3d &positions)
+{
+	int ip = m_xPosIndexes[index];
+	int jp = m_yPosIndexes[index];
+	int kp = m_zPosIndexes[index];
+
+	int np = m_zPosIndexes.size();
+	int neighborCount = 0;
+
+	int ibound = ip - 2;
+	if (ibound < 0)
+		ibound = 0;
+	int jbound = jp - 2;
+	if (jbound < 0)
+		jbound = 0;
+	int kbound = kp - 2;
+	if (kbound < 0)
+		kbound = 0;
+	for (int i = 0; i < np; i++)
+	{
+		if (neighborCount >= m_maxNumNeighbors || i == index)
+			continue;
+		if (m_xPosIndexes[i] > ibound && m_xPosIndexes[i] < (ip + 2))
+		{
+			if (m_yPosIndexes[i] > jbound && m_yPosIndexes[i] < (jp + 2))
+			{
+				if (m_zPosIndexes[i] > kbound && m_zPosIndexes[i] < (kp + 2))
+				{
+					m_neighbors[index * m_maxNumNeighbors + neighborCount] = i;
+					neighborCount++;
+				}
+			}	
+		}
+	}
+	m_numNeighbors[index] = neighborCount;
+}
+
+//brute Force
+inline 
+void PbdConstantDensityConstraint::UpdateNeighborsBruteForce(const Vec3d &pi, const int &index, const StdVectorOfVec3d &positions)
+{
+	double neighborRadius = 2 * m_maxDist;
+	Vec3d r;
+	double rLength;
+	int neighborCount = 0;
+	//loop over all points
+	for (int j = 0; j < positions.size(); j++)
+	{
+		if (j != index)
+		{
+			if (neighborCount >= m_maxNumNeighbors)
+				continue;
+			r = pi - positions[j];
+			rLength = Length(r);
+			if (rLength < neighborRadius)
+			{
+				m_neighbors[index * m_maxNumNeighbors + neighborCount] = j;
+				neighborCount++;
+			}
+		}
+	}
+	m_numNeighbors[index] = neighborCount;
+}
+
+
+inline void
+PbdConstantDensityConstraint::CalculateDensityEstimate(const Vec3d &pi, const int &index, const StdVectorOfVec3d &positions)
+{
+    double densitySum = 0.0;
+    for (int j = 0; j < m_numNeighbors[index]; j++)
+    {
+        densitySum += WPoly6(pi, positions[m_neighbors[index * m_maxNumNeighbors + j]]);
+    }
+
+    m_densities[index] = densitySum;
+}
+
+inline void
+PbdConstantDensityConstraint::CalculateLambdaScalingFactor(const Vec3d &pi, const int &index, const StdVectorOfVec3d &positions)
+{
+    double densityConstraint = (m_densities[index] / m_restDensity) - 1;
+    double gradientSum = 0.0;
+    for (int j = 0; j < m_numNeighbors[index]; j++)
+    {
+        gradientSum += pow(Length(GradSpiky(pi, positions[m_neighbors[index * m_maxNumNeighbors + j]])), 2) / m_restDensity;
+    }
+
+    m_lambdas[index] = densityConstraint / (gradientSum + m_relaxationParameter);
+}
+
+inline void
+PbdConstantDensityConstraint::DeltaPosition(const Vec3d &pi, const int &index, const StdVectorOfVec3d &positions)
+{
+    //Make sure the point is valid
+    Vec3d gradientLambdaSum;
+    gradientLambdaSum[0] = 0;
+    gradientLambdaSum[1] = 0;
+    gradientLambdaSum[2] = 0;
+    for (int j = 0; j < m_numNeighbors[index]; j++)
+    {
+        int neighborInd = m_neighbors[index * m_maxNumNeighbors + j];
+        double lambdasDiff = (m_lambdas[index] + m_lambdas[m_neighbors[index * m_maxNumNeighbors + j]]);
+        Vec3d gradKernal = GradSpiky(pi, positions[m_neighbors[index * m_maxNumNeighbors + j]]);
+        gradientLambdaSum += (gradKernal * lambdasDiff);
+    }
+
+    m_deltaPositions[index] = gradientLambdaSum / m_restDensity;
+}
+
+inline void
+PbdConstantDensityConstraint::UpdatePositions(Vec3d &pi, const int &index)
+{
+    //Make sure the point is valid
+    pi[0] += m_deltaPositions[index][0];
+    pi[1] += m_deltaPositions[index][1];
+    pi[2] += m_deltaPositions[index][2];
+}
+} // imstk
\ No newline at end of file
diff --git a/Base/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h b/Base/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h
new file mode 100644
index 0000000000000000000000000000000000000000..35bd739db5bccee827b0c487e71c119db601dc97
--- /dev/null
+++ b/Base/Constraint/PbdConstraints/imstkPbdConstantDensityConstraint.h
@@ -0,0 +1,86 @@
+/*=========================================================================
+
+Library: iMSTK
+
+Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+& Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0.txt
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+=========================================================================*/
+
+#ifndef imstkPbdConstantDensityConstraint_h
+#define imstkPbdConstantDensityConstraint_h
+
+#include "imstkPbdConstraint.h"
+#include "../Collision/CollisionDetection/DataStructures/imstkSpatialHashTableSeparateChaining.h"
+
+namespace imstk
+{
+class PbdConstantDensityConstraint : public PbdConstraint
+{
+public:
+    ///
+    /// \brief constructor
+    ///
+    PbdConstantDensityConstraint() : PbdConstraint() { m_vertexIds.resize(1); }
+    ///
+    /// \Constant Density Constraint Initialization
+    ///
+    void initConstraint(PbdModel& model, const double k);
+
+    ///
+    /// \brief Returns PBD constraint of type Type::ConstantDensity
+    ///
+    Type getType() const { return Type::ConstantDensity; }
+
+    ///
+    /// \brief Solves the constant density constraint
+    ///
+    bool solvePositionConstraint(PbdModel &model);
+
+private:
+    double WPoly6(const Vec3d &pi, const Vec3d &pj);
+    double WSpiky(const Vec3d &pi, const Vec3d &pj);
+    Vec3d GradSpiky(const Vec3d &pi, const Vec3d &pj);
+    double Length(const Vec3d &);
+
+    void PointTable(const Vec3d &pi, const int &index);
+	void UpdateNeighbors(const int &index, const StdVectorOfVec3d &positions);
+	void UpdateNeighborsBruteForce(const Vec3d &pi, const int &index, const StdVectorOfVec3d &positions);
+	void ClearNeighbors(const int &np);
+    void CalculateDensityEstimate(const Vec3d &pi, const int &index, const StdVectorOfVec3d &positions);
+    void CalculateLambdaScalingFactor(const Vec3d &pi, const int &index, const StdVectorOfVec3d &positions);
+    void DeltaPosition(const Vec3d &pi, const int &index, const StdVectorOfVec3d &positions);
+    void UpdatePositions(Vec3d &pi, const int &index);
+
+private:
+    double m_wPoly6Coeff;
+    double m_wSpikyCoeff;
+    double m_maxDist;
+    double m_relaxationParameter;
+    double m_restDensity;
+    int m_maxNumNeighbors;
+
+    std::vector<double> m_lambdas;             ///> lambdas
+    std::vector<double> m_densities;           ///> densities
+    std::vector<Vec3d> m_deltaPositions;       ///> delta positions
+    std::vector<int> m_neighbors;              ///> index of neighbors
+    std::vector<int> m_numNeighbors;           ///> number of neighbors
+	std::vector<int> m_xPosIndexes;
+	std::vector<int> m_yPosIndexes;
+	std::vector<int> m_zPosIndexes;
+};
+}
+
+#endif // imstkPbdConstantDensityConstraint_h