gpt4 book ai didi

c++ - 使用 Emscripten 将 OpenGL ES 转换反馈数据返回给主机

转载 作者:行者123 更新时间:2023-11-30 05:04:36 25 4
gpt4 key购买 nike

使用 GLFW,下面的 C++ OpenGL ES 代码计算五个数字的平方根并在命令行上输出它们。该代码使用了转换反馈。当我在 Ubuntu 17.10 上编译时,使用以下命令,我得到了我期望的结果:

$ g++ tf.cpp -lGL -lglfw

但是,如果我使用 Emscripten,则会抛出异常,这表明glMapBufferRange 仅在访问为 MAP_WRITE|INVALIDATE_BUFFER 时才受支持。我确实想阅读而不是写作,所以也许我不应该使用 glMapBufferRange,但是我可以使用什么来代替呢?我在 Firefox 和 Chromium 上都试过了。我使用 Emscripten 编译的命令是:

$ em++ -std=c++11 tf.cpp -s USE_GLFW=3 -s USE_WEBGL2=1 -s FULL_ES3=1 -o a.out.html

代码如下:

#include <iostream>

#define GLFW_INCLUDE_ES3
#include <GLFW/glfw3.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

static const GLuint WIDTH = 800;
static const GLuint HEIGHT = 600;
static const GLchar *vertex_shader_src =
"#version 300 es\n"
"precision mediump float;\n"
"in float inValue;\n"
"out float outValue;\n"
"void main() {\n"
" outValue = sqrt(inValue);\n"
"}\n";

// Emscripten complains if there's no fragment shader
static const GLchar *fragment_shader_src =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 colour;\n"
"void main() {\n"
" colour = vec4(1.0, 1.0, 0.0, 1.0);\n"
"}\n";

static const GLfloat vertices[] = {
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
};

GLint get_shader_prog(const char *vert_src, const char *frag_src = "")
{
enum Consts { INFOLOG_LEN = 512 };
GLchar infoLog[INFOLOG_LEN];
GLint fragment_shader, vertex_shader, shader_program, success;
shader_program = glCreateProgram();

auto mk_shader = [&](GLint &shader, const GLchar **str, GLenum shader_type) {
shader = glCreateShader(shader_type);
glShaderSource(shader, 1, str, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, INFOLOG_LEN, NULL, infoLog);
std::cout << "ERROR::SHADER::COMPILATION_FAILED\n" << infoLog << '\n';
}
glAttachShader(shader_program, shader);
};

mk_shader(vertex_shader, &vert_src, GL_VERTEX_SHADER);
mk_shader(fragment_shader, &frag_src, GL_FRAGMENT_SHADER);

const GLchar* feedbackVaryings[] = { "outValue" };
glTransformFeedbackVaryings(shader_program, 1, feedbackVaryings,
GL_INTERLEAVED_ATTRIBS);

glLinkProgram(shader_program);
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader_program, INFOLOG_LEN, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << '\n';
}
glUseProgram(shader_program);

glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return shader_program;
}

int main(int argc, char *argv[])
{
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
GLFWwindow *window = glfwCreateWindow(WIDTH, HEIGHT, __FILE__, NULL, NULL);
glfwMakeContextCurrent(window);

GLuint shader_prog = get_shader_prog(vertex_shader_src, fragment_shader_src);
GLint inputAttrib = glGetAttribLocation(shader_prog, "inValue");

glViewport(0, 0, WIDTH, HEIGHT);

GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

GLfloat data[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };

GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);

glVertexAttribPointer(inputAttrib, 1, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(inputAttrib);

GLuint tbo;
glGenBuffers(1, &tbo);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(data),
nullptr, GL_STATIC_READ);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
glEnable(GL_RASTERIZER_DISCARD);

glBeginTransformFeedback(GL_POINTS);
glDrawArrays(GL_POINTS, 0, 5);
glEndTransformFeedback();

glDisable(GL_RASTERIZER_DISCARD);
glFlush();

GLfloat feedback[5]{1,2,3,4,5};
void *void_buf = glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER,0,
sizeof(feedback), GL_MAP_READ_BIT);
GLfloat *buf = static_cast<GLfloat *>(void_buf);
for (int i = 0; i < 5; i++)
feedback[i] = buf[i];
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);

for (int i = 0; i < 5; i++)
std::cout << feedback[i] << ' ';
std::cout << std::endl;

glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &tbo);
glDeleteVertexArrays(1, &vao);
glfwTerminate();

return 0;
}

最佳答案

正如另一个答案所提到的,WebGL 2.0 接近于 OpenGL ES 3.0,但令人困惑的是没有定义 glMapBufferRange() 函数,因此 Emscripten 尝试仅模拟该函数的部分功能。

然而,Real WebGL 2.0 公开了 glGetBufferSubData() 模拟,它在 OpenGL ES 中不存在,但在桌面 OpenGL 中存在。该方法可以通过 EM_ASM_ 包装在代码中:

void myGetBufferSubData (GLenum theTarget, GLintptr theOffset, GLsizeiptr theSize, void* theData)
{
#ifdef __EMSCRIPTEN__
EM_ASM_(
{
Module.ctx.getBufferSubData($0, $1, HEAPU8.subarray($2, $2 + $3));
}, theTarget, theOffset, theData, theSize);
#else
glGetBufferSubData (theTarget, theOffset, theSize, theData);
#endif
}

取回 VBO 数据在多平台代码中很麻烦:

  1. OpenGL 1.5+
    • glGetBufferSubData():是
    • glMapBufferRange():是
  2. OpenGL ES 2.0
    • glGetBufferSubData():否
    • glMapBufferRange():否
  3. OpenGL ES 3.0+
    • glGetBufferSubData():否
    • glMapBufferRange():是
  4. WebGL 1.0
    • glGetBufferSubData():否
    • glMapBufferRange():否
  5. WebGL 2.0
    • glGetBufferSubData():是
    • glMapBufferRange():否

这样:

  • 桌面 OpenGL 提供了最大的灵 active 。
  • OpenGL ES 2.0 和 WebGL 1.0 没有机会检索数据。
  • OpenGL ES 3.0+ 仅提供映射缓冲区。
  • WebGL 2.0 仅提供 getBufferSubData()。

关于c++ - 使用 Emscripten 将 OpenGL ES 转换反馈数据返回给主机,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48808993/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com