【问题标题】:How do I render a subset of a texture (knowing the size in pixels) in a OpenGL/WebGL Fragment Shader?如何在 OpenGL/WebGL 片段着色器中渲染纹理的子集(以像素为单位)?
【发布时间】:2014-10-12 01:39:53
【问题描述】:

我有一些代码可以将 2D 精灵渲染到屏幕上。一切正常;但纹理坐标在0,0 - 1,1 范围内提供。我想以像素为单位提供坐标,以便在创建精灵时,我可以提供以像素为单位渲染的精灵表部分(否则,如果我的精灵表改变大小,我需要重新 -计算所有位置,这看起来不太正常)。

// IDEAL SPRITE INIT CODE
var player = new Sprite(
  position: new Vector2.zero(),
  velocity: new Vector2.zero(),
  size: new Vector2(128.0, 128.0) // Rendered size in world-units
  texture: player2Texture,
  textureOffset: new Vector2.zero(), // Offset in spritesheet
  textureSize: new Vector2(100, 100), // Size of section of spritesheet to render
);

我可以在这里传入纹理的总大小,然后除以它,得到 0-1 范围内的数字,但我看不到 WebGL 中的纹理是否让我可以访问它(我也不能当然这是正常的事情)。

我正在尝试在着色器中进行尽可能多的计算(我认为这是合乎逻辑的,因为 GPU 往往比 CPU 更快,但就像我说的,我是菜鸟,请指出这是否是傻!),我当前的着色器看起来像这样:

# VERTEXT SHADER
uniform vec2 uResolution;

attribute vec2 aSpriteLocation;
attribute vec2 aSpriteSize;
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
attribute vec2 aTextureSize;

varying vec2 vTextureCoord;
varying vec2 vTextureSize;

void main() {
  // Convert from screen coords to clipSpace (-1,-1 to 1,1)
  vec2 clipSpace = (((aSpriteLocation + (aVertexPosition * aSpriteSize)) / uResolution) * 2.0) - 1.0;

  // Flip upside down, so 0,0 is at the top of the screen!
  clipSpace = clipSpace * vec2(1, -1);

  gl_Position = vec4(clipSpace, 0.0, 1.0);
  vTextureCoord = aTextureCoord;
  vTextureSize = aTextureSize;
}
# FRAGMENT SHADER
#ifdef GL_ES
precision highp float;
#endif

uniform sampler2D uSampler;

varying vec2 vTextureCoord;
varying vec2 vTextureSize; # Currently this must be in the range 0,0 - 1,1; but I want to pass in texture pixels

void main() {
  gl_FragColor = texture2D(uSampler, vTextureSize * vec2(vTextureCoord.s, vTextureCoord.t));
}

目前,用于我的片段着色器的vTextureSize0,0 - 1,1 范围内工作。为我的纹理提供像素坐标并将它们映射到某处的正确方法是什么?

我认为可能有一个用于基本 2D 渲染的通用/标准着色器集,它已经有一堆我可以提供的制服/属性,但我一直找不到。但是,如果存在这样的事情,我很想知道(因为我什至还没有进行旋转、alpha、着色和其他我可能想要在精灵上做的事情;-))

