iOS Open GL ES中使用GL_LINES的最小渲染对象大小

时间:2012-02-27 19:44:22

标签: ios glsl opengl-es-2.0

我刚刚完成了我的iOS应用的第一个版本Corebox,现在正在开发一些新功能。

其中一项新功能是对OpenGL渲染进行“小”调整,以强制某些对象永远不会被绘制为小于最小尺寸。需要此处理的所有对象都是使用GL_LINES绘制的简单2点线。

这个带注释的截图解释了我的追求。忽略灰线,我感兴趣的唯一对象是黄色较宽的线条。

Corebox OpenGL scene

我已经广泛搜索了这个,看起来我需要做的是使用顶点着色器改变线条的几何形状。我对GLSL和大多数着色器示例都很陌生,我可以找到应用光照和其他效果的例子,例如:GLSL Heroku EditorKicksJS shader editor

我当前的顶点着色器非常基本:

// GL_LINES vertex shader
uniform mat4 Projection;
uniform mat4 Modelview;

attribute vec4 Position;
attribute vec4 SourceColor;

varying vec4 DestinationColor;

void main(void) {
    DestinationColor = SourceColor;
    gl_Position = Projection * Modelview * Position;
}

我的片段着色器也是如此:

// GL_LINES fragment shader
varying lowp vec4 DestinationColor;

void main(void) {
    gl_FragColor = DestinationColor;
}

我猜是什么需要:

  • 确定查看器(摄像机位置)与对象之间的距离
  • 根据屏幕尺寸和与相机的距离确定屏幕上物体的大小
  • 如果对象太小,则调整其顶点,使其变得足够大,以便在屏幕上轻松查看。

警告和其他说明:

  1. 但如果缩小不会导致模型在屏幕上只是一团橙色?是的,这正是我追求的效果。
  2. 编辑:以下是实施mifortin建议的最终工作版

    uniform mat4 Projection;
    uniform mat4 Modelview;
    uniform float MinimumHeight;
    
    attribute vec4 Position;
    attribute vec4 ObjectCenter;
    attribute vec4 SourceColor;
    
    varying vec4 DestinationColor;
    
    void main(void) {
        // screen-space position of this vertex
        vec4 screenPosition = Projection * Modelview * Position;
        // screen-space mid-point of the object this vertex belongs to
        vec4 screenObjectCenter   = Projection * Modelview * ObjectCenter;
    
        // Z should be 0 by this time and the projective transform in w.
        // scale so w = 1  (these two should be in screen-space)
        vec2 newScreenPosition = screenPosition.xy / screenPosition.w;
        vec2 newObjectCenter   = screenObjectCenter.xy / screenObjectCenter.w;
    
        float d = distance(newScreenPosition, newObjectCenter);
    
        if (d < MinimumHeight && d > 0.0) {
            // Direction of this object, this really only makes sense in the context
            // of a line (eg: GL_LINES)
            vec2 towards = normalize(newScreenPosition - newObjectCenter);
    
            // Shift the center point then adjust the vertex position accordingly
            // Basically this converts: *--x--* into *--------x--------*
            newObjectCenter = newObjectCenter + towards * MinimumHeight;
            screenPosition.xy = newObjectCenter.xy * screenPosition.w;
        }
    
        gl_Position = screenPosition;
        DestinationColor = SourceColor;
    }
    

1 个答案:

答案 0 :(得分:2)

请注意,我没有测试代码,但它应该说明解决方案。

如果要使用着色器,请添加另一个作为线条中心位置的均匀vec4。然后你可以做类似的事情(注意中心可以在CPU上预先计算一次):

uniform float MIN;   //Minimum size of blob on-screen
uniform vec4 center; //Center of the line / blob
...
vec4 screenPos = Projection * Modelview * Position;
vec4 center = Projection * Modelview * Position;

//Z should be 0 by this time and the projective transform in w.
//scale so w = 1  (these two should be in screen-space)
vec2 nScreenPos = screenPos.xy / screenPos.w;
vec2 nCenter = center.xy / center.w;

float d = distance(nScreenPos, nCenter);
if (d < MIN && d > 0)
{
    vec2 towards = normalize(nScreenPos - nCenter);
    nCenter = nCenter + towards * MIN;

    screenPos.xy = nCenter.xy * screenPos.w;
}

gl_Position = screenPos;

在屏幕上找到顶点将被绘制的位置,然后从blob的中心拉伸它,以确保最小尺寸。

此示例适用于圆形对象。对于角点,您可以使MIN成为属性,以便距离中心的距离在每个顶点的基础上变化。

如果您只想要更像盒子的东西,请分别检查x和y坐标的最小距离。

在CPU上,您可以在提交到GPU之前计算屏幕空间中的坐标并进行相应缩放。