deepkolos / three-platformize

一个让 THREE 平台化的项目,目前已适配微信,淘宝,头条小程序,微信小游戏
533 stars 82 forks source link

Working screenshot on iphone? #8

Closed louiselessel closed 3 years ago

louiselessel commented 3 years ago

Hi!

I found your code snippet here https://juejin.cn/post/6920981822864097288 It works great in the WeChat Dev Tools and on Android phones, but have you been able to get it to work on an iPhone? It does not work on the iPhone 8 and 10 that I tested it on.

It appears the readPixels return all 0 values.

Thank you for your great work on three-platformize.

deepkolos commented 3 years ago

可以加个重试机制,手动判断下是否有像素,重试几次。

晚点有空我再加个测试用例到three-platformize-wechat-demo里吧

louiselessel commented 3 years ago

Thank you! And thank you again for this tool! It makes my life so much easier!

I tried printing it out every frame, but it was all 0's every frame. I wonder if it could be an iphone problem or whether there is a particular way to set it up. It works great in the IDE on a macbook.

deepkolos commented 3 years ago

可以先试试new 一个RenderTarget然后在用WebGLRenderer.readRenderTargetPixels

// 在渲染循环里检测checkFramebufferStatus状态,完成后再读取像素
const render = () => {
  if (this.disposing) return
  requestAnimationFrame(render);
  demo.update()
  renderer.render(scene, camera);

  if (this.screenshotResolve) {

    // 也可以把这个去掉试试,或者new 一个renderTarget,然后再readRenderTargetPixels

    // if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) {

    // }
      // @ts-ignore
      gl.readPixels(0, 0, frameBuffer.x, frameBuffer.y, gl.RGBA, gl.UNSIGNED_BYTE, pixelData);
      // 翻转Y轴
      flip(pixelData, frameBuffer.x, frameBuffer.y, 4);
      // 确保有像素,微信小程序安卓在进入子页面返回本页面后,再一次readPixels稳定无像素
      if (pixelData.some(i => i !== 0)) {
        this.screenshotResolve([pixelData, frameBuffer.x, frameBuffer.y])
        this.screenshotResolve = null as unknown as Function;
      }
  }
}
deepkolos commented 3 years ago

我这边初步测试是需要关闭锯齿

const renderer = new WebGL1Renderer({ canvas, antialias: false, alpha: false, preserveDrawingBuffer: true });

通过renderTarget也能拿到pixels, 同样得到的结果是没有锯齿的,但是使用renderTarget的好处是显示的时候可以开抗锯齿

sceenshot: async () => {
  const { width, height } = deps.canvas
  const renderTarget = new WebGLRenderTarget(deps.canvas.width, deps.canvas.height)
  deps.renderer.setRenderTarget(renderTarget)
  deps.renderer.render(deps.scene, deps.camera)
  const buffer = new Uint8Array(deps.canvas.width * deps.canvas.height * 4)
  deps.renderer.readRenderTargetPixels(renderTarget, 0, 0, deps.canvas.width, deps.canvas.height, buffer)
  deps.renderer.setRenderTarget(null)

  console.log(buffer.some(i => i !== 0))
  const { canvas2d, canvasCtx } = deps
  // @ts-ignore
  const img = canvas2d.createImageData(buffer, width, height);
  canvas2d.height = img.height;
  canvas2d.width = img.width;
  canvasCtx.putImageData(img, 0, 0);
  const imgData = canvasCtx.getImageData(0, 0, width, height)
  const hasPixel = imgData.data.some(i => i !== 0)
  console.log(hasPixel)
  wx.canvasToTempFilePath({
    canvas: deps.canvas2d,
    success(res) {
      wx.previewImage({
        urls: [res.tempFilePath],
      })
    }
  })
},
louiselessel commented 3 years ago

Nice! Were you able to get this to run on the iphone? If yes, then I will try this approach as well on my iphone 8!

I attempted with the rendertarget approach and setting preserveDrawingBuffer to true also, but also couldn't get that to run in wechat on the iphone, though my code wasn't exactly this. I got a blank image. The image gets made but is all alpha / zeros.

deepkolos commented 3 years ago

我这边使用iphone 7的测试机,注意 canvas2d 也需要设置宽高

里面有截图的Demo 微信小程序 DEMO