2022-06-14 Canvas画布模糊问题

【重要】view大小(属性值决定最终上屏时的缩放比例) 画布bufffer大小 gl.viewPort视口大小(映射画布坐标到NDC坐标 -1到1 GL世界的坐标)

所有view单位 和 buffer单位不一致的,都要 渲染引擎提供处理的。

threejs的处理流程

renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(screenCanvas.clientWidth, screenCanvas.clientHeight);

skottie的处理流程

json文件内为view单位,创建buffer用的物理像素,绘制通过render 给定dstR 做映射,实现了view单位到物理像素单位的映射。

    auto canvas = skottieAnimation_->mRenderTarget->getCanvas();
    // canvas->clear(backgroundColor);

    SkAutoCanvasRestore acr(canvas, true);
    SkRect bounds = SkRect::MakeWH(width_, height_);
    skottieAnimation_->mAnimation->render(canvas, &bounds);
    canvas->flush();

void Animation::render(SkCanvas* canvas, const SkRect* dstR) {
const SkRect srcR = SkRect::MakeSize(this->size());
if (dstR) {
canvas->concat(SkMatrix::MakeRectToRect(srcR, *dstR, SkMatrix::kCenter_ScaleToFit));
}
}

WebCanvas的流程

要自己手动调整和映射。canvas.scale

如何解决画布模糊问题 https://opendocs.alipay.com/support/01rb86
画布大小、图片绘制尺寸、保存图片实际尺寸。viewsize、buffersize。

  1. 逻辑像素 * pixelRatio = 设备像素
  2. 原因是 清晰度问题。attribute width/height决定了画布大小(逻辑像素)。css_style决定view大小(设备像素)。drawapi中的单位是画布单位。小画布 上屏到大容器view中,被放大导致的模糊。
    大画布绘制到小view中,也会模糊。
  3. canvas中的变换矩阵。transform。移动缩放倾斜。不包含旋转。https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/transform
  4. 矩阵的乘法。都是先行。M*N M是多少行。乘的时候从第一个矩阵的第一行开始,乘以第二个矩阵的第一列。


    一个m×n的矩阵就是m×n个数排成m行n列的一个数阵
图像的几何变换主要分为三类:刚性变换、仿射变换和透视变换

https://zhuanlan.zhihu.com/p/80852438

  1. 仿射变换&透视变换 正交投影&透视投影(近大远小) fov(视野可视角度)
    https://hyiker.com/2021/03/25/%E6%AD%A3%E4%BA%A4%E6%8A%95%E5%BD%B1-%E9%80%8F%E8%A7%86%E6%8A%95%E5%BD%B1/
    5.1 canvas中提供的变换矩阵,3*3的不支持旋转角,支持了个扭曲拉伸 仿射变换。
  2. 变换矩阵 。https://pengfeixc.com/blog/60a7492be97367196dce3eef

https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_canvas_height_width_clear





Your browser does not support the HTML5 canvas tag.



前端css尺寸px是逻辑像素呀,并且window.innerWidth也会逻辑像素。在做threejs的适配是,没有单独设置 canvas.width(决定物理像素) ,而是修改的 canvas.style={ width: width + "px",} (决定虚拟像素) 。 如果不设置 width 的话,默认 canvas.width = canvas.style.width * pixleRadio 。 适配threejs没有设置width,所以要传递给devicePixelRatio 给threejs 让他内部自己换算到物理物理像素。screenCanvas.clientWidth == viewWidth; viewWidth = getIntValue(viewWidth, w); bufferWidth = getIntValue(bufferWidth, w);

这样的话,绘制接口的坐标 可以走CSS(虽然绘制API单位是物理像素,但是threejs内部有canvas.scale的设置,保证了可以走CSS单位)

如果需要自己调整画布大小呢,用于降级,则可以,自己给定一个devicePixelRatio值,并手动设置canvas.width 和 renderer.setPixelRatio 。

renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(screenCanvas.clientWidth, screenCanvas.clientHeight);

skottie的流程是

尺寸问题

  1. webcanvas中如何绘制高分辨率,是通过 手动 把逻辑像素乘以屏幕密度,然后再canvas.scale放大2倍,相当于让原绘制逻辑中的坐标、长度单位也同步放大2倍,保证了不需要修改代码。

  2. NativeCanvas的解决方案是 直接修改surface的物理像素大小。但是所有的绘制接口用于生成三角形顶点的单位依然是逻辑像素,这样生成归一化的坐标还是正确的。glviewport要使用物理像素大小。

view大小(属性值决定最终上屏时的缩放比例) 画布bufffer大小 gl.viewPort视口大小(映射画布坐标到NDC坐标 -1到1 GL世界的坐标)

ViewPort指定坐标比画布buffer大时,绘制超出画布buffer,走Per-Sample_Processing 相关的流程 做裁剪。 Early Fragment Test 可能是有 被剔除

  1. surfaceholder修改buffer的物理像素的方法
    surface_1.getHolder().setFixedSize(100, 100);
    surfaceChanged{ surfaceWidth = holder.getSurfaceFrame().width();}

  2. glViewport设置 可以比画布buffer大 ,但是只绘制 重合部分 。
    【重要】绘制用物理内存

前端html中定义tag的宽高,映射到native决定了自身view的大小和宽高radio。
surface画布物理大小在内存降级时,可以自己降低scale屏幕密度值来减少内存占用,但是要保持radio。
如果radio不一致,则会存在拉伸,在上屏时,由系统根据View的宽高属性,拉伸画布。

在一块很大的画布上,居中绘制,则可以通过glviewport来实现的。
但是如何保持让2d绘制依然使用 逻辑像素单位呢,主要为了生成顶点作用用的。

  1. skottie中逻辑像素单位,在每次绘制时都指定,在最终绘制时,内部走了
    auto canvas = skottieAnimation_->mRenderTarget->getCanvas();
    // canvas->clear(backgroundColor);

     SkAutoCanvasRestore acr(canvas, true);
     SkRect bounds = SkRect::MakeWH(width_, height_);
     skottieAnimation_->mAnimation->render(canvas, &bounds);
     canvas->flush();
    

void Animation::render(SkCanvas* canvas, const SkRect* dstR) {
const SkRect srcR = SkRect::MakeSize(this->size());
if (dstR) {
canvas->concat(SkMatrix::MakeRectToRect(srcR, *dstR, SkMatrix::kCenter_ScaleToFit));
}
}

你可能感兴趣的:(2022-06-14 Canvas画布模糊问题)