OpenGL高级用法之坐标变换

141 阅读2分钟

如何通过在GPU中实现顶点的计算,且渲染多个视频时,每个视频都要保持原始的宽高比绘制,且选中某个视频,能绘制出这个视频的边框

两个步骤

实现所有纹理保持宽高比绘制

  • 多个视频纹理渲染,都使用同一个由1和-1组合成的VBO,通过在着色器中修改顶点坐标。
  • 通过uniform变量在着色器中重新计算顶点坐标
// 当前纹理宽高比
float curAspect = curTexSize.width / curTexSize.height;
// 主纹理宽高比
float mainAspect = mainTexSize.width / mainTexSize.height;

if (!mainAspect || !curAspect) {
    return;
}

Size aspectRatio = Size(1, 1);
// 处理主视频纹理、画中画视频纹理宽高比问题,保持每个视频资源的原始宽高比
if (curTexSize > mainAspect) {
    aspectRatio.width = 1;
    aspectRatio.height = mainAspect/curTexSize;
    
    // 保持宽高比不变,用于计算四个顶点
    m_size.height *= mainAspect/curTexSize;
} else {
    aspectRatio.width = curTexSize/mainAspect;
    aspectRatio.height = 1;
    
    // 保持宽高比不变,用于计算四个顶点
    m_size.width *= curTexSize/mainAspect;
}

/// 通过中心点和宽高计算四个顶点
/// - Parameter angle: 旋转角度值
void upRotate(float angle) {
    m_rotate = angle;
    // 计算旋转后的四个点
    float cosA = cos(angle);
    float sinA = sin(angle);
    
    // 左上,左和上需要减
    float x1 = cosA * (-m_size.width/2) - sinA * (-m_size.height/2) + m_center.x;
    float y1 = sinA * (-m_size.width/2) + cosA * (-m_size.height/2) + m_center.y;
    // 右上
    float x2 = cosA * (m_size.width/2) - sinA * (-m_size.height/2) + m_center.x;
    float y2 = sinA * (m_size.width/2) + cosA * (-m_size.height/2) + m_center.y;
    // 右下
    float x3 = (cosA * (m_size.width/2)) - sinA * (m_size.height/2) + m_center.x;
    float y3 = (sinA * (m_size.width/2)) + cosA * (m_size.height/2) + m_center.y;
    // 左下
    float x4 = (cosA * (-m_size.width/2)) - sinA * (m_size.height/2) + m_center.x;
    float y4 = (sinA * (-m_size.width/2)) + cosA * (m_size.height/2) + m_center.y;

    Vertex2_4 vertexs = Vertex2_4({x1,y1, x2,y2, x3,y3, x4,y4});
}

着色器代码如下

attribute vec4 position;
attribute vec4 inputTextureCoordinate;
varying vec2 textureCoordinate;
uniform vec2 move;
uniform float scale;
uniform float rotate;
uniform vec2 viewAspectRatio;

mat4 getTransform() { 
    // 平移
    mat4 translateMat = mat4(1.0);
    translateMat[3] = vec4(move.x, move.y, 0.0, 1.0);
    // 旋转
    mat4 rotateMat = mat4(1.0);
    float c = cos(rotate);
    float s = sin(rotate);
    rotateMat[0] = vec4(c, -s, 0.0, 0.0);
    rotateMat[1] = vec4(s, c, 0.0, 0.0);
    // 等比缩放
    mat4 scaleMat = mat4(1.0);
    scaleMat[0][0] = scale;
    scaleMat[1][1] = scale;
    
    // 保持宽高比
    mat4 arMat = mat4(1.0);
    arMat[0][0] = viewAspectRatio.x;
    arMat[1][1] = viewAspectRatio.y;

    return translateMat * rotateMat * scaleMat * arMat;
}

void main() {
    mat4 transform = getTransform();
    gl_Position = transform * position;
    textureCoordinate = inputTextureCoordinate.xy;
}

再实现点击某个纹理,返回该纹理对应UIView上的四个顶点