Решение
Я наконец-то понял, как ее решить:
Когда я поместил инициализацию контекста WebGL в самый первый вызов фрейма анимации, в то время как фактический рендеринг выполняется во всех других вызовах, он работал, как и ожидалось, на моем устройстве Android. Вот main.js
Я изменился:
export default class Main {
constructor() {
this.render = this.render_first
requestAnimationFrame(() => this.animate())
}
showmsg(t,c) {
wx.showModal({
title: ""+t,
content: ""+c,
showCancel: false,
confirmText:'OK',
success: function(res){}
});
}
animate() {
this.render();
requestAnimationFrame(() => this.animate())
}
render_first() {
this.render = this.render_normal
var _this = this
this.domElement = canvas
var contextAttributes = {
alpha: false,
depth: true,
stencil: false,
antialias: false
}
this.domElement.addEventListener("webglcontextlost", function(e){
_this.showmsg("WebGL","Context lost");
}, false)
this.domElement.addEventListener("webglcontextrestored", function(e){
_this.showmsg("WebGL","Context restored");
}, false)
this._gl = this.domElement.getContext( 'webgl', contextAttributes ) || this.domElement.getContext( 'experimental-webgl', contextAttributes )
var _gl = this._gl
var vsrc = ""
vsrc += "uniform mat4 uModelView;"
vsrc += "uniform mat4 uProjView;"
vsrc += "attribute highp vec4 aPosition;"
vsrc += "void main(void) {"
vsrc += " gl_Position = ( uProjView * uModelView ) * aPosition;"
vsrc += "}"
var vid = _gl.createShader(_gl.VERTEX_SHADER)
_gl.shaderSource(vid,vsrc)
_gl.compileShader(vid)
if (!_gl.getShaderParameter(vid, _gl.COMPILE_STATUS)) {
console.error("Vertex shader failed: ", _gl.getShaderInfoLog(vid))
}
this._vid = vid
var fsrc = ""
fsrc += "void main(void) {"
fsrc += " gl_FragColor = vec4(1.0,1.0,0.0,1.0);"
fsrc += "}"
var fid = _gl.createShader(_gl.FRAGMENT_SHADER)
_gl.shaderSource(fid,fsrc)
_gl.compileShader(fid)
if (!_gl.getShaderParameter(fid, _gl.COMPILE_STATUS)) {
console.error("Fragment shader failed: ", _gl.getShaderInfoLog(fid))
}
this._fid = fid
var pid = _gl.createProgram()
_gl.attachShader(pid,vid)
_gl.attachShader(pid,fid)
_gl.linkProgram(pid)
if (!_gl.getProgramParameter(pid, _gl.LINK_STATUS)) {
let info = _gl.getProgramInfoLog(pid)
console.error("Program link failed:", info )
}
_gl.useProgram(pid)
this._pid = pid
var aPosition = _gl.getAttribLocation(pid,"aPosition")
var uModelView = _gl.getUniformLocation(pid,"uModelView")
var uProjView = _gl.getUniformLocation(pid,"uProjView")
_gl.uniformMatrix4fv( uModelView, false, [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] )
_gl.uniformMatrix4fv( uProjView, false, [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] )
this.uni = [uModelView, uProjView]
this.phase = 0.0
var data = [0,0,0,1,0,0,0,1,0]
var idata = [0,1,2]
var vbID = _gl.createBuffer()
_gl.bindBuffer(_gl.ARRAY_BUFFER,vbID)
_gl.bufferData(_gl.ARRAY_BUFFER, new Float32Array(data), _gl.STATIC_DRAW)
var vbiID = _gl.createBuffer();
_gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, vbiID)
_gl.bufferData(_gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(idata), _gl.STATIC_DRAW)
_gl.vertexAttribPointer( aPosition, 3, _gl.FLOAT, false, 0, 0 )
_gl.enableVertexAttribArray( aPosition )
_gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, vbiID)
this.vb = [vbID,vbiID]
_gl.clearColor(1.0,0.0,1.0,1.0)
}
render_normal() {
var _gl = this._gl
var et = 60.0 / 1000.0
this.phase += 180.0 * 60.0 / 1000.0
var py = Math.sin(this.phase * Math.PI/180.0) * 0.5
_gl.uniformMatrix4fv( this.uni[0], false, [1,0,0,0,0,1,0,0,0,0,1,0,py,0,0,1] )
_gl.clear( _gl.COLOR_BUFFER_BIT )
_gl.drawElements(_gl.TRIANGLES, 3, _gl.UNSIGNED_SHORT, 0)
}
}
В чем проблема
Похоже, что на реальном устройстве мини-игра WeChat запускает цикл анимации в отдельном потоке, а не в основном выполнении JavaScript . Поскольку контекст WebGL (OpenGL) доступен только в одном потоке (за исключением собственных приложений, в которых несколько потоков могут совместно использовать один и тот же контекст), на устройстве произойдет сбой, поскольку функция рендеринга попытается получить доступ к контексту gl, инициализированному в другом потоке.
Это не было видно в WeChat Developer Tools, поскольку этот инструмент не имитирует точно, как работает архитектура устройства, а анимация и выполнение JavaScript, по-видимому, происходят в одном потоке.