Z pomocą NURBS umiem stworzyć górkę.
Tablica points[4*4*3]
0.0,0.0,5.0, 0.0,0.0,4.5, 0.0,0.0,0.5, 0.0,0.0,0.0,
0.5,0.0,5.0, 3.0,2.0,2.0, 3.0,2.0,3.0, 0.5,0.0,0.0,
4.5,0.0,5.0, 2.0,2.0,2.0, 2.0,2.0,3.0, 4.5,0.0,0.0,
5.0,0.0,5.0, 5.0,0.0,4.5, 5.0,0.0,0.5, 5.0,0.0,0.0
gluNurbsSurface(nurbs, 8, knots, 8, knots, 4 * 3, 3, points, 4, 4, GL_MAP2_VERTEX_3);
Rysunek:
Problem pojawia się wtedy kiedy chce zmienić ilość punktów, aby mieć większą kontrolę nad powierzchnią.
0.0,0.0,5.0, 0.0,0.0,4.5, 0.0,0.0,4.0, 0.0,0.0,1.0, 0.0,0.0,0.5, 0.0,0.0,0.0,
0.5,0.0,5.0, 3.0,2.0,4.0, 3.0,2.0,5.0, 3.0,2.0,1.0, 3.0,2.0,2.0, 0.5,0.0,0.0,
4.5,0.0,5.0, 2.0,2.0,4.0, 2.0,2.0,5.0, 2.0,2.0,1.0, 2.0,2.0,2.0, 4.5,0.0,0.0,
5.0,0.0,5.0, 5.0,0.0,4.5, 5.0,0.0,4.0, 5.0,0.0,1.0, 5.0,0.0,0.5, 5.0,0.0,0.0
gluNurbsSurface(nurbs, 8, knots, 8, knots, 4 * 3, 3, points, 4, 4, GL_MAP2_VERTEX_3);
Jak zmienię zestaw punktów to wychodzi coś takiego:
Jak dostosuje do nowej ilość punktów argumenty funkcji gluNurbsSurface
gluNurbsSurface(nurbs, 8, knots, 8, knots, 4*6, 3, points, 4, 6, GL_MAP2_VERTEX_3);
to otrzymuje:
Moim celem są dwa szczyty.
Jakakolwiek zmiana w parametrach funkcji gluNurbsSurface powoduje zniknięcie płaszczyzny. Gdzie i jaki popełniam błąd? Mój kod umieszczam poniżej. Używam OpenGL i freeGLUT.
Pozdrawiam
//Colors
GLfloat WHITE[] = { 1,1,1 };
GLfloat RED[] = { 1,0,0 };
GLfloat GREEN[] = { 0,1,0 };
GLfloat MAGENTA[] = { 1,0,1 };
GLfloat BLACK[] = { 0,0,0 };
GLfloat BLUE[] = { 0,0,1 };
//-----------------
// rozmiary bryły obcinania
const GLdouble left1 = -2.0;
const GLdouble right1 = 2.0;
const GLdouble bottom = -2.0;
const GLdouble top = 2.0;
const GLdouble near1 = 3.0;
const GLdouble far1 = 7.0;
// kąty obrotu obiektu
GLfloat rotatex = 0.0;
GLfloat rotatey = 0.0;
// wskaźnik naciśnięcia lewego przycisku myszki
int button_state = GLUT_UP;
// położenie kursora myszki
int button_x, button_y;
// współczynnik skalowania
GLfloat scale = 1.0;
// współrzędne punktów kontrolnych powierzchni
//4 * 4 * 3
GLfloat points[4 * 6 * 3] =
{
/*
0.0,0.0,5.0, 0.0,0.0,4.5, 0.0,0.0,0.5, 0.0,0.0,0.0,
0.5,0.0,5.0, 3.0,2.0,2.0, 3.0,2.0,3.0, 0.5,0.0,0.0,
4.5,0.0,5.0, 2.0,2.0,2.0, 2.0,2.0,3.0, 4.5,0.0,0.0,
5.0,0.0,5.0, 5.0,0.0,4.5, 5.0,0.0,0.5, 5.0,0.0,0.0
*/
0.0,0.0,5.0, 0.0,0.0,4.5, 0.0,0.0,4.0, 0.0,0.0,1.0, 0.0,0.0,0.5, 0.0,0.0,0.0,
0.5,0.0,5.0, 3.0,2.0,4.0, 3.0,2.0,5.0, 3.0,2.0,1.0, 3.0,2.0,2.0, 0.5,0.0,0.0,
4.5,0.0,5.0, 2.0,2.0,4.0, 2.0,2.0,5.0, 2.0,2.0,1.0, 2.0,2.0,2.0, 4.5,0.0,0.0,
5.0,0.0,5.0, 5.0,0.0,4.5, 5.0,0.0,4.0, 5.0,0.0,1.0, 5.0,0.0,0.5, 5.0,0.0,0.0
};
// węzły
GLfloat knots[4 * 2] =
{
0.0, 0.0,
0.0, 0.0,
1.0, 1.0,
1.0, 1.0
};
//A chekerboard
class Checkerboard {
int displayListId;
public:
int width;
int depth;
Checkerboard(int width, int depth) : width(width), depth(depth) {}
double centerx() { return width / 2; }
double centery() { return depth / 2; }
int returnx() { return width; }
int returny() { return depth; }
void create() {
displayListId = glGenLists(1);
glNewList(displayListId, GL_COMPILE);
glBegin(GL_QUADS);
glNormal3d(0, 1, 0);
for (int x = 0; x < width - 1; x++) {
for (int z = 0; z < depth - 1; z++) {
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
(x + z) % 2 == 0 ? RED : WHITE);
glVertex3d(x, 0, z);
glVertex3d(x + 1, 0, z);
glVertex3d(x + 1, 0, z + 1);
glVertex3d(x, 0, z + 1);
}
}
glEnd();
glEndList();
}
void draw() {
glCallList(displayListId);
}
void rotate()
{
glRotatef(rotatex, 1.0, 0, 0);
glRotatef(rotatey, 0, 1.0, 0);
}
};
Vector3d v(0, 0, 0), f(0, 0, 0);
int checkerboardSize = 6;
Checkerboard checkerboard(checkerboardSize, checkerboardSize);
void Update(void)
{
glutPostRedisplay();
}
void init(void)
{
glEnable(GL_DEPTH_TEST);
glLightfv(GL_LIGHT0, GL_DIFFUSE, WHITE);
glLightfv(GL_LIGHT0, GL_SPECULAR, WHITE);
glMaterialfv(GL_FRONT, GL_SPECULAR, WHITE);
glMaterialf(GL_FRONT, GL_SHININESS, 30);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
checkerboard.create();
}
void update() {
Update();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// wybór macierzy modelowania
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// włączenie testu bufora głębokości
glEnable(GL_DEPTH_TEST);
gluLookAt(12.0, 3.0, 0.0, checkerboard.centerx(), 0.0, checkerboard.centery(), 0.0, 1.0, 0.0);
checkerboard.rotate(); checkerboard.draw();
// obroty obiektu
glRotatef(rotatex, 1.0, 0, 0);
glRotatef(rotatey, 0, 1.0, 0);
// kolor krawędzi
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, BLUE);
// utworzenie obiektu NURBS
GLUnurbsObj* nurbs = gluNewNurbsRenderer();
// początek definicji powierzchni NURBS
gluBeginSurface(nurbs);
// sposób renderowania powierzchni NURBS
gluNurbsProperty(nurbs, GLU_DISPLAY_MODE, GLU_FILL);
// metoda podziału powierzchni NURBS na wielokąty
gluNurbsProperty(nurbs, GLU_SAMPLING_METHOD, GLU_PATH_LENGTH);
//gluNurbsProperty(nurbs, GLU_SAMPLING_TOLERANCE, 25.0);
//gluNurbsProperty(nurbs, GLU_DISPLAY_MODE, GLU_FILL);
// narysowanie powierzchni
gluNurbsSurface(nurbs, 8, knots, 8, knots, 4*6, 3, points, 4, 6, GL_MAP2_VERTEX_3);
//gluNurbsSurface(nurbs, 8, knots, 8, knots, 4 * 3, 3, points, 4, 4, GL_MAP2_VERTEX_3);
// koniec definicji powierzchni
gluEndSurface(nurbs);
// usunięcie obiektu NURBS
gluDeleteNurbsRenderer(nurbs);
// kolor punktów
//glColor3fv(WHITE);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, WHITE);
// rozxmiar punktów
glPointSize(6.0);
//int arrSize = sizeof(points) / sizeof(points[0]);
// narysowanie punktów kontrolnych
//cout << arrSize << endl;
glBegin(GL_POINTS);
for (int i = 0; i < 24; i++)
glVertex3fv(points + i * 3);
glEnd();
update();
glFlush();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(50.0, w / (GLfloat)h, 1.0, 150.0);
glMatrixMode(GL_MODELVIEW);
}
void timer(int v)
{
glutPostRedisplay();
glutTimerFunc(1000 / 60, timer, v);
}
//--------------------------------------------------
// obsługa przycisków myszki
void MouseButton(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON)
{
// zapamiętanie stanu lewego przycisku myszki
button_state = state;
// zapamiętanie położenia kursora myszki
if (state == GLUT_DOWN)
{
button_x = x;
button_y = y;
}
}
}
// obsługa ruchu kursora myszki
void MouseMotion(int x, int y)
{
if (button_state == GLUT_DOWN)
{
rotatey += 30 * (right1 - left1) / glutGet(GLUT_WINDOW_WIDTH) * (x - button_x);
button_x = x;
rotatex -= 30 * (top - bottom) / glutGet(GLUT_WINDOW_HEIGHT) * (button_y - y);
button_y = y;
glutPostRedisplay();
}
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 600);
glutInitWindowPosition(10, 10);
glutCreateWindow("SPH Implementation");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
// dołączenie funkcji obsługi klawiatury
//glutKeyboardFunc(Keyboard);
// obsługa przycisków myszki
glutMouseFunc(MouseButton);
// obsługa ruchu kursora myszki
glutMotionFunc(MouseMotion);
glutIdleFunc(Update);
glutTimerFunc(1, timer, 0);
init();
glutMainLoop();
return 0;
}