生成球体的顶点

发布于 2024-10-06 22:52:46 字数 4892 浏览 0 评论 0原文

在 DirectX 移动照明示例中,圆柱体是通过以下方式生成的:

for( DWORD i=0; i<50; i++ )
            {
                FLOAT theta = (2*D3DMX_PI*i)/(50-1);
                pVertices[2*i+0].position = D3DMXVECTOR3( (float)sin(theta),-1.0f, (float)cos(theta) );
                pVertices[2*i+0].normal   = D3DMXVECTOR3( (float)sin(theta), 0.0f, (float)cos(theta) );
                pVertices[2*i+1].position = D3DMXVECTOR3( (float)sin(theta), 1.0f, (float)cos(theta) );
                pVertices[2*i+1].normal   = D3DMXVECTOR3( (float)sin(theta), 0.0f, (float)cos(theta) );
            }

是否有类似的方法可以在 DirectX Mobile 中为球体生成顶点(作为三角形带或其他形式)? (据我所知,没有D3DMXCreateSphere方法)


最终的解决方案。感谢quarnion的所有帮助。

void CreateSphere()
{
    const int iFactor = 20;
    int iPos = 0;

    arr_Vertices = new CUSTOMVERTEX[ui_VCount];
    ui_ShapeCount = iFactor *iFactor * 2; // use when rendering

    float arrV[iFactor* iFactor][3];

    for (DWORD j= 0; j < iFactor; j ++)
    {
        FLOAT theta = (D3DMX_PI*j)/(iFactor);

        for( DWORD i=0; i<iFactor; i++ )
        {
            iPos = j*iFactor+i;
            FLOAT phi = (2*D3DMX_PI*i)/(iFactor);
            arrV[iPos][0] = (float)(sin(theta)*cos(phi));
            arrV[iPos][1] = (float)(sin(theta)*sin(phi));
            arrV[iPos][2] = (float)(cos(theta));

            /*std::cout << "[" << j <<"][" << i << "] = " << arrV[iPos][0]  
                << "," << arrV[iPos][1] << "," << arrV[iPos][2] <<std::endl;*/
        }
    }

    int iNext = 0;

    for (DWORD j= 0; j < iFactor; j ++)
    { 

        for( DWORD i=0; i<iFactor; i++ )
        {
            if (i == iFactor - 1)
                iNext = 0;
            else iNext = i +1;

            iPos = (j*iFactor*6)+(i*6);
            arr_Vertices[iPos].position = D3DMXVECTOR3( arrV[j*iFactor+i][0], arrV[j*iFactor+i][1], arrV[j*iFactor+i][2]);
            arr_Vertices[iPos + 1].position = D3DMXVECTOR3( arrV[j*iFactor+iNext][0], arrV[j*iFactor+iNext][1], arrV[j*iFactor+iNext][2]);


            if (j != iFactor -1)
                arr_Vertices[iPos + 2].position = D3DMXVECTOR3( arrV[((j+1)*iFactor)+i][0], arrV[((j+1)*iFactor)+i][1], arrV[((j+1)*iFactor)+i][2]);
            else
                arr_Vertices[iPos + 2].position = D3DMXVECTOR3( 0, 0, -1); //Create a pseudo triangle fan for the last set of triangles

            arr_Vertices[iPos].normal = D3DMXVECTOR3( arr_Vertices[iPos].position.x, arr_Vertices[iPos].position.y, arr_Vertices[iPos].position.z);
            arr_Vertices[iPos + 1].normal = D3DMXVECTOR3( arr_Vertices[iPos+1].position.x, arr_Vertices[iPos+1].position.y, arr_Vertices[iPos+1].position.z);
            arr_Vertices[iPos + 2].normal = D3DMXVECTOR3( arr_Vertices[iPos+2].position.x, arr_Vertices[iPos+2].position.y, arr_Vertices[iPos+2].position.z);

            arr_Vertices[iPos + 3].position = D3DMXVECTOR3( arr_Vertices[iPos+2].position.x, arr_Vertices[iPos+2].position.y, arr_Vertices[iPos+2].position.z);
            arr_Vertices[iPos + 4].position = D3DMXVECTOR3( arr_Vertices[iPos+1].position.x, arr_Vertices[iPos+1].position.y, arr_Vertices[iPos+1].position.z);

            if (j != iFactor - 1)
                arr_Vertices[iPos + 5].position = D3DMXVECTOR3( arrV[((j+1)*iFactor)+iNext][0], arrV[((j+1)*iFactor)+iNext][1], arrV[((j+1)*iFactor)+iNext][2]);
            else
                arr_Vertices[iPos + 5].position = D3DMXVECTOR3( 0,0,-1);

            arr_Vertices[iPos + 3].normal = D3DMXVECTOR3( arr_Vertices[iPos+3].position.x, arr_Vertices[iPos+3].position.y, arr_Vertices[iPos+3].position.z);
            arr_Vertices[iPos + 4].normal = D3DMXVECTOR3( arr_Vertices[iPos+4].position.x, arr_Vertices[iPos+4].position.y, arr_Vertices[iPos+4].position.z);
            arr_Vertices[iPos + 5].normal = D3DMXVECTOR3( arr_Vertices[iPos+5].position.x, arr_Vertices[iPos+5].position.y, arr_Vertices[iPos+5].position.z);

            //std::cout << "[" << iPos <<"] = " << arr_Vertices[iPos].position.x << 
            //  "," << arr_Vertices[iPos].position.y <<
            //  "," << arr_Vertices[iPos].position.z <<std::endl;

            //std::cout << "[" << iPos + 1 <<"] = " << arr_Vertices[iPos + 1].position.x << 
            //  "," << arr_Vertices[iPos+ 1].position.y <<
            //  "," << arr_Vertices[iPos+ 1].position.z <<std::endl;

            //std::cout << "[" << iPos + 2 <<"] = " << arr_Vertices[iPos].position.x << 
            //  "," << arr_Vertices[iPos + 2].position.y <<
            //  "," << arr_Vertices[iPos + 2].position.z <<std::endl;
        }
    }
}

