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

<!DOCTYPE html>
<html>
<body>

<img src="https://www.w3schools.com/graphics/pic_the_scream.jpg" id="tupian">
<canvas id="myCanvas" width="200" height="200" style="width:200px;height:200px;border:1px solid">
Your browser does not support the HTML5 canvas tag.
</canvas>

<script>
var c = document.getElementById("myCanvas");
var pixelRatio = 2;
c.width = 200 * pixelRatio;
c.height = 200 * pixelRatio;
var ctx = c.getContext("2d");
//ctx.scale(pixelRatio, pixelRatio)

var img = document.getElementById("tupian");
ctx.drawImage(img, 10, 10);

ctx.fillStyle = "#92B901";
ctx.fillRect(50, 50, 100, 100);
ctx.font = "30px Arial";
ctx.fillText("Hello World"+pixelRatio, 10, 50);

</script>

<button onclick="clearCanvas()">Clear canvas</button>

</body>
</html>

前端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));
}
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容