在 OpenGL ES 中绘制一个球体 [英] Drawing a sphere in OpenGL ES

查看:19
本文介绍了在 OpenGL ES 中绘制一个球体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想画一个球体,我知道如何在 OpenGL 中使用 glBegin() 和glEnd().

I want to draw a sphere, I know how to do it in OpenGL using calls such as glBegin() & glEnd().

但是 ES 中什么都没有.

But there is nothing in ES.

建议/教程链接?

推荐答案

既然你已经用 OpenGL ES 2.0 标记了这个,让我建议一种创建平滑球体的替代方法,那就是将它们绘制为光线跟踪的冒名顶替者.无需计算复制平滑球体所需的多个顶点,您可以利用球体从任何角度看起来都几乎相同的事实.

Since you've tagged this with OpenGL ES 2.0, let me suggest an alternative approach for creating smooth spheres, and that's to draw them as raytraced impostors. Rather than calculate the many vertices you'll need to replicate a smooth sphere, you can take advantage of the fact that a sphere looks pretty much the same from any angle.

为此,您采用如下流程:

To do this, you employ a process like the following:

您将代表两个三角形的四个顶点发送到顶点着色器,然后将它们置换以创建一个始终面向用户的正方形.在该正方形内,您使用片段着色器对每个像素进行光栅化,并提供通过该正方形窗口查看球体时球体在该点上的颜色.

You send four vertices that represent two triangles to a vertex shader, which then displaces them to create a square that always faces the user. Within that square, you use a fragment shader to raster over each pixel and provide the color that a sphere would have at that point if you were viewing it through this square window.

这种方法的优点是球体与显示器支持的分辨率一样平滑,并且球体可以轻松地从小到大缩放,而无需重新计算几何.它确实将渲染的负担从顶点处理器转移到了片段处理器,但对于单个球体,这在我使用过的 OpenGL ES 2.0 设备上并不是什么大问题.

The advantage of this approach is that the sphere is as smooth as the resolution of your display supports, and the sphere will easily scale from small to large without requiring any recalculation of your geometry. It does shift the burden for rendering from the vertex processor to the fragment processor, but for a single sphere that's not much of a problem on the OpenGL ES 2.0 devices I've worked with.

我在这个 iOS 应用程序中使用了这种技术,该页面上提供了源代码,并在这里.我使用的顶点着色器的简化版本如下所示:

I use this technique in this iOS application, for which the source code is available on that page, and talk about it a little more here. A simplified version of the vertex shader I use looks something like this:

attribute vec4 position;
attribute vec4 inputImpostorSpaceCoordinate;

varying mediump vec2 impostorSpaceCoordinate;
varying mediump vec3 normalizedViewCoordinate;

uniform mat4 modelViewProjMatrix;
uniform mediump mat4 orthographicMatrix;
uniform mediump float sphereRadius;

void main()
{
    vec4 transformedPosition;
    transformedPosition = modelViewProjMatrix * position;
    impostorSpaceCoordinate = inputImpostorSpaceCoordinate.xy;

    transformedPosition.xy = transformedPosition.xy + inputImpostorSpaceCoordinate.xy * vec2(sphereRadius);
    transformedPosition = transformedPosition * orthographicMatrix;

    normalizedViewCoordinate = (transformedPosition.xyz + 1.0) / 2.0;
    gl_Position = transformedPosition;
}

简化的片段着色器是这样的:

and the simplified fragment shader is this:

precision mediump float;

uniform vec3 lightPosition;
uniform vec3 sphereColor;
uniform mediump float sphereRadius;

uniform sampler2D depthTexture;

varying mediump vec2 impostorSpaceCoordinate;
varying mediump vec3 normalizedViewCoordinate;

const mediump vec3 oneVector = vec3(1.0, 1.0, 1.0);

void main()
{
    float distanceFromCenter = length(impostorSpaceCoordinate);

    // Establish the visual bounds of the sphere
    if (distanceFromCenter > 1.0)
    {
        discard;
    }

    float normalizedDepth = sqrt(1.0 - distanceFromCenter * distanceFromCenter);

    // Current depth
    float depthOfFragment = sphereRadius * 0.5 * normalizedDepth;
    //        float currentDepthValue = normalizedViewCoordinate.z - depthOfFragment - 0.0025;
    float currentDepthValue = (normalizedViewCoordinate.z - depthOfFragment - 0.0025);

    // Calculate the lighting normal for the sphere
    vec3 normal = vec3(impostorSpaceCoordinate, normalizedDepth);

    vec3 finalSphereColor = sphereColor;

    // ambient
    float lightingIntensity = 0.3 + 0.7 * clamp(dot(lightPosition, normal), 0.0, 1.0);
    finalSphereColor *= lightingIntensity;

    // Per fragment specular lighting
    lightingIntensity  = clamp(dot(lightPosition, normal), 0.0, 1.0);
    lightingIntensity  = pow(lightingIntensity, 60.0);
    finalSphereColor += vec3(0.4, 0.4, 0.4) * lightingIntensity;

    gl_FragColor = vec4(finalSphereColor, 1.0);
}

这些着色器的当前优化版本有点难以理解,而且我还使用了环境光遮蔽照明,这些不存在.也没有显示这个球体的纹理,这可以通过适当的映射函数在球体表面坐标和矩形纹理之间转换来完成.这就是我为球体表面提供预先计算的环境光遮蔽值的方式.

The current optimized versions of these shaders are a little harder to follow, and I also use ambient occlusion lighting, which is not present with these. Also not shown is texturing of this sphere, which can be done with a proper mapping function to translate between sphere surface coordinates and a rectangular texture. This is how I provide precalculated ambient occlusion values for the surfaces of my spheres.

这篇关于在 OpenGL ES 中绘制一个球体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