只需进行一些调整即可使用。这会创建一个 TRANGLELIST,但可以更改为输出一组三角形条带

In the DirectX mobile lighting sample, a cylinder is generated in the following manner:

for( DWORD i=0; i<50; i++ )
            {
                FLOAT theta = (2*D3DMX_PI*i)/(50-1);
                pVertices[2*i+0].position = D3DMXVECTOR3( (float)sin(theta),-1.0f, (float)cos(theta) );
                pVertices[2*i+0].normal   = D3DMXVECTOR3( (float)sin(theta), 0.0f, (float)cos(theta) );
                pVertices[2*i+1].position = D3DMXVECTOR3( (float)sin(theta), 1.0f, (float)cos(theta) );
                pVertices[2*i+1].normal   = D3DMXVECTOR3( (float)sin(theta), 0.0f, (float)cos(theta) );
            }

Is there a similar way to generate vertices for a sphere in DirectX Mobile(as a triangle strip or otherwise)? (AFAIK there's no D3DMXCreateSphere method)


The final solution .Thanks to quarternion for all his help.

void CreateSphere()
{
    const int iFactor = 20;
    int iPos = 0;

    arr_Vertices = new CUSTOMVERTEX[ui_VCount];
    ui_ShapeCount = iFactor *iFactor * 2; // use when rendering

    float arrV[iFactor* iFactor][3];

    for (DWORD j= 0; j < iFactor; j ++)
    {
        FLOAT theta = (D3DMX_PI*j)/(iFactor);

        for( DWORD i=0; i<iFactor; i++ )
        {
            iPos = j*iFactor+i;
            FLOAT phi = (2*D3DMX_PI*i)/(iFactor);
            arrV[iPos][0] = (float)(sin(theta)*cos(phi));
            arrV[iPos][1] = (float)(sin(theta)*sin(phi));
            arrV[iPos][2] = (float)(cos(theta));

            /*std::cout << "[" << j <<"][" << i << "] = " << arrV[iPos][0]  
                << "," << arrV[iPos][1] << "," << arrV[iPos][2] <<std::endl;*/
        }
    }

    int iNext = 0;

    for (DWORD j= 0; j < iFactor; j ++)
    { 

        for( DWORD i=0; i<iFactor; i++ )
        {
            if (i == iFactor - 1)
                iNext = 0;
            else iNext = i +1;

            iPos = (j*iFactor*6)+(i*6);
            arr_Vertices[iPos].position = D3DMXVECTOR3( arrV[j*iFactor+i][0], arrV[j*iFactor+i][1], arrV[j*iFactor+i][2]);
            arr_Vertices[iPos + 1].position = D3DMXVECTOR3( arrV[j*iFactor+iNext][0], arrV[j*iFactor+iNext][1], arrV[j*iFactor+iNext][2]);


            if (j != iFactor -1)
                arr_Vertices[iPos + 2].position = D3DMXVECTOR3( arrV[((j+1)*iFactor)+i][0], arrV[((j+1)*iFactor)+i][1], arrV[((j+1)*iFactor)+i][2]);
            else
                arr_Vertices[iPos + 2].position = D3DMXVECTOR3( 0, 0, -1); //Create a pseudo triangle fan for the last set of triangles

            arr_Vertices[iPos].normal = D3DMXVECTOR3( arr_Vertices[iPos].position.x, arr_Vertices[iPos].position.y, arr_Vertices[iPos].position.z);
            arr_Vertices[iPos + 1].normal = D3DMXVECTOR3( arr_Vertices[iPos+1].position.x, arr_Vertices[iPos+1].position.y, arr_Vertices[iPos+1].position.z);
            arr_Vertices[iPos + 2].normal = D3DMXVECTOR3( arr_Vertices[iPos+2].position.x, arr_Vertices[iPos+2].position.y, arr_Vertices[iPos+2].position.z);

            arr_Vertices[iPos + 3].position = D3DMXVECTOR3( arr_Vertices[iPos+2].position.x, arr_Vertices[iPos+2].position.y, arr_Vertices[iPos+2].position.z);
            arr_Vertices[iPos + 4].position = D3DMXVECTOR3( arr_Vertices[iPos+1].position.x, arr_Vertices[iPos+1].position.y, arr_Vertices[iPos+1].position.z);

            if (j != iFactor - 1)
                arr_Vertices[iPos + 5].position = D3DMXVECTOR3( arrV[((j+1)*iFactor)+iNext][0], arrV[((j+1)*iFactor)+iNext][1], arrV[((j+1)*iFactor)+iNext][2]);
            else
                arr_Vertices[iPos + 5].position = D3DMXVECTOR3( 0,0,-1);

            arr_Vertices[iPos + 3].normal = D3DMXVECTOR3( arr_Vertices[iPos+3].position.x, arr_Vertices[iPos+3].position.y, arr_Vertices[iPos+3].position.z);
            arr_Vertices[iPos + 4].normal = D3DMXVECTOR3( arr_Vertices[iPos+4].position.x, arr_Vertices[iPos+4].position.y, arr_Vertices[iPos+4].position.z);
            arr_Vertices[iPos + 5].normal = D3DMXVECTOR3( arr_Vertices[iPos+5].position.x, arr_Vertices[iPos+5].position.y, arr_Vertices[iPos+5].position.z);

            //std::cout << "[" << iPos <<"] = " << arr_Vertices[iPos].position.x << 
            //  "," << arr_Vertices[iPos].position.y <<
            //  "," << arr_Vertices[iPos].position.z <<std::endl;

            //std::cout << "[" << iPos + 1 <<"] = " << arr_Vertices[iPos + 1].position.x << 
            //  "," << arr_Vertices[iPos+ 1].position.y <<
            //  "," << arr_Vertices[iPos+ 1].position.z <<std::endl;

            //std::cout << "[" << iPos + 2 <<"] = " << arr_Vertices[iPos].position.x << 
            //  "," << arr_Vertices[iPos + 2].position.y <<
            //  "," << arr_Vertices[iPos + 2].position.z <<std::endl;
        }
    }
}

Should be usable with only a few adjustments. This creates a TRIANGLELIST but could be altered to output a set of triangle strips

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

烏雲後面有陽光 2024-10-13 22:52:46

思考它的基本方式:

第一种方法不使用连续的三角形带...

已经有一段时间了,所以我可能会犯错误...

以参数方式定义的单位圆:

Where 0 =< theta < 2pi 
x = sin(theta);
y = cos(theta);

现在我们可以定义单个圆,想象一下同心环x,y 平面。
现在想象一下,抬起最里面的圆圈,当您抬起它时,它会拉起下一个环,就像一个紧身衣……这种视觉效果仅适用于半个球体。

因此,从同心环产生球体形状的形式当然是另一个与环正交的圆,即 (z,y) 平面...当然,我们只对找到环的偏移量感兴趣(它需要从 (x,y) 平面偏移多高或多低,

因为我们只需要偏移量,所以我们只需要半个圆......而且极点将只是一个点。每个环之间的杆和条

经过此心理练习后,请参阅http://en.wikipedia.org/wiki/Sphere
并搜索“半径为 r 的球体上的点可以通过参数化”,您将在该行后面看到参数形式。

法线非常简单,球体应始终围绕 (0,0,0) 构建,并且球体应始终以半径 1 构建(因此您可以简单地将其缩放到所需的大小),然后是圆上的每个顶点表面等于法线。


上面的方法使用两个三角形扇形和一系列三角形带...另一种方法可以生成顶点均匀分布的球体,并且可以用单个三角形带绘制,尽管目前我会疯狂地尝试编码它涉及以下想法:

想象一个以原点为中心的四面体(点距 0,0,0 1 个单位)。这是一个相当可悲的球体表示,但它是一个近似值。现在想象一下,我们找到四个面上每个面的中点,然后将该点推出,直到它位于球体的表面上。然后我们找到这些面的中点并将它们推出到球体的表面...

tetrahdralSphere(int recursions){}

找到中点非常简单,它只是每个 x,y,z 分量的平均值。然后,由于球体是单位球体,因此将它们移动到表面就像标准化这个新向量一样简单。


方法一产生一个看起来像经度和纬度线的点分布,并产生一个非均匀分布(如果使用四边形和线框,它看起来就像一个地球仪),它很容易实现。第二种方法需要递归,所以有点困难,但看起来更统一。如果你想变得非常复杂并且伤到你的头......那么尝试分布n个点,然后模拟点之间的排斥力,使它们分开,然后在表面上对它们进行标准化。要使这项工作有效地进行,需要解决各种令人头疼的问题,但是您拥有相当均匀分布的点,并且可以控制顶点的数量,并且您将开始了解建模工具需要什么才能实现这一点。找到表示模型的最小几何形状。


使用第一种方法。
在 (0,0,1) 处画一个点,然后您需要第一个同心环(为简单起见,每个环将具有相同数量的点)。

让我们在每个环上画 10 个点...所以 phi 将以 2pi/10 的增量递增
让我们绘制 10 个同心环

,我们将绘制 10 个环 + 2 个极点,因此 theta 将以 pi/12 的增量增加。

//this psudo code places the points
//NOT TESTED
deltaTheta = pi/12;
deltaPhi = 2pi/10;
drawVertex(0,0,1) //north pole end cap
for(int ring; ring < 10; ring++){ //move to a new z - offset 
  theta += deltaTheta;
  for(int point; point < 10; point++){ // draw a ring
    phi += deltaPhi;
    x = sin(theta) * cos(phi)
    y = sin(theta) * sin(phi)
    z = cos(theta)
    drawVertex(x,y,z)
  }
}
drawVertex(0, 0, -1) //south pole end cap

Basic way of thinking about it:

First method not using a continuous triangle strip...

It's been a while so I might make a mistake...

A unit circle defined parametrically:

Where 0 =< theta < 2pi 
x = sin(theta);
y = cos(theta);

Now that we can define a single circle, imagine concentric rings on the x,y plane.
Now imagine raising the inner most circle and as you raise it it pulls up the next ring, like a slinky... This visual only works for half a sphere.

So the form that produces the shape of a sphere from the concentric rings is of course another circle which is orthogonal to the rings, the (z,y) plane... Of course we are only interested in finding the offset of the ring (how high or low it needs to be offset from the (x,y) plane.

Because we just need the offset we only need half a circle... and further the poles will only be a single point. Use a triangle fan at the poles and strips between each ring.

After this mental exercise see http://en.wikipedia.org/wiki/Sphere
and search for "The points on the sphere with radius r can be parametrized via" and you'll see the parametric form after that line.

The normals are very easy the sphere should always be built around (0,0,0) and the sphere should always be built with a radius of 1 (so you can simply scale it to the desired size) and then each vertex on the circle surface is equal to the normal.


The above method uses two triangle fans and a series of triangle strips... another method which produces a sphere with an even distribution of vertexes and can be drawn with a single triangle strip, although at the moment I'd go crazy trying to code it involves the following idea:

Imagine a tetrahedron centered about the origin (the points are 1 unit from 0,0,0). It is a pretty pathetic representation of a sphere but it is an approximation. Now imagine that we find the midpoint on each of the four faces and then push that point out until it is on the surface of the sphere. Then we find the midpoints of those faces and push them out to the surface of the sphere...

tetrahdralSphere(int recursions){}

Finding the mid point is very simple it is just the average of each of the x,y,z components. Then since the sphere is a unit sphere moving them to the surface is as simple as normalizing this new vector.


Method one produces a point distribution that looks lines of longitude and latitude and produces a non uniform distribution (it looks just like a globe if using quads and a wire frame), it is quite easy to implement. The second method requires recursion so it a little more difficult but will look more uniform. If you want to get really complicated and hurt your head... then try distributing n points and then simulate a repellent force between points which moves them apart and then normalize them across the surface. There are all kinds of headaches that need to addressed to make this work effectively but then you have rather uniformly distributed points and you can control the number of vertices's and you'll have have the very start of appreciation of what it takes for modeling tools to find the minimal geometry to represent a model.


Going with the first method.
Draw a point at (0,0,1) then you need your first concentric ring (each ring will have the same number of points for simplicity).

Lets draw 10 points per ring... so phi will step in increments of 2pi/10
and lets draw 10 concentric rings

and we will draw 10 rings + 2 poles so theta will increase in increments of pi/12.

//this psudo code places the points
//NOT TESTED
deltaTheta = pi/12;
deltaPhi = 2pi/10;
drawVertex(0,0,1) //north pole end cap
for(int ring; ring < 10; ring++){ //move to a new z - offset 
  theta += deltaTheta;
  for(int point; point < 10; point++){ // draw a ring
    phi += deltaPhi;
    x = sin(theta) * cos(phi)
    y = sin(theta) * sin(phi)
    z = cos(theta)
    drawVertex(x,y,z)
  }
}
drawVertex(0, 0, -1) //south pole end cap
ヤ经典坏疍 2024-10-13 22:52:46

对单位球体进行三角测量的常用方法是构建一个 四面体二十面体 并且

  • 如果精度足够,则停止
  • Else,对于每个现有面:
  • 在每条边的中点添加一个顶点并将其标准化,使其位于单位球体上
  • 用四个新面替换该面。其中一个面以三个新的中点为角(将其画在纸上,其他三个面将变得明显)
  • 循环。

为了避免在边中点重复顶点,您需要跟踪现有顶点以供重用。

The usual way to triangulate a unit sphere is to build a tetrahedron or a icosahedron and

  • If precision is enough, stop
  • Else, for each existing face:
  • Add a vertex at the midpoint of each edge and normalize it so that it is on the unit sphere
  • Replace the face with four new faces. One of the faces has the three new midpoints as corners (draw it on paper, and the other three faces will become obvious)
  • Loop.

To avoid duplicating vertexes at the edge midpoints, you need to track the existing vertices for reuse.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文