2016-11-25 1 views
0

Я сузил проблему. У меня есть два атрибута, указывающие на одни и те же данные. Это прекрасно работает при сборке на родном C++. Однако, когда построен с emscripten, то Консоль JavaScript показывает следующее сообщение об ошибке на каждом кадре:'glDrawArrays: попытка получить доступ к вершинам диапазона в атрибуте 1' на Emscripten/OpenGL-коде (работает на родном C++)

'glDrawArrays: attempt to access out of range vertices in attribute 1' 

Когда я закомментируйте строку «glEnableVertexAttribArray», чтобы включить второй атрибут, я не получаю эту ошибку.

Ниже приведен мой код. Начну с созданием буфера данных:

GLfloat rectangleData[] = 
{ 
    -.5f, -.5f,  0,1, 
    -.5f, .5f,  0,0, 
    .5f, .5f,  1,0, 
    .5f, -.5f,  1,1, 
    -.5f, -.5f,  0,1 
}; 
glGenBuffers(1, &rectangleBuffer); 
glBindBuffer(GL_ARRAY_BUFFER, rectangleBuffer); 
glBufferData(
     GL_ARRAY_BUFFER, sizeof(rectangleData), 
     rectangleData, GL_STATIC_DRAW); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 

Вот соответствующий отрывок из моей текстурированной коды четырехъядерных чертежной:

glBindBuffer(GL_ARRAY_BUFFER, rectangleBuffer); 

int vertexPosition = Shader::getParameterInfo("vertexPosition")->id; 
glVertexAttribPointer(
     vertexPosition, 2, GL_FLOAT, 
     GL_FALSE, 16, BUFFER_OFFSET(0)); 
glEnableVertexAttribArray(vertexPosition); 

int vertexTexCoord = Shader::getParameterInfo("vertexTexCoord")->id; 
glVertexAttribPointer(
     vertexTexCoord, 2, GL_FLOAT, 
     GL_FALSE, 16, BUFFER_OFFSET(0)); 
glEnableVertexAttribArray(vertexTexCoord); 

glDrawArrays(GL_TRIANGLE_FAN, 0, 5); 

Обратите внимание, что я настроил второй атрибут, чтобы указать на то же самое данных в качестве первого (для уменьшения сложности при отладке). Я здесь довольно превзойден и могу действительно использовать свежую/опытную перспективу.

EDIT: Вот что BUFFER_OFFSET выглядит следующим образом:

#define BUFFER_OFFSET(i) ((char *)NULL + (i)) 

Источник: How to cast int to const GLvoid*?

EDIT: Для чего это стоит, вот эквивалент Emscripten генерируется JS код. Я пошлю любой JS-код, если это потребуется.

dest=$rectangleData; src=2328; stop=dest+80|0; do { 
HEAP32[dest>>2]=HEAP32[src>>2]|0; dest=dest+4|0; src=src+4|0; } while 
((dest|0) < (stop|0)); 
_glGenBuffers(1,(2300|0)); 
$30 = HEAP32[2300>>2]|0; 
_glBindBuffer(34962,($30|0)); 
_glBufferData(34962,80,($rectangleData|0),35044); 
_glBindBuffer(34962,0); 

$11 = HEAP32[2300>>2]|0; 
_glBindBuffer(34962,($11|0)); 
$12 = (__ZN8platform6Shader16getParameterInfoEPKc(17356)|0); 
$13 = HEAP32[$12>>2]|0; 
$vertexPosition = $13; 
$14 = $vertexPosition; 
_glVertexAttribPointer(($14|0),2,5126,0,16,(0|0)); 
$15 = $vertexPosition; 
_glEnableVertexAttribArray(($15|0)); 
$16 = (__ZN8platform6Shader16getParameterInfoEPKc(17379)|0); 
$17 = HEAP32[$16>>2]|0; 
$vertexTexCoord = $17; 
$18 = $vertexTexCoord; 
_glVertexAttribPointer(($18|0),2,5126,0,16,(0|0)); 
$19 = $vertexTexCoord; 
_glEnableVertexAttribArray(($19|0)); 
_glDrawArrays(6,0,5); 

Edit: А еще лучше, я приведу ссылку на код JS работает на GitHub, и C++ код тоже (он находится в нижней части в "DrawImage()"):

https://rawgit.com/jon-heard/Native-WebGL-framework/c134e35ac94fdf3243a9662353ad2227f8c84b43/Native-WebGL-framework/web/index.html

https://github.com/jon-heard/Native-WebGL-framework/blob/c134e35ac94fdf3243a9662353ad2227f8c84b43/Native-WebGL-framework/src/platform/draw.cpp

+0

Пара вопросов. Является 'sizeof (rectangleBuffer)' действительно '20 * sizeof (GLfloat)', а не размером указателя? И что делает 'BUFFER_OFFSET'? –

+0

@KirillDmitrenko: Если OP написал это именно так, тогда да, 'sizeof (rectangleData)' будет оценивать общий размер массива (он не будет работать, если массив передан как параметр функции или деградация указателя). – datenwolf

+0

How выглядит соответствующий код javascript? C++ выглядит правильно. – BDL

ответ

2

Этот вопрос у вас есть один вершинный шейдер, всегда использует 2 ПРИЗНАКИ

var gl = document.createElement("canvas").getContext("webgl"); 
 