【问题讨论】:

    标签: opengl-es dart webgl shader fragment-shader


    【解决方案1】:

    虽然我在发布时找不到任何示例;获取完整的 TextureSize 并除以它可能并不罕见; XNA SpriteBatch 着色器is here online 就是这样做的。在没有其他人的情况下,这可能是一个很好的起点! :)

    (为方便起见,包括下面的源代码,因为它在提供的链接处以 zip 的形式打包。许可证是 MS-PL

    //-----------------------------------------------------------------------------
    // SpriteBatch.fx
    //
    // Microsoft XNA Community Game Platform
    // Copyright (C) Microsoft Corporation. All rights reserved.
    //-----------------------------------------------------------------------------
    
    
    // Input parameters.
    float2   ViewportSize    : register(c0);
    float2   TextureSize     : register(c1);
    float4x4 MatrixTransform : register(c2);
    sampler  TextureSampler  : register(s0);
    
    
    #ifdef XBOX360
    
    
    // Vertex shader for rendering sprites on Xbox.
    void SpriteVertexShader(int        index          : INDEX,
                            out float4 outputPosition : POSITION0,
                            out float4 outputColor    : COLOR0,
                            out float2 outputTexCoord : TEXCOORD0)
    {
        // Read input data from the vertex buffer.
        float4 source;
        float4 destination;
        float4 originRotationDepth;
        float4 effects;
        float4 color;
    
        int vertexIndex = index / 4;
        int cornerIndex = index % 4;
    
        asm
        {
            vfetch source,              vertexIndex, texcoord0
            vfetch destination,         vertexIndex, texcoord1
            vfetch originRotationDepth, vertexIndex, texcoord2
            vfetch effects,             vertexIndex, texcoord3
            vfetch color,               vertexIndex, texcoord4
        };
    
        // Unpack into local variables, to make the following code more readable.
        float2 texCoordPosition = source.xy;
        float2 texCoordSize = source.zw;
    
        float2 position = destination.xy;
        float2 size = destination.zw;
    
        float2 origin = originRotationDepth.xy;
        float rotation = originRotationDepth.z;
        float depth = originRotationDepth.w;
    
        // Which of the four sprite corners are we currently shading?
        float2 whichCorner;
    
        if      (cornerIndex == 0) whichCorner = float2(0, 0);
        else if (cornerIndex == 1) whichCorner = float2(1, 0);
        else if (cornerIndex == 2) whichCorner = float2(1, 1);
        else                       whichCorner = float2(0, 1);
    
        // Calculate the vertex position.
        float2 cornerOffset = (whichCorner - origin / texCoordSize) * size;
    
        // Rotation.
        float cosRotation = cos(rotation);
        float sinRotation = sin(rotation);
    
        position += mul(cornerOffset, float2x2(cosRotation, sinRotation, -sinRotation, cosRotation));
    
        // Apply the matrix transform.
        outputPosition = mul(float4(position, depth, 1), transpose(MatrixTransform));
    
        // Half pixel offset for correct texel centering.
        outputPosition.xy -= 0.5;
    
        // Viewport adjustment.
        outputPosition.xy /= ViewportSize;
        outputPosition.xy *= float2(2, -2);
        outputPosition.xy -= float2(1, -1);
    
        // Texture mirroring.
        whichCorner = lerp(whichCorner, 1 - whichCorner, effects);
    
        // Compute the texture coordinate.
        outputTexCoord = (texCoordPosition + whichCorner * texCoordSize) / TextureSize;
    
        // Simple color output.
        outputColor = color;
    }
    
    
    #else
    
    
    // Vertex shader for rendering sprites on Windows.
    void SpriteVertexShader(inout float4 position : POSITION0,
                            inout float4 color    : COLOR0,
                            inout float2 texCoord : TEXCOORD0)
    {
        // Apply the matrix transform.
        position = mul(position, transpose(MatrixTransform));
    
        // Half pixel offset for correct texel centering.
        position.xy -= 0.5;
    
        // Viewport adjustment.
        position.xy /= ViewportSize;
        position.xy *= float2(2, -2);
        position.xy -= float2(1, -1);
    
        // Compute the texture coordinate.
        texCoord /= TextureSize;
    }
    
    
    #endif
    
    
    // Pixel shader for rendering sprites (shared between Windows and Xbox).
    void SpritePixelShader(inout float4 color : COLOR0, float2 texCoord : TEXCOORD0)
    {
        color *= tex2D(TextureSampler, texCoord);
    }
    
    
    technique SpriteBatch
    {
        pass
        {
            VertexShader = compile vs_1_1 SpriteVertexShader();
            PixelShader  = compile ps_1_1 SpritePixelShader();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-27
      • 2016-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多