glBindAttribLocation 和 glGetAttribLocation

在将数据(顶点、纹理等)传送给GPU之前,我们需要获取到相对应缓冲的索引,之前我都是使用

GLint glGetAttribLocation(GLuint program,const GLchar *name);

其中,program指定查询的程序对象,name指定要查询位置的属性变量的名称,返回的就是属性变量的位置。

glGetAttribLocation查询由program指定的先前链接的程序对象,用于name指定的属性变量,并返回绑定到该属性变量的通用顶点属性的索引。 如果name是矩阵属性变量,则返回矩阵的第一列的索引。 如果指定的属性变量不是指定程序对象中的活动属性,或者名称以保留前缀“gl_”开头,则返回-1。

可以通过调用glBindAttribLocation随时指定属性变量名和通用属性索引之间的关联。 在调用glLinkProgram之前,属性绑定不会生效。 成功链接程序对象后,属性变量的索引值将保持固定,直到发生下一个链接命令。 如果链接成功,则只能在链接后查询属性值。 glGetAttribLocation返回上次为指定程序对象调用glLinkProgram时实际生效的绑定。 glGetAttribLocation不返回自上次链接操作以来指定的属性绑定。

一般也没啥问题,只要shader里面有的属性,在这里都可以获取的到。但是这次顶点着色器中的三个属性中的my_Color就是获取不到,返回-1,以下是两个着色器内容:

vs:

attribute vec4 my_Vertex;
attribute vec4 my_Color;
uniform   mat4 my_TransformMatrix;
attribute vec2 my_Texcoor;
varying vec2 vTexcoor;
varying vec4 color;

void main()
{
	vTexcoor = my_Texcoor;
	color = my_Color;
	gl_Position = my_TransformMatrix * my_Vertex;
}

fs:

varying vec4 color;
uniform sampler2D my_Sampler;
varying vec2 vTexcoor;

void main (void)
{
	vec4 tex = texture2D(my_Sampler, vTexcoor);
	gl_FragColor = tex;
}

接下来想查询一下有哪些激活的属性:

    GLint count;

     GLint size; // size of the variable
     GLenum type; // type of the variable (float, vec3 or mat4, etc)

     const GLsizei bufSize = 256; // maximum name length
     GLchar name[bufSize]; // variable name in GLSL
     GLsizei length; // name length

         glGetProgramiv(programHandle, GL_ACTIVE_ATTRIBUTES, &count);

      printf("Active Attributes: %d\n", count);
      for (int idx = 0; idx < count; idx++)
      {
       glGetActiveAttrib(programHandle, (GLuint)idx, bufSize, &length, &size, &type, name);

       printf("Attribute #%d Type: 0x%x Name: %s\n", idx, type, name);
       GLuint location = glGetAttribLocation(programHandle, name);
       printf("location = %d \n",location);
      }

结果也还是一样,没有my_Color.

纠结了好久,最终发现是因为shader在编译的时候做了优化,对于一些没有真正参与到计算的属性直接移除掉了,所以怎么找也找不到my_Color。

解决方案,使用glBindAttribLocation。

void glBindAttribLocation(GLuint program,   GLuint index, const GLchar *name);

其中,program指定要在其中建立关联的程序对象的句柄。index指定要绑定的通用顶点属性的索引。name指定一个以空终止符结尾的字符串,其中包含要绑定索引的顶点着色器属性变量的名称。

在调用glLinkProgram之前,属性绑定不会生效。成功链接程序对象后,通用属性的索引值保持固定(并且可以查询它们的值),直到发生下一个链接命令。

可以在任何顶点着色器对象绑定到指定程序对象之前调用glBindAttribLocation。也允许将通用属性索引绑定到从未在顶点着色器中使用的属性变量名称。

如果以前绑定了name,则该信息将丢失。因此,您不能将一个用户定义的属性变量绑定到多个索引,但您可以将多个用户定义的属性变量绑定到同一索引。

允许应用程序将多个用户定义的属性变量绑定到相同的通用顶点属性索引。这称为aliasing(别名),仅当可执行程序中只有一个别名属性处于活动状态时,或者如果没有通过着色器的路径消耗属于同一位置的一组属性的多个属性时,才允许使用别名。允许编译器和链接器假定没有进行别名,并且可以自由地使用仅在没有别名的情况下工作的优化。不需要OpenGL实现来进行错误检查以检测别名。由于无法绑定标准属性,因此无法使用常规属性对通用属性进行别名(通用属性0除外)。

