gluSphere ()를 사용하지 않고 OpenGL에서 구 그리기?
OpenGL에서 사용하지 않고도 구를 그릴 수있는 방법을 설명하는 튜토리얼이 gluSphere()
있습니까?
OpenGL에 대한 많은 3D 튜토리얼은 큐브에 있습니다. 나는 검색했지만 구를 그리는 대부분의 솔루션은 gluSphere()
. 이 사이트에 구를 그리는 코드가있는 사이트도 있지만 구를 그리는 이면의 수학을 설명하지 않습니다. 해당 링크의 쿼드 대신 다각형으로 구를 그리는 방법에 대한 다른 버전도 있습니다. 그러나 다시 말하지만 코드로 구체가 어떻게 그려 지는지 이해하지 못합니다. 필요한 경우 구를 수정할 수 있도록 시각화 할 수 있기를 원합니다.
이를 수행 할 수있는 한 가지 방법은 삼각형면이있는 플라토닉 솔리드 ( 예 : 팔면체 )로 시작하는 것 입니다. 그런 다음 각 삼각형을 재귀 적으로 더 작은 삼각형으로 나눕니다.
충분한 양의 점이 있으면 벡터가 모두 솔리드 중심에서 일정한 거리에 있도록 벡터를 정규화합니다. 이렇게하면 점의 수를 늘릴수록 부드러움이 증가하면서 측면이 구와 유사한 모양으로 튀어 나옵니다.
여기서 정규화는 다른 점에 대한 각도가 같지만 그 사이의 거리가 달라 지도록 점을 이동하는 것을 의미합니다. 다음은 2 차원의 예입니다.
A와 B는 6 단위 떨어져 있습니다. 그러나 우리가 A에서 12 단위 떨어진 라인 AB에서 한 지점을 찾고 싶다고 가정 해 보겠습니다.
C는 거리가 12 인 A에 대해 B의 정규화 된 형태라고 말할 수 있습니다. 다음과 같은 코드로 C를 얻을 수 있습니다.
#returns a point collinear to A and B, a given distance away from A.
function normalize(a, b, length):
#get the distance between a and b along the x and y axes
dx = b.x - a.x
dy = b.y - a.y
#right now, sqrt(dx^2 + dy^2) = distance(a,b).
#we want to modify them so that sqrt(dx^2 + dy^2) = the given length.
dx = dx * length / distance(a,b)
dy = dy * length / distance(a,b)
point c = new point
c.x = a.x + dx
c.y = a.y + dy
return c
이 정규화 프로세스를 동일한 점 A에 대해 동일한 거리 R에 대해 많은 점에 대해 수행하면 정규화 된 점은 모두 중심 A와 반경 R을 갖는 원의 호에 놓일 것입니다.
여기에서 검은 색 점은 선에서 시작하여 호로 "불룩 해집니다".
이 과정은 3 차원으로 확장 될 수 있으며,이 경우 원이 아닌 구를 얻게됩니다. 정규화 함수에 dz 구성 요소를 추가하기 만하면됩니다.
Epcot 에서 구를 보면이 기술이 작동하는 것을 볼 수 있습니다. 그것은 더 둥글게 보이게하기 위해 튀어 나온 얼굴을 가진 십이 면체입니다.
위도와 경도를 사용하여 구를 생성하는 인기있는 방법을 추가로 설명하겠습니다 (또 다른 방법 인 icospheres 는이 글을 쓰는 당시 가장 인기있는 답변에서 이미 설명되었습니다.)
구는 다음과 같은 파라 메트릭 방정식으로 표현할 수 있습니다.
F ( u , v ) = [cos (u) * sin (v) * r, cos (v) * r, sin (u) * sin (v) * r]
어디:
- r 은 반경입니다.
- u 는 0에서 2π까지의 경도입니다. 과
- v 는 0에서 π까지의 위도입니다.
그런 다음 구를 생성하려면 고정 된 간격으로 파라 메트릭 함수를 평가해야합니다.
예를 들어, 16 개의 경도 라인을 생성하려면 u 축을 따라 π / 8 (2π / 16) 간격 으로 17 개의 그리드 라인이 있어야 합니다 (17 번째 라인이 둘러싸 임).
다음 의사 코드는 일정한 간격으로 파라 메트릭 함수를 평가하여 삼각형 메시를 생성합니다 (이는 구뿐만 아니라 모든 파라 메트릭 표면 함수에서 작동 함 ).
아래 의사 코드에서 UResolution 은 U 축 (여기서는 경도 선)을 따르는 격자 점의 수 이고 VResolution 은 V 축 (여기서는 위 도선)을 따르는 격자 점의 수입니다.
var startU=0
var startV=0
var endU=PI*2
var endV=PI
var stepU=(endU-startU)/UResolution // step size between U-points on the grid
var stepV=(endV-startV)/VResolution // step size between V-points on the grid
for(var i=0;i<UResolution;i++){ // U-points
for(var j=0;j<VResolution;j++){ // V-points
var u=i*stepU+startU
var v=j*stepV+startV
var un=(i+1==UResolution) ? EndU : (i+1)*stepU+startU
var vn=(j+1==VResolution) ? EndV : (j+1)*stepV+startV
// Find the four points of the grid
// square by evaluating the parametric
// surface function
var p0=F(u, v)
var p1=F(u, vn)
var p2=F(un, v)
var p3=F(un, vn)
// NOTE: For spheres, the normal is just the normalized
// version of each vertex point; this generally won't be the case for
// other parametric surfaces.
// Output the first triangle of this grid square
triangle(p0, p2, p1)
// Output the other triangle of this grid square
triangle(p3, p1, p2)
}
}
샘플의 코드는 빠르게 설명됩니다. 함수를 살펴 봐야합니다 void drawSphere(double r, int lats, int longs)
.
void drawSphere(double r, int lats, int longs) {
int i, j;
for(i = 0; i <= lats; i++) {
double lat0 = M_PI * (-0.5 + (double) (i - 1) / lats);
double z0 = sin(lat0);
double zr0 = cos(lat0);
double lat1 = M_PI * (-0.5 + (double) i / lats);
double z1 = sin(lat1);
double zr1 = cos(lat1);
glBegin(GL_QUAD_STRIP);
for(j = 0; j <= longs; j++) {
double lng = 2 * M_PI * (double) (j - 1) / longs;
double x = cos(lng);
double y = sin(lng);
glNormal3f(x * zr0, y * zr0, z0);
glVertex3f(r * x * zr0, r * y * zr0, r * z0);
glNormal3f(x * zr1, y * zr1, z1);
glVertex3f(r * x * zr1, r * y * zr1, r * z1);
}
glEnd();
}
}
매개 변수 lat
는 구에 포함 할 수평선 수와 수직선 수를 정의합니다 lon
. r
구의 반경입니다.
이제 lat
/에 대한 이중 반복이 있으며 lon
간단한 삼각법을 사용하여 정점 좌표가 계산됩니다.
계산 된 정점이 이제를 사용하여 GPU glVertex...()
로 GL_QUAD_STRIP
전송됩니다. 즉, 이전에 전송 된 두 정점과 함께 쿼드를 형성하는 각 정점 두 개를 전송합니다.
이제 이해해야 할 것은 삼각 함수가 작동하는 방식 뿐이지 만 쉽게 이해할 수있을 것 같습니다.
여우처럼 교활하고 싶다면 GLU의 코드를 반 인치로 만들 수 있습니다. MesaGL 소스 코드 (http://cgit.freedesktop.org/mesa/mesa/)를 확인하세요.
OpenGL red book : http://www.glprogramming.com/red/chapter02.html#name8 다각형 세분화로 문제를 해결합니다.
'삼각형 스트립'을 사용하여 "극성"구를 그리는 방법의 예는 쌍의 드로잉 포인트로 구성됩니다.
const float PI = 3.141592f;
GLfloat x, y, z, alpha, beta; // Storage for coordinates and angles
GLfloat radius = 60.0f;
int gradation = 20;
for (alpha = 0.0; alpha < GL_PI; alpha += PI/gradation)
{
glBegin(GL_TRIANGLE_STRIP);
for (beta = 0.0; beta < 2.01*GL_PI; beta += PI/gradation)
{
x = radius*cos(beta)*sin(alpha);
y = radius*sin(beta)*sin(alpha);
z = radius*cos(alpha);
glVertex3f(x, y, z);
x = radius*cos(beta)*sin(alpha + PI/gradation);
y = radius*sin(beta)*sin(alpha + PI/gradation);
z = radius*cos(alpha + PI/gradation);
glVertex3f(x, y, z);
}
glEnd();
}
입력 된 첫 번째 점 (glVertex3f)은 다음과 같은 파라 메트릭 방정식이고 두 번째 점은 알파 각도의 단일 단계 (다음 평행선에서)만큼 이동합니다.
받아 들여지는 대답으로 질문이 해결되지만 끝에 약간의 오해가 있습니다. 정 십이 면체 는 모든면이 같은 면적을 갖는 정다면체입니다. 그것은 Epcot의 경우 인 것 같습니다 (그런데, 이것은 십이 면체 가 아닙니다 ). @Kevin이 제안한 솔루션은 이러한 특성을 제공하지 않기 때문에 이러한 특성을 추가 할 수 있다고 생각했습니다.
A good way to generate an N-faced polyhedron where all vertices lay in the same sphere and all its faces have similar area/surface is starting with an icosahedron and the iteratively sub-dividing and normalizing its triangular faces (as suggested in the accepted answer). Dodecahedrons, for instance, are actually truncated icosahedrons.
Regular icosahedrons have 20 faces (12 vertices) and can easily be constructed from 3 golden rectangles; it's just a matter of having this as a starting point instead of an octahedron. You may find an example here.
I know this is a bit off-topic but I believe it may help if someone gets here looking for this specific case.
One way is to make a quad that faces the camera and write a vertex and fragment shader that renders something that looks like a sphere. You could use equations for a circle/sphere that you can find on the internet.
One nice thing is that the silhouette of a sphere looks the same from any angle. However, if the sphere is not in the center of a perspective view, then it would appear perhaps more like an ellipse. You could work out the equations for this and put them in the fragment shading. Then the light shading needs to changed as the player moves, if you do indeed have a player moving in 3D space around the sphere.
Can anyone comment on if they have tried this or if it would be too expensive to be practical?
struct v3
{
double x,y,z;
v3(double _x=0, double _y=0, double _z=0){x=_x;y=_y;z=_z; }
v3 operator + ( v3 v) {return { x+v.x, y+v.y, z+v.z };}
v3 operator * ( double k) {return { x*k, y*k, z*k };}
v3 operator / ( double k) {return { x/k, y/k, z/k };}
v3 normalize(){
double L=sqrt( x*x+y*y+z*z);
return { x/L , y/L , z/L };}
};
void draw_spheree(double r,int adim)
{
// z
// |
// __
// /|
// |
// |
// | * \
// | _ _| _ _ _ | _y
// / \c |n / a4 --- a3
// / \o |i | |
// / \s|s z=sin(v) a1 --- a2
// |/__ y=cos(v) *sin(u)
// x=cos(v) *cos(u)
// /
// x
//
//glEnable(GL_LIGHTING);
//glEnable(GL_LIGHT0);
//glEnable(GL_TEXTURE_2D);
double pi=3.141592;
double d=pi/adim;
for(double u=-pi ; u<pi ; u+=d) //horizonal xy düzlemi Longitude -180 -180
for(double v=-pi/2; v<pi/2; v+=d) //vertical z aks Latitude -90 90
{
v3 a1 = { cos(v)*cos(u) ,cos(v)*sin(u) ,sin(v) },
a2 = { cos(v)*cos(u+d) ,cos(v)*sin(u+d) ,sin(v) },
a3 = { cos(v+d)*cos(u+d) ,cos(v+d)*sin(u+d) ,sin(v+d) },
a4 = { cos(v+d)*cos(u) ,cos(v+d)*sin(u) ,sin(v+d) };
v3 normal=(a1+a2+a3+a4)/4.0; //normal vector
a1=a1*r;
a2=a2*r;
a3=a3*r;
a4=a4*r;
double tu=(u+pi) / (2*pi); //0 to 1 horizonal
double tv=(v+pi/2)/ pi; //0 to 1 vertical
double td=1.0/2./adim;
glNormal3dv((double *)&normal);
glBegin(GL_POLYGON);
glTexCoord2d(tu ,tv ); glVertex3dv((double *) &a1);
glTexCoord2d(tu+td ,tv ); glVertex3dv((double *) &a2);
glTexCoord2d(tu+td ,tv+2*td ); glVertex3dv((double *) &a3);
glTexCoord2d(tu ,tv+2*td ); glVertex3dv((double *) &a4);
glEnd();
}
}
참고URL : https://stackoverflow.com/questions/7687148/drawing-sphere-in-opengl-without-using-glusphere
'program tip' 카테고리의 다른 글
Eclipse에서 프로젝트 탐색기 창을 표시하는 방법 (0) | 2020.10.13 |
---|---|
일부 항목을 제거하려면 "잊음"루프 (0) | 2020.10.13 |
.NET의 HttpWebRequest / Response와 함께 자체 서명 된 인증서 사용 (0) | 2020.10.13 |
Entity Framework Code First Fluent API로 테이블 이름을 지정하는 방법 (0) | 2020.10.13 |
파이썬에서 팬더를 사용하여 모든 중복 항목 목록을 얻으려면 어떻게해야합니까? (0) | 2020.10.13 |