[英]Rotate a 2D square about the Y axis and display it in perspective projection using neither DirectX nor openGL
[英]OpenGL - Rotate a 'Curve' About the Y-Axis
按我的問題在數學Stackexchange:
我正在為我的3D圖形課程設計一個項目。 該項目使用C ++和OpenGL / Glut構建。 基本上,我創建了一個水平矩形窗口,分為兩個正方形。 在左側,我有一個二維坐標平面,允許用戶指向和單擊並定義一個輪廓“曲線”。 然后,我需要將此曲線繞Y軸纏繞n次。
那么,有誰能指導我如何使用三角函數來計算連續點的X和Z值? 例如,如果用戶單擊並創建該點:
(1,1,0)
然后將其掃描分辨率(n)設置為10,然后我需要繞Y軸每36(360/10)度重繪一次該點。
我以為三角學會在這里對我有幫助嗎? 如果是這樣,有人可以請我啟發一下如何計算平移點在3D空間中的位置嗎? 自從上手Trig以來已經有一段時間了,我不相信我們曾經離開過2D空間。
編輯 :我試圖使用:
x'=xcos(theta)-zsin(theta)
y'=y
z'=xsin(theta)+zcos(theta)
,據我對AMPerrine的回答的理解,我認為它沒有達到我希望的效果:
// this is in a loop
// setup the new angle
double angle = i>0 ? (360/sweepResolutionMod)*i : 0;
angle = angle * (M_PI/180);
// for each point...
for( int i=0; i<clickedPoints.size(); i++ )
{
// initial point, normalized
GLfloat tempX = (clickedPoints[i].x-250)/250;
GLfloat tempY = (clickedPoints[i].y-250)/250;
GLfloat tempZ = 0.0;
// log the initial point
cout << "(" << tempX << ", " << tempY << ", 0.0) by " << angle << " radians = ";
// generate the new point
GLfloat newX = (tempX * cos(angle)) - (tempZ * sin(angle));
GLfloat newY = tempY;
GLfloat newZ = (tempX * sin(angle)) - (tempZ * cos(angle));
// log the new point
cout << "(" << newX << ", " << newY << ", " << newZ << ")\n";
// render the new point
glVertex3d(newX, newY, newZ);
}
這不會產生任何屏幕輸出,但是會產生以下控制台輸出:
(0.048, -0.296, 0.0) by 0 radians = (0.048, -0.296, 0)
(0.376, -0.508, 0.0) by 0 radians = (0.376, -0.508, 0)
(0.72, -0.204, 0.0) by 0 radians = (0.72, -0.204, 0)
(0.652, 0.176, 0.0) by 0 radians = (0.652, 0.176, 0)
(0.368, 0.504, 0.0) by 0 radians = (0.368, 0.504, 0)
(0.048, -0.296, 0.0) by 0.628319 radians = (0.0388328, -0.296, 0.0282137)
(0.376, -0.508, 0.0) by 0.628319 radians = (0.30419, -0.508, 0.221007)
(0.72, -0.204, 0.0) by 0.628319 radians = (0.582492, -0.204, 0.423205)
(0.652, 0.176, 0.0) by 0.628319 radians = (0.527479, 0.176, 0.383236)
(0.368, 0.504, 0.0) by 0.628319 radians = (0.297718, 0.504, 0.216305)
(0.048, -0.296, 0.0) by 1.25664 radians = (0.0148328, -0.296, 0.0456507)
(0.376, -0.508, 0.0) by 1.25664 radians = (0.11619, -0.508, 0.357597)
(0.72, -0.204, 0.0) by 1.25664 radians = (0.222492, -0.204, 0.684761)
(0.652, 0.176, 0.0) by 1.25664 radians = (0.201479, 0.176, 0.620089)
(0.368, 0.504, 0.0) by 1.25664 radians = (0.113718, 0.504, 0.349989)
...
(0.048, -0.296, 0.0) by 6.28319 radians = (0.048, -0.296, -1.17566e-17)
(0.376, -0.508, 0.0) by 6.28319 radians = (0.376, -0.508, -9.20934e-17)
(0.72, -0.204, 0.0) by 6.28319 radians = (0.72, -0.204, -1.76349e-16)
(0.652, 0.176, 0.0) by 6.28319 radians = (0.652, 0.176, -1.59694e-16)
(0.368, 0.504, 0.0) by 6.28319 radians = (0.368, 0.504, -9.0134e-17)
我不確定這到底是怎么回事,但是我很難解決這個問題,所以請不要以為我想獲得雙重聲譽或其他任何東西,我只是被卡住了。
編輯 2:這是我的透視子視圖的整個顯示例程:
void displayPersp(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
gluLookAt (-2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0);
// draw the axis
glBegin(GL_LINES);
// x
glVertex3f(500.0, 0.0, 0.0);
glVertex3f(-500.0, 0.0, 0.0);
// y
glVertex3f(0.0, -500.0, 0.0);
glVertex3f(0.0, 500.0, 0.0);
// z
glVertex3f(0.0, 0.0, -500.0);
glVertex3f(0.0, 0.0, 500.0);
glEnd();
cout << endl;
// loop as many number of times as we are going to draw the points around the Y-Axis
for( int i=0; i<=sweepResolutionMod; i++ )
{
cout << endl;
// setup the new angle
double angle = i>0 ? (360/sweepResolutionMod)*i : 0;
angle = angle * (M_PI/180);
// for each point...
for( int i=0; i<clickedPoints.size(); i++ )
{
GLfloat tempX = (clickedPoints[i].x-250)/250;
GLfloat tempY = (clickedPoints[i].y-250)/250;
GLfloat tempZ = 0.0;
cout << "(" << tempX << ", " << tempY << ", 0.0) by " << angle << " degrees = ";
GLfloat newX = (tempX * cos(angle)) - (tempZ * sin(angle));
GLfloat newY = tempY;
GLfloat newZ = (tempX * sin(angle)) - (tempZ * cos(angle));
cout << "(" << newX << ", " << newY << ", " << newZ << ")\n";
glVertex3d(newX, newY, newZ);
}
// the following was my old solution, using OpenGL's rotate(), but that
// didn't allow me to get back the new point's coordinates.
/*
glRotatef(angle, 0.0, 1.0, 0.0);
// draw a line?
if( clickedPoints.size() > 1 )
{
glBegin(GL_LINE_STRIP);
for(int i=0; i<clickedPoints.size(); i++ )
{
glVertex3f((clickedPoints[i].x-250)/250, (clickedPoints[i].y-250)/250, 0.0);
}
glEnd();
}
// everyone gets points
glBegin(GL_POINTS);
for(int i=0; i<clickedPoints.size(); i++ )
{
glVertex3f((clickedPoints[i].x-250)/250, (clickedPoints[i].y-250)/250, 0.0);
}
glEnd();
*/
}
glutSwapBuffers();
}
編輯3:這是一個可怕的插圖,說明了我需要做的事情。 我知道透視圖似乎不對,但是我試圖獲取的是右側子視圖中的綠色“水平線”(這是使用上面注釋掉的glRotatef()代碼):
最終編輯 (適用於子孫后代!):
與大學的老師討論了線性代數之后,我終於開始工作了:
void displayPersp(void)
{
glClear(GL_COLOR_BUFFER_BIT);
gluLookAt (-2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
// draw the axis
glBegin(GL_LINES);
// x
glVertex3f(500.0, 0.0, 0.0);
glVertex3f(-500.0, 0.0, 0.0);
// y
glVertex3f(0.0, -500.0, 0.0);
glVertex3f(0.0, 500.0, 0.0);
// z
glVertex3f(0.0, 0.0, -500.0);
glVertex3f(0.0, 0.0, 500.0);
glEnd();
cout << endl;
double previousTheta = 0.0;
for( int i=0; i<=sweepResolutionMod; i++ )
{
double theta = i>0 ? (360/sweepResolutionMod)*i : 0;
theta = theta * (M_PI/180);
if( clickedPoints.size() > 1 )
{
// the 'vertical' piece
glBegin(GL_LINE_STRIP);
for(int i=0; i<clickedPoints.size(); i++ )
{
// normalize
GLfloat tempX = (clickedPoints[i].x-250)/250;
GLfloat tempY = (clickedPoints[i].y-250)/250;
GLfloat tempZ = 0.0;
// new points
GLfloat newX = ( tempX * cos(theta) ) + ( tempZ * sin(theta) );
GLfloat newY = tempY;
GLfloat newZ = ( tempZ * cos(theta) ) - ( tempX * sin(theta) );
glVertex3f(newX, newY, newZ);
}
glEnd();
// the 'horizontal' piece
if( previousTheta != theta )
{
glBegin(GL_LINES);
for(int i=0; i<clickedPoints.size(); i++ )
{
// normalize
GLfloat tempX = (clickedPoints[i].x-250)/250;
GLfloat tempY = (clickedPoints[i].y-250)/250;
GLfloat tempZ = 0.0;
// new points
GLfloat newX = ( tempX * cos(theta) ) + ( tempZ * sin(theta) );
GLfloat newY = tempY;
GLfloat newZ = ( tempZ * cos(theta) ) - ( tempX * sin(theta) );
// previous points
GLfloat previousX = ( tempX * cos(previousTheta) ) + ( tempZ * sin(previousTheta) );
GLfloat previousY = tempY;
GLfloat previousZ = ( tempZ * cos(previousTheta) ) - ( tempX * sin(previousTheta) );
// horizontal component
glVertex3f(newX, newY, newZ);
glVertex3f(previousX, previousY, previousZ);
}
glEnd();
}
}
previousTheta = theta;
}
glutSwapBuffers();
}
觸發函數采用的弧度角不是弧度。
我還懷疑您的視口設置不正確,這解釋了為什么您看不到屏幕上的任何內容。 通常,當我認為素材無法渲染時,通常是,但是,我沒有正確配置相機,照明和其他素材。
編輯2:好的,我看到您遇到的問題-這是我忘記的限制(因此,我之前發布的代碼完全錯誤,根本無法使用)。 問題是您不允許在glBegin
/ glEnd
對之間調用glRotate
如果這樣做,它將設置一個錯誤標志,並且將不再進行繪制。
這確實意味着您幾乎必須自己處理旋轉。 幸運的是,這比您嘗試的要簡單一些:
static const double pi = 3.1416;
for (int point=0; point<NUM_POINTS; point++) {
glBegin(GL_LINE_STRIP);
for (double theta = 0.0; theta < 2.0 * pi; theta += pi/6.0) {
double x = cos(theta);
double z = sin(theta);
glVertex3d(points[point][0]*x, points[point][1], -1.0-points[point][0]*z);
}
glEnd();
}
照原樣,此代碼沿Z軸使用-1.0作為旋轉中心。 顯然,您可以將其移動到所需的位置,盡管截頭錐體之外的任何內容顯然都不會顯示。
另請注意,要獲得線框,您必須分別繪制“垂直”和“水平”線,因此代碼如下所示:
for (int point=0; point<NUM_POINTS; point++) {
glBegin(GL_LINE_STRIP);
for (double theta = 0.0; theta < 2.0 * pi; theta += pi/6.0) {
double x = cos(theta);
double z = sin(theta);
glVertex3d(points[point][0]*x, points[point][1], -1.0 - points[point][0]*z);
}
glEnd();
}
for (double theta = 0.0; theta < 2.0 * pi; theta += pi/6.0) {
glBegin(GL_LINE_STRIP);
for (int point=0; point<NUM_POINTS; point++) {
double x = cos(theta);
double z = sin(theta);
glVertex3d(points[point][0]*x, points[point][1], -1.0 - points[point][0]*z);
}
glEnd();
}
看起來您正在嘗試構造旋轉的曲面 / 旋轉的 實體 / “車床對象” 。
一個工作示例:
#include <GL/glut.h>
#include <glm/glm.hpp>
#include <vector>
#include <cmath>
using namespace std;
using namespace glm;
struct Vertex
{
Vertex( const vec3& position, const vec3& normal )
: position( position )
, normal( normal )
{}
vec3 position;
vec3 normal;
};
// spin the pts array around the Z axis.
// pts.x will become the radius, and pts.y will become the height
// pts should be sorted by y-coordinate
vector< Vertex > Lathe( const vector< vec2 >& pts, unsigned int segments = 32 )
{
// precalculate circle points
vector< vec2 > circlePts;
for( unsigned int i = 0; i <= segments; ++i )
{
float angle = ( i / (float)segments ) * 3.14159f * 2.0f;
circlePts.push_back( vec2( cos( angle ), sin( angle ) ) );
}
// fill each layer
typedef vector< vec3 > Layer;
typedef vector< Layer > Layers;
Layers layers( pts.size(), Layer( circlePts.size() ) );
for( size_t i = 0; i < pts.size(); ++i )
{
for( unsigned int j = 0; j < circlePts.size(); ++j )
{
layers[i][j] = vec3( circlePts[j] * pts[i].x, pts[i].y );
}
}
// move through layers generating triangles
vector< Vertex > verts;
for( size_t i = 1; i < layers.size(); ++i )
{
const Layer& prvLayer = layers[ i-1 ];
const Layer& curLayer = layers[ i-0 ];
for( size_t j = 1; j < circlePts.size(); ++j )
{
// upper = cur layer
// UL -- UR
// left | 0 / | right
// = j-1 | / 1 | = j-0
// LL -- LR
// lower = prv layer
const vec3& LL = prvLayer[ j-1 ]; // lower-left
const vec3& LR = prvLayer[ j-0 ]; // lower-right
const vec3& UL = curLayer[ j-1 ]; // upper-left
const vec3& UR = curLayer[ j-0 ]; // upper-right
// triangle0: LL -> UR -> UL
const vec3 normal0 = normalize( cross( UR - LL, UL - LL ) );
verts.push_back( Vertex( LL, normal0 ) );
verts.push_back( Vertex( UR, normal0 ) );
verts.push_back( Vertex( UL, normal0 ) );
// triangle1: LL -> LR -> UR
const vec3 normal1 = normalize( cross( LR - LL, UL - LL ) );
verts.push_back( Vertex( LL, normal1 ) );
verts.push_back( Vertex( LR, normal1 ) );
verts.push_back( Vertex( UR, normal1 ) );
}
}
return verts;
}
// mouse state
int btn;
ivec2 startMouse;
ivec2 startRot, curRot;
void mouse(int button, int state, int x, int y )
{
if( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
{
btn = button;
startMouse = ivec2( x, glutGet( GLUT_WINDOW_HEIGHT ) - y );
startRot = curRot;
}
}
void motion( int x, int y )
{
ivec2 curMouse( x, glutGet( GLUT_WINDOW_HEIGHT ) - y );
if( btn == GLUT_LEFT_BUTTON )
{
curRot = startRot + ( curMouse - startMouse );
}
glutPostRedisplay();
}
vector< Vertex > model;
void display()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
double ar = w / h;
gluPerspective( 60, ar, 0.1, 40 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0, 0, -10 );
glPushMatrix();
glRotatef( curRot.x % 360, 0, 1, 0 );
glRotatef( -curRot.y % 360, 1, 0, 0 );
// draw model
if( !model.empty() )
{
glColor3ub( 255, 0, 0 );
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_NORMAL_ARRAY );
glVertexPointer( 3, GL_FLOAT, sizeof(Vertex), &model[0].position );
glNormalPointer( GL_FLOAT, sizeof(Vertex), &model[0].normal );
glDrawArrays( GL_TRIANGLES, 0, model.size() );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
}
// draw bounding cube
glDisable( GL_LIGHTING );
glColor3ub( 255, 255, 255 );
glutWireCube( 7 );
glEnable( GL_LIGHTING );
glPopMatrix();
glutSwapBuffers();
}
int main( int argc, char **argv )
{
vector< vec2 > pts;
pts.push_back( vec2( 0.1, -3 ) );
pts.push_back( vec2( 2, -2 ) );
pts.push_back( vec2( 3, -1 ) );
pts.push_back( vec2( 1, 0 ) );
pts.push_back( vec2( 3, 1 ) );
pts.push_back( vec2( 4, 2 ) );
pts.push_back( vec2( 4, 3 ) );
model = Lathe( pts );
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMouseFunc( mouse );
glutMotionFunc( motion );
glEnable( GL_DEPTH_TEST );
// set up lighting
glShadeModel( GL_SMOOTH );
glEnable( GL_COLOR_MATERIAL );
glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ) ;
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE );
glEnable( GL_LIGHTING );
// set up "headlamp"-like light
glEnable( GL_LIGHT0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
GLfloat position[] = { 0, 0, 1, 0 };
glLightfv( GL_LIGHT0, GL_POSITION, position );
glPolygonMode( GL_FRONT, GL_FILL );
glPolygonMode( GL_BACK, GL_LINE );
glutMainLoop();
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.