本文介绍了将部分纹理(精灵表/纹理贴图)应用于iOS OpenGL ES 2.0中的点精灵的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看起来这应该很容易,但是使用点精灵的部分纹理我遇到了很多困难。我已经广泛搜索并提出了各种答案,但这些都没有解决我遇到的具体问题。



到目前为止我学到了什么:





  • ,在这里越来越近..

  • 之前已经完成了精灵+精灵表,但只能在OpenGL ES 2.0(不是1.0)中使用



  • 这是我想要实现的图表





    我在哪里:




    • 我有一组工作点精灵都使用相同的单个方形图像。例如:一个16x16的圆形图像效果很好。

    • 我有一个Objective-C方法,它生成一个600x600的图像,其中包含一个包含多个图像的精灵表。我已经通过将整个精灵表单图像应用到使用GL_TRIANGLES绘制的四边形来验证这是有效的。

    • 我已成功使用上述方法将部分精灵表绘制到四边形上。我只是不能让它与点精灵一起工作。

    • 目前我正在生成指向我正在定位的精灵表上的精灵中心的纹理坐标。例如:使用底部的图像;明星:0.166,0.5;云:0.5,0.5;心脏:0.833,0.5。



    代码:



    顶点着色器

     统一mat4投影; 
    制服mat4 Modelview;
    统一浮点PointSize;

    属性vec4位置;
    属性vec2 TextureCoordIn;

    改变vec2 TextureCoord;

    void main(void)
    {
    gl_Position = Projection * Modelview * Position;
    TextureCoord = TextureCoordIn;
    gl_PointSize = PointSize;
    }

    片段着色器

     不同的mediump vec2 TextureCoord; 
    uniform sampler2D Sampler;

    void main(void)
    {
    //使用我的TextureCoord只绘制一个灰色方块,所以
    //我可能生成纹理坐标,纹理2D不不喜欢。
    gl_FragColor = texture2D(Sampler,TextureCoord);

    //使用gl_PointCoord只绘制我的整个精灵图
    // gl_FragColor = texture2D(Sampler,gl_PointCoord);
    }

    我坚持的内容:


  • 我不明白如何在片段着色器中使用 gl_PointCoord 变量。最初包含 gl_PointCoord 的内容是什么?为什么?它在哪里得到它的数据?

  • 我不明白要传入什么样的纹理坐标。例如,点精灵如何选择我的精灵表的哪一部分基于纹理坐标?我习惯于绘制有效4组纹理坐标的四边形(每个顶点一个),这有什么不同(显然是这样)?


  • 解决方案

    我的一位同事帮助解决了这个问题。事实证明,诀窍是利用点的大小(以OpenGL单位)和精灵的大小(纹理单位,(0..1))结合一点矢量数学来渲染部分每个点都有精灵表。



    顶点着色器

     制服mat4投影; 
    制服mat4 Modelview;
    // OpenGL单位中的点的半径,例如:20.0
    uniform float PointSize;
    //正在渲染的精灵的大小。我的精灵是方形的
    //所以我只是在漂浮。对于非方形精灵,传递
    //宽度和高度作为vec2。
    uniform float TextureCoordPointSize;

    属性vec4位置;
    属性vec4 ObjectCenter;
    //精灵表
    属性中给定精灵​​的左上角vec2 TextureCoordIn;

    改变vec2 TextureCoord;
    不同的vec2 TextureSize;

    void main(void)
    {
    gl_Position = Projection * Modelview * Position;
    TextureCoord = TextureCoordIn;
    TextureSize = vec2(TextureCoordPointSize,TextureCoordPointSize);

    //这是可选的,它是一种快速而肮脏的方式,使得点数在屏幕上保持不变
    //大小,无论距离如何。
    gl_PointSize = PointSize / Position.w;
    }

    片段着色器

     不同的mediump vec2 TextureCoord; 
    不同的mediump vec2 TextureSize;
    uniform sampler2D Sampler;

    void main(void)
    {
    //这是神奇发生的地方。结合所有三个因子来渲染
    //这一点精灵表的一部分
    mediump vec2 realTexCoord = TextureCoord +(gl_PointCoord * TextureSize);
    mediump vec4 fragColor = texture2D(Sampler,realTexCoord);

    //可选,模拟GL_ALPHA_TEST以使用
    //点精灵的透明图像,而不必担心z顺序。
    //参见:http://stackoverflow.com/a/5985195/806988
    if(fragColor.a == 0.0){
    discard;
    }

    gl_FragColor = fragColor;
    }


    It seems this should be easy but I'm having a lot of difficulty using part of a texture with a point sprite. I have googled around extensively and turned up various answers but none of these deal with the specific issue I'm having.

    What I've learned so far:

  • Basics of point sprite drawing
  • How to deal with point sprites rendering as solid squares
  • How to alter orientation of a point sprite
  • How to use multiple textures with a point sprite, getting closer here..
  • That point sprites + sprite sheets has been done before, but is only possible in OpenGL ES 2.0 (not 1.0)
  • Here is a diagram of what I'm trying to achieve

    Where I'm at:

    • I have a set of working point sprites all using the same single square image. Eg: a 16x16 image of a circle works great.
    • I have an Objective-C method which generates a 600x600 image containing a sprite-sheet with multiple images. I have verified this is working by applying the entire sprite sheet image to a quad drawn with GL_TRIANGLES.
    • I have used the above method successfully to draw parts of a sprite sheet on to quads. I just cant get it to work with point sprites.
    • Currently I'm generating texture coordinates pointing to the center of the sprite on the sprite sheet I'm targeting. Eg: Using the image at the bottom; star: 0.166,0.5; cloud: 0.5,0.5; heart: 0.833,0.5.

    Code:

    Vertex Shader

    uniform mat4 Projection;
    uniform mat4 Modelview;
    uniform float PointSize;
    
    attribute vec4 Position;
    attribute vec2 TextureCoordIn;
    
    varying vec2 TextureCoord;
    
    void main(void)
    {
        gl_Position = Projection * Modelview * Position;
        TextureCoord = TextureCoordIn;
        gl_PointSize = PointSize;
    }
    

    Fragment Shader

    varying mediump vec2 TextureCoord;
    uniform sampler2D Sampler;
    
    void main(void)
    {
        // Using my TextureCoord just draws a grey square, so
        // I'm likely generating texture coords that texture2D doesn't like.
        gl_FragColor = texture2D(Sampler, TextureCoord);
    
        // Using gl_PointCoord just draws my whole sprite map
        // gl_FragColor = texture2D(Sampler, gl_PointCoord);
    }
    

    What I'm stuck on:

  • I don't understand how to use the gl_PointCoord variable in the fragment shader. What does gl_PointCoord contain initially? Why? Where does it get its data?
  • I don't understand what texture coordinates to pass in. For example, how does the point sprite choose what part of my sprite sheet to use based on the texture coordinates? I'm used to drawing quads which have effectively 4 sets of texture coordinates (one for each vertex), how is this different (clearly it is)?
  • 解决方案

    A colleague of mine helped with the answer. It turns out the trick is to utilize both the size of the point (in OpenGL units) and the size of the sprite (in texture units, (0..1)) in combination with a little vector math to render only part of the sprite-sheet onto each point.

    Vertex Shader

    uniform mat4 Projection;
    uniform mat4 Modelview;
    // The radius of the point in OpenGL units, eg: "20.0"
    uniform float PointSize;
    // The size of the sprite being rendered. My sprites are square
    // so I'm just passing in a float.  For non-square sprites pass in
    // the width and height as a vec2.
    uniform float TextureCoordPointSize;
    
    attribute vec4 Position;
    attribute vec4 ObjectCenter;
    // The top left corner of a given sprite in the sprite-sheet
    attribute vec2 TextureCoordIn;
    
    varying vec2 TextureCoord;
    varying vec2 TextureSize;
    
    void main(void)
    {
        gl_Position = Projection * Modelview * Position;
        TextureCoord = TextureCoordIn;
        TextureSize = vec2(TextureCoordPointSize, TextureCoordPointSize);
    
        // This is optional, it is a quick and dirty way to make the points stay the same
        // size on the screen regardless of distance.
        gl_PointSize = PointSize / Position.w;
    }
    

    Fragment Shader

    varying mediump vec2 TextureCoord;
    varying mediump vec2 TextureSize;
    uniform sampler2D Sampler;
    
    void main(void)
    {
        // This is where the magic happens.  Combine all three factors to render
        // just a portion of the sprite-sheet for this point
        mediump vec2 realTexCoord = TextureCoord + (gl_PointCoord * TextureSize);
        mediump vec4 fragColor = texture2D(Sampler, realTexCoord);
    
        // Optional, emulate GL_ALPHA_TEST to use transparent images with
        // point sprites without worrying about z-order.
        // see: http://stackoverflow.com/a/5985195/806988
        if(fragColor.a == 0.0){
            discard;
        }
    
        gl_FragColor = fragColor;
    }
    

    这篇关于将部分纹理(精灵表/纹理贴图)应用于iOS OpenGL ES 2.0中的点精灵的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

    09-23 20:46