var program = twgl.createProgramFromScripts(gl, ["vs", "fs"]); 
 

 
log("list of used attributes"); 
 
log("-----------------------"); 
 

 
var numAttribs = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES); 
 
for (var ii = 0; ii < numAttribs; ++ii) { 
 
    var attribInfo = gl.getActiveAttrib(program, ii); 
 
    if (!attribInfo) { 
 
    break; 
 
    } 
 
    log(gl.getAttribLocation(program, attribInfo.name), attribInfo.name); 
 
} 
 

 
function log(...args) { 
 
    var div = document.createElement("div"); 
 
    div.textContent = [...args].join(" "); 
 
    document.body.appendChild(div); 
 
}
<script src="https://twgljs.org/dist/2.x/twgl.min.js"></script> 
 
<script type="foo" id="vs"> 
 
uniform mat4 sceneTransform; 
 
uniform mat4 rotationTransform; 
 
uniform vec2 objectPosition; 
 
uniform vec2 objectScale; 
 
attribute vec2 vertexPosition; 
 
attribute vec2 vertexTexCoord; 
 
varying vec2 UVs; 
 
void main() 
 
{ 
 
    UVs = vertexTexCoord; 
 
    gl_Position = 
 
    sceneTransform * 
 
    vec4(vertexPosition * objectScale + objectPosition, 0, 1); 
 
} 
 
</script> 
 
<script type="foo" id="fs"> 
 
precision mediump float; 
 

 
uniform vec3 objectColor; 
 
uniform float objectOpacity; 
 

 
void main() 
 
{ 
 
\t gl_FragColor = vec4(objectColor, objectOpacity); 
 
} 
 
</script>

При вызове DrawCircle присвоить оба этих атрибутов буферов, то в вашем коде выше, если вы ничего не делаете во втором атрибуте, он все еще указывает на предыдущий буфер.Этот буфер слишком мал для вашего вызова рисования, и вы получаете сообщение об ошибке.

WebGL не будет жаловаться на неиспользуемые атрибуты, но он будет жаловаться на используемые атрибуты. Вы всегда должны указывать атрибуты, необходимые вашему шейдеру.

В вашем случае у вас есть по крайней мере 2 варианта

  1. изменить код, чтобы ваш шейдер использует только один атрибут

    У вас есть только один вершинный шейдер, если я прочитал код правильно , Для тех случаев, когда шейдер фрагмента не использует координаты текстуры, используйте другой вершинный шейдер, который их не предоставляет.

  2. Отключить атрибут так, что он использует постоянное значение

    gl.disableVertexAttribArray(...) 
    

    означает, что этот атрибут будет использовать постоянное значение, поставляемый

    gl.vertexAttribXXX 
    

1, возможно, лучше, чем 2, так как ваш шейдер вершин не будет тратить время на чтение из атрибута и копирование его на переменную, только чтобы не использовать его в шейдере фрагмента.

+0

Ах да. Это имеет большой смысл. Я использую один вершинный шейдер для рендеринга двух атрибутов и рендеринга с одним атрибутом. Он сохраняет привязку атрибута вершины при возврате к рендерингу с одним атрибутом. Я рассмотрю возможность настройки моего кода для использования разных вершинных шейдеров в зависимости от обстоятельств. –

0

ошибка действительно возникает из другого места, формируют вызов отрисовки из drawCircle функции. По внешнему виду вы забыли отключить неиспользуемые массивы атрибутов. Here вы используете только один атрибут, привязанный к 0, но ошибка для атрибута 1. Очевидно, вы включили массив вершин для атрибута 1 где-то и забыли отключить его. Теперь обратный вызов проверяет, является ли он обязательным, обнаруживает, что он неверен и возникает ошибка GL_INVALID_OPERATION. The spec says, что проверка вне пределов должна выполняться только для атрибутов, используемых в текущей программе, но по внешнему виду at least Chromium просто проверяет все связанные с массивом.

UPD. Я неправильно понял код Хромиума. Как указано в @gman, он действительно проверяет, что вне зависимости от доступа используются только атрибуты, используемые текущей программой.

+0

Это замечательно. Спасибо Кирилл! Я предполагаю, что для этого требуется некоторая отладка JS, чтобы точно определить. Я ценю ваши усилия и буду держать этот параметр в виду для будущей отладки. код выглядит зверски, но параллель с исходным кодом C++, поэтому, вероятно, это не так плохо, как кажется. –

+0

РЕШЕНИЕ: для записи я решил это, вызвав gldisableVertexAttribArray() для каждого атрибута после завершения каждого вызова рисования. webgl или, по крайней мере, emscripten, в настоящее время требуется дополнительный шаг. –

+0

@JonathanHeard Вы также можете использовать [объекты массива вершин] (https: // www .khronos.org/registry/webgl/extensions/OES_vertex_array_object /) расширение, когда оно доступно –

0

Я видел эту ошибку, когда пытался восстановить this и совершил ошибку. Код учебника можно найти here. Однако я получил эту ошибку, потому что я определил цветной буфер ПОСЛЕ установки данных в буфере позиции. Я исправил это путем определения цветового буфера, а затем определил буфер позиции и данные привязки к буфере. Это сделал трюк. Поэтому в заключение эта ошибка может возникнуть, если мы не будем определять атрибуты последовательно.

Смежные вопросы