opengles 画球

既然你已经告诉我使用OpenGL ES 2.0,那让我提出的另一种方法创建光滑球,这就是用光线跟踪来代替。而不是计算你需要复制的一个光滑的球体的所有顶点。你可以利用到一点,即一个球体从任何角度看起来都相同,。

要做到这些, 你可以利用下一点:

Sphere impostor generation

首先将4个代表两个三角形的顶点发送给顶点着色器,然后替换掉这四个顶点,创建一个总是面对用户的正方形。在该正方形中,您可以使用一个片段着色器来光栅每个像素,并在这一点上提供一个球体的颜色,如果你是通过这个广场的窗口观看。

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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值