【重要】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。
- 逻辑像素 * pixelRatio = 设备像素
- 原因是 清晰度问题。attribute width/height决定了画布大小(逻辑像素)。css_style决定view大小(设备像素)。drawapi中的单位是画布单位。小画布 上屏到大容器view中,被放大导致的模糊。
大画布绘制到小view中,也会模糊。 - canvas中的变换矩阵。transform。移动缩放倾斜。不包含旋转。https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/transform
-
矩阵的乘法。都是先行。M*N M是多少行。乘的时候从第一个矩阵的第一行开始,乘以第二个矩阵的第一列。
一个m×n的矩阵就是m×n个数排成m行n列的一个数阵
https://zhuanlan.zhihu.com/p/80852438
- 仿射变换&透视变换 正交投影&透视投影(近大远小) 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的不支持旋转角,支持了个扭曲拉伸 仿射变换。 - 变换矩阵 。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的流程是
尺寸问题
-
webcanvas中如何绘制高分辨率,是通过 手动 把逻辑像素乘以屏幕密度,然后再canvas.scale放大2倍,相当于让原绘制逻辑中的坐标、长度单位也同步放大2倍,保证了不需要修改代码。
-
NativeCanvas的解决方案是 直接修改surface的物理像素大小。但是所有的绘制接口用于生成三角形顶点的单位依然是逻辑像素,这样生成归一化的坐标还是正确的。glviewport要使用物理像素大小。
view大小(属性值决定最终上屏时的缩放比例) 画布bufffer大小 gl.viewPort视口大小(映射画布坐标到NDC坐标 -1到1 GL世界的坐标)
ViewPort指定坐标比画布buffer大时,绘制超出画布buffer,走Per-Sample_Processing 相关的流程 做裁剪。 Early Fragment Test 可能是有 被剔除
-
surfaceholder修改buffer的物理像素的方法
surface_1.getHolder().setFixedSize(100, 100);
surfaceChanged{ surfaceWidth = holder.getSurfaceFrame().width();} -
glViewport设置 可以比画布buffer大 ,但是只绘制 重合部分 。
【重要】绘制用物理内存
前端html中定义tag的宽高,映射到native决定了自身view的大小和宽高radio。
surface画布物理大小在内存降级时,可以自己降低scale屏幕密度值来减少内存占用,但是要保持radio。
如果radio不一致,则会存在拉伸,在上屏时,由系统根据View的宽高属性,拉伸画布。
在一块很大的画布上,居中绘制,则可以通过glviewport来实现的。
但是如何保持让2d绘制依然使用 逻辑像素单位呢,主要为了生成顶点作用用的。
-
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));
}
}
网友评论