我用width=16
和height=16
创建了一个画布。然后,我使用WebGL为其渲染图像。看起来像这样:
然后,我使用width: 256px
和height: 256px
缩放了画布。我还将image-rendering
设置为pixelated
:
canvas {
image-rendering: optimizeSpeed; /* STOP SMOOTHING, GIVE ME SPEED */
image-rendering: -moz-crisp-edges; /* Firefox */
image-rendering: -o-crisp-edges; /* Opera */
image-rendering: -webkit-optimize-contrast; /* Chrome (and eventually Safari) */
image-rendering: pixelated; /* Chrome */
image-rendering: optimize-contrast; /* CSS3 Proposed */
-ms-interpolation-mode: nearest-neighbor; /* IE8+ */
width: 256px;
height: 256px;
}
这是结果:
图像模糊。为什么?我正在OSX Mojave上使用Safari 12.0.2。
答案 0 :(得分:3)
Safari尚未在WebGL上支持image-rendering: pixelated;
。 Filed a bug
crisp-edges
也不!= pixelated
。 crisp-edges
可以是任意数量的算法。这并不意味着pixelated
。这意味着应用一些保持清晰边缘的算法,其中有很多算法。
The spec itself显示了示例:
给出此图片:
这是pixelated
:
在允许浏览器为crisp-edges
使用各种算法的情况下,例如结果可能是
因此,换句话说,您的CSS可能不会产生您期望的结果。如果浏览器不支持像素化,但支持边缘清晰,并且它们使用上述算法,那么您将不会具有像素化外观。
在没有image-rendering: pixelated
的情况下绘制像素化图形的最有效方法是先绘制一个小的纹理,然后使用NEAREST
过滤将该纹理绘制到画布上。
const vs = `
attribute vec4 position;
void main() {
gl_Position = position;
}
`;
const fs = `
precision mediump float;
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}
`;
const screenVS = `
attribute vec4 position;
varying vec2 v_texcoord;
void main() {
gl_Position = position;
// because we know position goes from -1 to 1
v_texcoord = position.xy * 0.5 + 0.5;
}
`;
const screenFS = `
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D u_tex;
void main() {
gl_FragColor = texture2D(u_tex, v_texcoord);
}
`;
const gl = document.querySelector('canvas').getContext('webgl', {antialias: false});
// compile shaders, link programs, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const screenProgramInfo = twgl.createProgramInfo(gl, [screenVS, screenFS]);
const width = 16;
const height = 16;
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
// create buffers and put data in
const quadBufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: [
-1, -1,
1, -1,
-1, 1,
-1, 1,
1, -1,
1, 1,
],
}
});
render();
function render() {
// draw at 16x16 to texture
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.viewport(0, 0, width, height);
gl.useProgram(programInfo.program);
// bind buffers and set attributes
twgl.setBuffersAndAttributes(gl, programInfo, quadBufferInfo);
gl.drawArrays(gl.TRIANGLES, 0, 3); // only draw the first triangle
// draw texture to canvas
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.useProgram(screenProgramInfo.program);
// bind buffers and set attributes
twgl.setBuffersAndAttributes(gl, screenProgramInfo, quadBufferInfo);
// uniforms default to 0 so in this simple case
// no need to bind texture or set uniforms since
// we only have 1 texture, it's on texture unit 0
// and the uniform defaults to 0
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
<canvas width="256" height="256"></canvas>
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
注意:如果要渲染3D或出于其他原因需要深度缓冲区,则需要向帧缓冲区添加深度渲染缓冲区附件。
请注意,optimizeSpeed
也不是真正的选择。它早已被弃用,就像crisp-edges
由浏览器解释一样。
答案 1 :(得分:2)
这是一个非常古老的Webkit bug,距闪烁分支发生之前还很早。
从那时起,眨眼fixed it,Webkit仍然没有。
您可能想通过评论仍未解决的问题来让他们知道仍然存在问题。
至于一种变通方法,有几种,但还不完美。
但是这里真正的问题是找出您是否需要此解决方法。我认为没有必要对这种情况进行功能测试(至少在没有Houdini的情况下),因此这意味着您要么必须进行丑陋的用户代理检测,要么将变通办法应用于所有人。