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

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

问题描述

我想绘制一个球体,我知道如何在OpenGL中使用诸如glBegin()& glEnd()。



但ES中没有任何东西。



建议/教程链接?

解决方案

由于您已经使用OpenGL ES 2.0对此进行了标记,因此我建议一种创建平滑球体的替代方法,即将它们绘制为光线跟踪骗子。而不是计算复制平滑球体所需的许多顶点,您可以利用球体从任何角度都几乎相同的事实。



要做到这一点,你需要采用如下流程:





您向顶点着色器发送代表两个三角形的四个顶点,然后替换它们以创建一个始终面向用户的正方形。在该平方中,您使用片段着色器对每个像素进行光栅处理,并提供如果您通过此方形窗口查看球体时球体将具有的颜色。



这种方法的优点是球体与显示器支持的分辨率一样平滑,并且球体很容易从小到大缩放,而不需要重新计算几何图形。它确实将渲染负担从顶点处理器转移到碎片处理器,但是对于一个单一的领域来说,这与我一直使用的OpenGL ES 2.0设备没有多大的问题。



我在此iOS应用程序中使用此技术,该源代码在该页面上可用,并多谈一点这里一>。我使用的顶点着色器的简化版本如下所示:

 属性vec4 position; 
属性vec4 inputImpostorSpaceCoordinate;

不同的中介vec2 impostorSpaceCoordinate;
不同中介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;
}

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

  precision mediump float; 

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

uniform sampler2D depthTexture;

不同的中介vec2 impostorSpaceCoordinate;
不同中介vec3 normalizedViewCoordinate;

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

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

//建立球体的可视范围
if(distanceFromCenter> 1.0)
{
discard;
}

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

//当前深度
float depthOfFragment = sphereRadius * 0.5 * normalizedDepth;
// float currentDepthValue = normalizedViewCoordinate.z - depthOfFragment - 0.0025;
float currentDepthValue =(normalizedViewCoordinate.z - depthOfFragment - 0.0025);

//计算球体的照明法线值
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;

//每片段镜面照明
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);
}

这些着色器的当前优化版本有点难以遵循,而且我也使用环境遮挡照明,这是不存在的。同样未示出的是该球体的纹理,这可以通过适当的映射函数在球体表面坐标和矩形纹理之间进行转换来完成。这是我为我的球体表面提供预先计算的环境遮挡值的方式。

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

But there is nothing in ES.

Suggestions/Tutorial links?

解决方案

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.

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.

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天全站免登陆