Using NURBS to interpolate patch vertex positions.

This commit is contained in:
kbladin
2016-04-07 15:25:33 -04:00
parent f9a98a2d2a
commit 16349686d5
5 changed files with 265 additions and 29 deletions

View File

@@ -50,7 +50,7 @@ namespace {
namespace openspace {
ClipMapGlobe::ClipMapGlobe(const ghoul::Dictionary& dictionary)
: _patch(10, 10, 0, 0, M_PI / 6, M_PI / 6)
: _patch(20, 20, 0, 0, M_PI / 4, M_PI / 4)
, _rotation("rotation", "Rotation", 0, 0, 360)
{
std::string name;

View File

@@ -168,7 +168,7 @@ void Geometry::drawUsingActiveProgram() {
glBindVertexArray(_vaoID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _elementBufferID);
glDrawElements(GL_TRIANGLES, _elementData.size(), GL_UNSIGNED_INT, 0);
glDrawElements(GL_LINES, _elementData.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}

View File

@@ -112,36 +112,48 @@ namespace openspace {
// TODO : Need to get the radius of the globe
double r = 6e6;
// Create control points (double)
glm::dvec3 p00, p01, p10, p11;
// Create control points and normals(double)
glm::dvec3 p00, p01, p02, p10, p11, p12, p20, p21, p22;
glm::dvec3 n00, n01, n02, n10, n11, n12, n20, n21, n22;
// Calculate global positions of control points
p00 = glm::dvec3(converter::latLonToCartesian(
_posLatLon.x - _sizeLatLon.x,
_posLatLon.y - _sizeLatLon.y,
r));
p10 = glm::dvec3(converter::latLonToCartesian(
_posLatLon.x + _sizeLatLon.x,
_posLatLon.y - _sizeLatLon.y,
r));
p01 = glm::dvec3(converter::latLonToCartesian(
_posLatLon.x - _sizeLatLon.x,
_posLatLon.y + _sizeLatLon.y,
r));
p11 = glm::dvec3(converter::latLonToCartesian(
_posLatLon.x + _sizeLatLon.x,
_posLatLon.y + _sizeLatLon.y,
r));
// Calculate positions of corner control points
p00 = calculateCornerPointLeftBottom();
p20 = calculateCornerPointRightBottom();
p02 = calculateCornerPointLeftTop();
p22 = calculateCornerPointRightTop();
// Get position of center control points
p01 = calculateCenterPoint(p00, p02);
p21 = calculateCenterPoint(p20, p22);
p10 = calculateCenterPoint(p00, p20);
p12 = calculateCenterPoint(p02, p22);
p11 = calculateCenterPoint(p01, p21);
// Calculate normals from control point positions
n00 = normalize(p00);
n01 = normalize(p01);
n02 = normalize(p02);
n10 = normalize(p10);
n11 = normalize(p11);
n12 = normalize(p12);
n20 = normalize(p20);
n21 = normalize(p21);
n22 = normalize(p22);
// TODO : Transformation to world space from model space should also consider
// rotations. Now it only uses translatation for simplicity. Should be done
// With a matrix transform
// TODO : Normals should also be transformed
glm::dvec3 position = data.position.dvec3();
p00 += position;
p10 += position;
p20 += position;
p01 += position;
p11 += position;
p21 += position;
p02 += position;
p12 += position;
p22 += position;
// Calculate global position of camera
// TODO : Should only need to fetch the camera transform and use directly
// Now the viewTransform is wrong due to the constant lookUpVector
@@ -155,19 +167,48 @@ namespace openspace {
// Transform control points to camera space
p00 = glm::dvec3(viewTransform * glm::dvec4(p00, 1.0));
p10 = glm::dvec3(viewTransform * glm::dvec4(p10, 1.0));
p20 = glm::dvec3(viewTransform * glm::dvec4(p20, 1.0));
p01 = glm::dvec3(viewTransform * glm::dvec4(p01, 1.0));
p11 = glm::dvec3(viewTransform * glm::dvec4(p11, 1.0));
p21 = glm::dvec3(viewTransform * glm::dvec4(p21, 1.0));
p02 = glm::dvec3(viewTransform * glm::dvec4(p02, 1.0));
p12 = glm::dvec3(viewTransform * glm::dvec4(p12, 1.0));
p22 = glm::dvec3(viewTransform * glm::dvec4(p22, 1.0));
// Send control points to GPU to be used in shader
// TODO : Will need more control points or possibly normals to be able to
// do better than linear interpolation
// Transform normals to camera space
n00 = glm::dvec3(viewTransform * glm::dvec4(n00, 0.0));
n10 = glm::dvec3(viewTransform * glm::dvec4(n10, 0.0));
n20 = glm::dvec3(viewTransform * glm::dvec4(n20, 0.0));
n01 = glm::dvec3(viewTransform * glm::dvec4(n01, 0.0));
n11 = glm::dvec3(viewTransform * glm::dvec4(n11, 0.0));
n21 = glm::dvec3(viewTransform * glm::dvec4(n21, 0.0));
n02 = glm::dvec3(viewTransform * glm::dvec4(n02, 0.0));
n12 = glm::dvec3(viewTransform * glm::dvec4(n12, 0.0));
n22 = glm::dvec3(viewTransform * glm::dvec4(n22, 0.0));
// Send control points and normals to GPU to be used in shader
_programObject->setUniform("p00", glm::vec3(p00));
_programObject->setUniform("p10", glm::vec3(p10));
_programObject->setUniform("p20", glm::vec3(p20));
_programObject->setUniform("p01", glm::vec3(p01));
_programObject->setUniform("p11", glm::vec3(p11));
_programObject->setUniform("p21", glm::vec3(p21));
_programObject->setUniform("p02", glm::vec3(p02));
_programObject->setUniform("p12", glm::vec3(p12));
_programObject->setUniform("p22", glm::vec3(p22));
_programObject->setUniform("n00", glm::vec3(n00));
_programObject->setUniform("n10", glm::vec3(n10));
_programObject->setUniform("n20", glm::vec3(n20));
_programObject->setUniform("n01", glm::vec3(n01));
_programObject->setUniform("n11", glm::vec3(n11));
_programObject->setUniform("n21", glm::vec3(n21));
_programObject->setUniform("n02", glm::vec3(n02));
_programObject->setUniform("n12", glm::vec3(n12));
_programObject->setUniform("n22", glm::vec3(n22));
_programObject->setUniform("Projection", data.camera.projectionMatrix());
// Render triangles (use texture coordinates to interpolate to new positions)
glDisable(GL_CULL_FACE);
//glCullFace(GL_BACK);
@@ -187,4 +228,50 @@ namespace openspace {
_posLatLon = posLatLon;
}
glm::dvec3 LatLonPatch::calculateCornerPointLeftBottom() {
double r = 6e6; // TODO : DEFINE r AS A MEMBER VARIABLE
return glm::dvec3(converter::latLonToCartesian(
_posLatLon.x - _sizeLatLon.x,
_posLatLon.y - _sizeLatLon.y,
r));
}
glm::dvec3 LatLonPatch::calculateCornerPointRightBottom() {
double r = 6e6; // TODO : DEFINE r AS A MEMBER VARIABLE
return glm::dvec3(converter::latLonToCartesian(
_posLatLon.x + _sizeLatLon.x,
_posLatLon.y - _sizeLatLon.y,
r));
}
glm::dvec3 LatLonPatch::calculateCornerPointLeftTop() {
double r = 6e6; // TODO : DEFINE r AS A MEMBER VARIABLE
return glm::dvec3(converter::latLonToCartesian(
_posLatLon.x - _sizeLatLon.x,
_posLatLon.y + _sizeLatLon.y,
r));
}
glm::dvec3 LatLonPatch::calculateCornerPointRightTop() {
double r = 6e6; // TODO : DEFINE r AS A MEMBER VARIABLE
return glm::dvec3(converter::latLonToCartesian(
_posLatLon.x + _sizeLatLon.x,
_posLatLon.y + _sizeLatLon.y,
r));
}
glm::dvec3 LatLonPatch::calculateCenterPoint(glm::dvec3 p0, glm::dvec3 p2) {
glm::dvec3 n0 = glm::normalize(p0);
glm::dvec3 n2 = glm::normalize(p2);
// Solution derived
glm::dvec2 u = glm::dvec2(0, glm::dot(p2, n2) - glm::dot(p0, n2));
double cosNormalAngle = glm::dot(n0, n2);
glm::dmat2 A = glm::dmat2({ 1, cosNormalAngle, cosNormalAngle, 1 });
glm::dvec2 stParam = glm::inverse(A) * u;
glm::dvec3 p1 = p0 + stParam.s * n0 + stParam.t * n2;
return p1;
}
} // namespace openspace

View File

@@ -61,6 +61,17 @@ namespace openspace {
void setPositionLatLon(glm::dvec2 posLatLon);
glm::dvec3 calculateCornerPointLeftBottom();
glm::dvec3 calculateCornerPointRightBottom();
glm::dvec3 calculateCornerPointLeftTop();
glm::dvec3 calculateCornerPointRightTop();
/**
Finds a third control point between the two parameter points assuming
they both lie on a sphere with the origin in the center.
*/
glm::dvec3 calculateCenterPoint(glm::dvec3 p0, glm::dvec3 p2);
private:
std::unique_ptr<ghoul::opengl::ProgramObject> _programObject;

View File

@@ -28,8 +28,23 @@ uniform mat4 Projection;
uniform vec3 p00;
uniform vec3 p10;
uniform vec3 p20;
uniform vec3 p01;
uniform vec3 p11;
uniform vec3 p21;
uniform vec3 p02;
uniform vec3 p12;
uniform vec3 p22;
uniform vec3 n00;
uniform vec3 n10;
uniform vec3 n20;
uniform vec3 n01;
uniform vec3 n11;
uniform vec3 n21;
uniform vec3 n02;
uniform vec3 n12;
uniform vec3 n22;
layout(location = 1) in vec2 in_UV;
@@ -37,12 +52,135 @@ out vec4 vs_position;
#include "PowerScaling/powerScaling_vs.hglsl"
void nurbsBasis(int c, float t, int npts, int x[7], inout float n[4])
{
int nplusc;
int i,k;
float d, e;
float temp[36];
nplusc = npts + c;
/* calculate the first order basis functions n[i][1] */
for (i = 1; i<= nplusc-1; i++){
if (( t >= x[i]) && (t < x[i+1]))
temp[i] = 1;
else
temp[i] = 0;
}
/* calculate the higher order basis functions */
for (k = 2; k <= c; k++){
for (i = 1; i <= nplusc-k; i++){
if (temp[i] != 0) /* if the lower order basis function is zero skip the calculation */
d = ((t-x[i])*temp[i])/(x[i+k-1]-x[i]);
else
d = 0;
if (temp[i+1] != 0) /* if the lower order basis function is zero skip the calculation */
e = ((x[i+k]-t)*temp[i+1])/(x[i+k]-x[i+1]);
else
e = 0;
temp[i] = d + e;
}
}
float floatXnplusc = x[nplusc];
if (t == floatXnplusc){ /* pick up last point */
temp[npts] = 1;
}
/* put in n array */
for (i = 1; i <= npts; i++) {
n[i] = temp[i];
}
}
void getKnots(int n, int c, inout int x[7])
{
int nplusc, nplus2, i;
nplusc = n + c;
nplus2 = n + 2;
x[1] = 0;
for (i = 2; i <= nplusc; i++){
if ( (i > c) && (i < nplus2) )
x[i] = x[i-1] + 1;
else
x[i] = x[i-1];
}
}
void main()
{
// Bilinear interpolation
vec3 p0 = (1 - in_UV.x) * p00 + in_UV.x * p10;
vec3 p1 = (1 - in_UV.x) * p01 + in_UV.x * p11;
vec3 p = (1 - in_UV.y) * p0 + in_UV.y * p1;
/*
vec3 p0 = (1 - in_UV.x) * p00 + in_UV.x * p20;
vec3 p2 = (1 - in_UV.x) * p02 + in_UV.x * p22;
vec3 p = (1 - in_UV.y) * p0 + in_UV.y * p2;
*/
// Calculate three weights
// These values of the weights will make the curves in to circle segments
float w10 = dot(n00, normalize(n00 + n20));
float w11 = dot(n01, normalize(n01 + n21));
float w12 = dot(n02, normalize(n02 + n22));
float basisFunctionValues[4];
int order = 3; // Order of the NURBS curve
int npts = 3; // Number of control points
int knotVector[7] = {0,0,0,0,1,1,1};
// Interpolate in u direction
// getKnots(npts, order, knotVector);
nurbsBasis(order, in_UV.x, npts, knotVector, basisFunctionValues);
vec3 p0 =
basisFunctionValues[1] * p00 +
basisFunctionValues[2] * p10 * w10 +
basisFunctionValues[3] * p20;
vec3 p1 =
basisFunctionValues[1] * p01 +
basisFunctionValues[2] * p11 * w11 +
basisFunctionValues[3] * p21;
vec3 p2 =
basisFunctionValues[1] * p02 +
basisFunctionValues[2] * p12 * w12 +
basisFunctionValues[3] * p22;
// Interpolate normals
vec3 n0 =
basisFunctionValues[1] * n00 +
basisFunctionValues[2] * n10 * w10 +
basisFunctionValues[3] * n20;
vec3 n1 =
basisFunctionValues[1] * n01 +
basisFunctionValues[2] * n11 * w11 +
basisFunctionValues[3] * n21;
vec3 n2 =
basisFunctionValues[1] * n02 +
basisFunctionValues[2] * n12 * w12 +
basisFunctionValues[3] * n22;
// Calculate the last weight
float w1 = dot(n0, n1);
// Interpolate in v direction
nurbsBasis(order, in_UV.y, npts, knotVector, basisFunctionValues);
vec3 p =
basisFunctionValues[1] * p0 +
basisFunctionValues[2] * p1 * w1 +
basisFunctionValues[3] * p2;
//p = (1 - in_UV.y) * p0 + in_UV.y * p2;
vec4 position = Projection * vec4(p, 1);
gl_Position = z_normalization(position);