调用glLinkProgram时,链接器将绑定未显式绑定的活动属性。可以通过调用glGetAttribLocation来查询分配的位置。

调用glBindAttribLocation时,OpenGL会复制名称字符串,因此应用程序可以在函数返回后立即释放其名称字符串的副本。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是一个简单的例子,演示如何使用OpenGL ES和MediaCodec将RGB图像转换为MP4视频。 首先,我们需要使用OpenGL ES将RGB图像渲染到纹理上。以下是一个简单的渲染器类: ```cpp class Renderer { public: Renderer(); ~Renderer(); void init(); void render(const uint8_t* data, int width, int height); private: GLuint mTexture; GLuint mProgram; GLuint mVertexShader; GLuint mFragmentShader; GLint mPositionHandle; GLint mTexCoordHandle; GLint mTextureHandle; }; ``` 在Renderer的构造函数中,我们可以编译和链接顶点着色器和片段着色器: ```cpp Renderer::Renderer() { const char* vertexShaderSrc = "attribute vec4 position;\n" "attribute vec2 texCoord;\n" "varying vec2 vTexCoord;\n" "void main() {\n" " gl_Position = position;\n" " vTexCoord = texCoord;\n" "}"; const char* fragmentShaderSrc = "precision mediump float;\n" "varying vec2 vTexCoord;\n" "uniform sampler2D texture;\n" "void main() {\n" " gl_FragColor = texture2D(texture, vTexCoord);\n" "}"; mVertexShader = loadShader(GL_VERTEX_SHADER, vertexShaderSrc); mFragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentShaderSrc); mProgram = glCreateProgram(); glAttachShader(mProgram, mVertexShader); glAttachShader(mProgram, mFragmentShader); glBindAttribLocation(mProgram, ATTRIB_VERTEX, "position"); glBindAttribLocation(mProgram, ATTRIB_TEXTURE, "texCoord"); glLinkProgram(mProgram); mPositionHandle = glGetAttribLocation(mProgram, "position"); mTexCoordHandle = glGetAttribLocation(mProgram, "texCoord"); mTextureHandle = glGetUniformLocation(mProgram, "texture"); } ``` 在render函数中,我们将RGB数据上传到纹理中,并在渲染器中绘制纹理: ```cpp void Renderer::render(const uint8_t* data, int width, int height) { if (!data) { return; } if (!mTexture) { glGenTextures(1, &mTexture); glBindTexture(GL_TEXTURE_2D, mTexture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); } glBindTexture(GL_TEXTURE_2D, mTexture); glUseProgram(mProgram); glEnableVertexAttribArray(mPositionHandle); glEnableVertexAttribArray(mTexCoordHandle); glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gVertices); glVertexAttribPointer(mTexCoordHandle, 2, GL_FLOAT, GL_FALSE, 0, gTexCoords); glUniform1i(mTextureHandle, 0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableVertexAttribArray(mPositionHandle); glDisableVertexAttribArray(mTexCoordHandle); } ``` 接下来,我们使用MediaCodec将渲染的帧编码为MP4视频。以下是一个简单的编码器类: ```cpp class Encoder { public: Encoder(); ~Encoder(); void init(int width, int height); void encodeFrame(const uint8_t* data, int64_t pts); void flush(); private: AMediaCodec* mEncoder; AMediaMuxer* mMuxer; int mTrackIndex; int mFrameIndex; bool mIsStarted; }; ``` 在Encoder的构造函数中,我们可以创建MediaCodec和MediaMuxer: ```cpp Encoder::Encoder() { mEncoder = AMediaCodec_createEncoderByType("video/avc"); AMediaFormat* format = AMediaFormat_new(); AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "video/avc"); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, 2000000); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, 30); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 1); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, COLOR_FormatSurface); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, 720); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, 1280); AMediaCodec_configure(mEncoder, format, nullptr, nullptr, AMEDIACODEC_CONFIGURE_FLAG_ENCODE); AMediaFormat_delete(format); mTrackIndex = -1; mFrameIndex = 0; mIsStarted = false; } ``` 在init函数中,我们将MediaCodec的输出Surface传递给MediaMuxer,并启动MediaCodec和MediaMuxer: ```cpp void Encoder::init(int width, int height) { if (mIsStarted) { return; } AMediaCodec_start(mEncoder); AMediaMuxer_start(mMuxer); ANativeWindow* window = AMediaCodec_createInputSurface(mEncoder); AMediaMuxer_addTrack(mMuxer, AMediaCodec_getOutputFormat(mEncoder)); AMediaMuxer_start(mMuxer); mTrackIndex = 0; mIsStarted = true; } ``` 在encodeFrame函数中,我们从输出Surface中获取编码的数据,并将其写入MediaMuxer: ```cpp void Encoder::encodeFrame(const uint8_t* data, int64_t pts) { if (!mIsStarted) { return; } ANativeWindow* window = AMediaCodec_createInputSurface(mEncoder); AMediaCodec_configure(mEncoder, nullptr, nullptr, nullptr, 0); AMediaCodec_start(mEncoder); AMediaSurface* surface = AMediaSurface_fromSurfaceTexture((ASurfaceTexture*) window); AMediaCodec_setOutputSurface(mEncoder, surface); AMediaSurface_release(surface); AMediaCodecBufferInfo bufferInfo; int outputBufferIndex = AMediaCodec_dequeueOutputBuffer(mEncoder, &bufferInfo, 0); if (outputBufferIndex >= 0) { AMediaCodec_releaseOutputBuffer(mEncoder, outputBufferIndex, true); } int inputBufferIndex = AMediaCodec_dequeueInputBuffer(mEncoder, 0); if (inputBufferIndex >= 0) { AMediaCodecInputBuffer* inputBuffer = AMediaCodec_getInputBuffer(mEncoder, inputBufferIndex); size_t bufferSize = AMediaCodec_getInputBufferSize(mEncoder); uint8_t* buffer = AMediaCodecInputBuffer_getBuffer(inputBuffer); memcpy(buffer, data, bufferSize); AMediaCodec_queueInputBuffer(mEncoder, inputBufferIndex, 0, bufferSize, pts, 0); } outputBufferIndex = AMediaCodec_dequeueOutputBuffer(mEncoder, &bufferInfo, 0); if (outputBufferIndex >= 0) { AMediaCodecBufferInfo bufferInfo; AMediaCodec_getOutputBufferInfo(mEncoder, outputBufferIndex, &bufferInfo); uint8_t* outputBuffer = AMediaCodec_getOutputBuffer(mEncoder, outputBufferIndex); AMediaMuxer_writeSampleData(mMuxer, mTrackIndex, outputBuffer, &bufferInfo); AMediaCodec_releaseOutputBuffer(mEncoder, outputBufferIndex, false); mFrameIndex++; } } ``` 在flush函数中,我们停止MediaCodec和MediaMuxer: ```cpp void Encoder::flush() { if (!mIsStarted) { return; } AMediaCodec_signalEndOfInputStream(mEncoder); AMediaCodecBufferInfo bufferInfo; while (true) { int outputBufferIndex = AMediaCodec_dequeueOutputBuffer(mEncoder, &bufferInfo, 0); if (outputBufferIndex >= 0) { AMediaCodec_releaseOutputBuffer(mEncoder, outputBufferIndex, true); } else if (outputBufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) { AMediaFormat* format = AMediaCodec_getOutputFormat(mEncoder); AMediaMuxer_addTrack(mMuxer, format); mTrackIndex = AMediaMuxer_addTrack(mMuxer, format); AMediaMuxer_start(mMuxer); } else { break; } } AMediaCodec_stop(mEncoder); AMediaCodec_delete(mEncoder); AMediaMuxer_stop(mMuxer); AMediaMuxer_delete(mMuxer); mIsStarted = false; } ``` 在使用时,我们可以像这样使用渲染器和编码器: ```cpp Renderer renderer; Encoder encoder; renderer.init(); encoder.init(width, height); for (int i = 0; i < numFrames; i++) { renderer.render(data[i], width, height); encoder.encodeFrame(data[i], i * 1000000 / 30); } encoder.flush(); ``` 请注意,这只是一个非常简单的例子,实际上要实现一个完整的视频编码器需要更多的步骤和细节。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值