WeChat (WebGL) MiniGame не работает на устройстве, но работает в devtool

1

Что я хочу сделать

Я пытаюсь перенести свой собственный движок на основе WebGL в среду WeChat MiniGame, и в настоящее время пытаюсь создать контекст WebGL, который будет очищен розовым цветом:

Изображение 174551

В чем проблема

Я следовал за примерами, которые предоставляет Tencent, а также примером ThreeJS по настройке игрового проекта. Он прекрасно работает в WeChat Developer Tool (как видно на изображении выше), однако, когда я пытаюсь открыть его на своем устройстве (телефон Android), он застревает на экране загрузки 100%:

Изображение 174551

Это остается примерно в течение 1 минуты, а затем показывает черный экран.

Мой код

В моем коде нет загрузки ресурсов. Вот что находится в моем main.js:


var ctx = canvas.getContext('webgl', {
  antialias: true,
  depth: true,
  preserveDrawingBuffer: true
});

ctx.viewport(0,0,ctx.canvas.width,ctx.canvas.height)
ctx.colorMask(true,true,true,true)
ctx.depthMask(true)
ctx.enable(ctx.BLEND)
ctx.blendFunc(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA)
ctx.clearColor(1.0,0.0,1.0,1.0)

export default class Main {

  constructor() {
    window.requestAnimationFrame(this.loop.bind(this), canvas)
  }

  render() {
    ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT)
  }

  update() {

  }

  loop() {
    this.update()
    this.render()
    window.requestAnimationFrame(this.loop.bind(this), canvas)
  }
}

Мой game.js также прост:

import './weapp-adapter/index.js'
import './symbol'
import Main from './js/main'
new Main()

Мой game.json содержит только следующее:

{
    "deviceOrientation": "portrait"
}

Дополнительная информация

Я также заметил, что когда я пробую пример Threejs (который работает на устройстве) и комментирует строки в функции рендеринга, он будет вести себя так же (зависает при 100% загрузке).

Теги:
webgl
wechat

1 ответ

0
Лучший ответ

Решение

Я наконец понял, как решить эту проблему:

Когда я поместил инициализацию контекста 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, похоже, происходят в одном потоке.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню