現在、何千もの円を描画しており、円のジオメトリ(多くの三角形)をインスタンス化しています。
または、単純に四角形(2つの三角形)をインスタンス化することもできますが、距離関数とを使用して、フラグメントシェーダーで円を切り取りdiscard
ます。
どちらのアプローチが速いでしょうか?-フラグメントシェーダーで行われる計算よりも多くの三角形を描画する方がコストがかかりますか?
最速の方法は、GPUと、円の描画方法、2D、3D、それらをブレンドするか、zバッファーを使用するかなど、他の多くの要因に依存する可能性があります...しかし、一般的に、三角形が少ないほどですより多くより速く、より少ないピクセルはより多くより速くなります。だから....、私たちが本当にできることは試してみることだけです。
まず、ブレンドせずにテクスチャードクワッドを描画します。まず、WebGLから常に一貫性のないパフォーマンスが得られるようですが、GPUでのテストでは、インスタンス化を使用して、この300x150キャンバスで60fpsで20k〜30kのクワッドを取得します。
function main() {
const gl = document.querySelector('canvas').getContext('webgl');
const ext = gl.getExtension('ANGLE_instanced_arrays');
if (!ext) {
return alert('need ANGLE_instanced_arrays');
}
twgl.addExtensionsToContext(gl);
const vs = `
attribute float id;
attribute vec4 position;
attribute vec2 texcoord;
uniform float time;
varying vec2 v_texcoord;
varying vec4 v_color;
void main() {
float o = id + time;
gl_Position = position + vec4(
vec2(
fract(o * 0.1373),
fract(o * 0.5127)) * 2.0 - 1.0,
0, 0);
v_texcoord = texcoord;
v_color = vec4(fract(vec3(id) * vec3(0.127, 0.373, 0.513)), 1);
}`;
const fs = `
precision mediump float;
varying vec2 v_texcoord;
varying vec4 v_color;
uniform sampler2D tex;
void main() {
gl_FragColor = texture2D(tex, v_texcoord) * v_color;
}
`;
// compile shaders, link program, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const maxCount = 250000;
const ids = new Float32Array(maxCount);
for (let i = 0; i < ids.length; ++i) {
ids[i] = i;
}
const x = 16 / 300 * 2;
const y = 16 / 150 * 2;
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: [
-x, -y,
x, -y,
-x, y,
-x, y,
x, -y,
x, y,
],
},
texcoord: [
0, 1,
1, 1,
0, 0,
0, 0,
1, 1,
1, 0,
],
id: {
numComponents: 1,
data: ids,
divisor: 1,
}
});
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
{
const ctx = document.createElement('canvas').getContext('2d');
ctx.canvas.width = 32;
ctx.canvas.height = 32;
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.arc(16, 16, 15, 0, Math.PI * 2);
ctx.fill();
const tex = twgl.createTexture(gl, { src: ctx.canvas });
}
const fpsElem = document.querySelector('#fps');
const countElem = document.querySelector('#count');
let count;
function getCount() {
count = Math.min(maxCount, parseInt(countElem.value));
}
countElem.addEventListener('input', getCount);
getCount();
const maxHistory = 60;
const fpsHistory = new Array(maxHistory).fill(0);
let historyNdx = 0;
let historyTotal = 0;
let then = 0;
function render(now) {
const deltaTime = now - then;
then = now;
historyTotal += deltaTime - fpsHistory[historyNdx];
fpsHistory[historyNdx] = deltaTime;
historyNdx = (historyNdx + 1) % maxHistory;
fpsElem.textContent = (1000 / (historyTotal / maxHistory)).toFixed(1);
gl.useProgram(programInfo.program);
twgl.setUniforms(programInfo, {time: now * 0.001});
ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, count);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
canvas { display: block; border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
<div>fps: <span id="fps"></span></div>
<div>count: <input type="number" id="count" min="0" max="1000000" value="25000"></div>
そして、インスタンス化する代わりにジオメトリに繰り返しを使用して、60fpsで同じパフォーマンスを取得します。7〜8年前に繰り返しジオメトリをテストしたときは、20〜30%速かったので、これは私にとって驚くべきことです。それが今より良いGPUを持っているからなのか、それともより良いドライバーを持っているからなのか、それとも私にはわからないことなのか。
function main() {
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute float id;
attribute vec4 position;
attribute vec2 texcoord;
uniform float time;
varying vec2 v_texcoord;
varying vec4 v_color;
void main() {
float o = id + time;
gl_Position = position + vec4(
vec2(
fract(o * 0.1373),
fract(o * 0.5127)) * 2.0 - 1.0,
0, 0);
v_texcoord = texcoord;
v_color = vec4(fract(vec3(id) * vec3(0.127, 0.373, 0.513)), 1);
}`;
const fs = `
precision mediump float;
varying vec2 v_texcoord;
varying vec4 v_color;
uniform sampler2D tex;
void main() {
gl_FragColor = texture2D(tex, v_texcoord) * v_color;
}
`;
// compile shaders, link program, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const maxCount = 250000;
const x = 16 / 300 * 2;
const y = 16 / 150 * 2;
const quadPositions = [
-x, -y,
x, -y,
-x, y,
-x, y,
x, -y,
x, y,
];
const quadTexcoords = [
0, 1,
1, 1,
0, 0,
0, 0,
1, 1,
1, 0,
];
const positions = new Float32Array(maxCount * 2 * 6);
const texcoords = new Float32Array(maxCount * 2 * 6);
for (let i = 0; i < maxCount; ++i) {
const off = i * 2 * 6;
positions.set(quadPositions, off);
texcoords.set(quadTexcoords, off);
}
const ids = new Float32Array(maxCount * 6);
for (let i = 0; i < ids.length; ++i) {
ids[i] = i / 6 | 0;
}
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: positions,
},
texcoord: texcoords,
id: {
numComponents: 1,
data: ids,
}
});
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
{
const ctx = document.createElement('canvas').getContext('2d');
ctx.canvas.width = 32;
ctx.canvas.height = 32;
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.arc(16, 16, 15, 0, Math.PI * 2);
ctx.fill();
const tex = twgl.createTexture(gl, { src: ctx.canvas });
}
const fpsElem = document.querySelector('#fps');
const countElem = document.querySelector('#count');
let count;
function getCount() {
count = Math.min(maxCount, parseInt(countElem.value));
}
countElem.addEventListener('input', getCount);
getCount();
const maxHistory = 60;
const fpsHistory = new Array(maxHistory).fill(0);
let historyNdx = 0;
let historyTotal = 0;
let then = 0;
function render(now) {
const deltaTime = now - then;
then = now;
historyTotal += deltaTime - fpsHistory[historyNdx];
fpsHistory[historyNdx] = deltaTime;
historyNdx = (historyNdx + 1) % maxHistory;
fpsElem.textContent = (1000 / (historyTotal / maxHistory)).toFixed(1);
gl.useProgram(programInfo.program);
twgl.setUniforms(programInfo, {time: now * 0.001});
gl.drawArrays(gl.TRIANGLES, 0, 6 * count);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
canvas { display: block; border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
<div>fps: <span id="fps"></span></div>
<div>count: <input type="number" id="count" min="0" max="1000000" value="25000"></div>
次は、フラグメントシェーダーでテクスチャまたは円を計算します。
function main() {
const gl = document.querySelector('canvas').getContext('webgl');
const ext = gl.getExtension('ANGLE_instanced_arrays');
if (!ext) {
return alert('need ANGLE_instanced_arrays');
}
twgl.addExtensionsToContext(gl);
const vs = `
attribute float id;
attribute vec4 position;
attribute vec2 texcoord;
uniform float time;
varying vec2 v_texcoord;
varying vec4 v_color;
void main() {
float o = id + time;
gl_Position = position + vec4(
vec2(
fract(o * 0.1373),
fract(o * 0.5127)) * 2.0 - 1.0,
0, 0);
v_texcoord = texcoord;
v_color = vec4(fract(vec3(id) * vec3(0.127, 0.373, 0.513)), 1);
}`;
const fs = `
precision mediump float;
varying vec2 v_texcoord;
varying vec4 v_color;
void main() {
gl_FragColor = mix(
v_color,
vec4(0),
step(1.0, length(v_texcoord.xy * 2. - 1.)));
}
`;
// compile shaders, link program, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const maxCount = 250000;
const ids = new Float32Array(maxCount);
for (let i = 0; i < ids.length; ++i) {
ids[i] = i;
}
const x = 16 / 300 * 2;
const y = 16 / 150 * 2;
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: [
-x, -y,
x, -y,
-x, y,
-x, y,
x, -y,
x, y,
],
},
texcoord: [
0, 1,
1, 1,
0, 0,
0, 0,
1, 1,
1, 0,
],
id: {
numComponents: 1,
data: ids,
divisor: 1,
}
});
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
const fpsElem = document.querySelector('#fps');
const countElem = document.querySelector('#count');
let count;
function getCount() {
count = Math.min(maxCount, parseInt(countElem.value));
}
countElem.addEventListener('input', getCount);
getCount();
const maxHistory = 60;
const fpsHistory = new Array(maxHistory).fill(0);
let historyNdx = 0;
let historyTotal = 0;
let then = 0;
function render(now) {
const deltaTime = now - then;
then = now;
historyTotal += deltaTime - fpsHistory[historyNdx];
fpsHistory[historyNdx] = deltaTime;
historyNdx = (historyNdx + 1) % maxHistory;
fpsElem.textContent = (1000 / (historyTotal / maxHistory)).toFixed(1);
gl.useProgram(programInfo.program);
twgl.setUniforms(programInfo, {time: now * 0.001});
ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, count);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
canvas { display: block; border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
<div>fps: <span id="fps"></span></div>
<div>count: <input type="number" id="count" min="0" max="1000000" value="25000"></div>
測定可能な違いはありません。サークル機能を試す
function main() {
const gl = document.querySelector('canvas').getContext('webgl');
const ext = gl.getExtension('ANGLE_instanced_arrays');
if (!ext) {
return alert('need ANGLE_instanced_arrays');
}
twgl.addExtensionsToContext(gl);
const vs = `
attribute float id;
attribute vec4 position;
attribute vec2 texcoord;
uniform float time;
varying vec2 v_texcoord;
varying vec4 v_color;
void main() {
float o = id + time;
gl_Position = position + vec4(
vec2(
fract(o * 0.1373),
fract(o * 0.5127)) * 2.0 - 1.0,
0, 0);
v_texcoord = texcoord;
v_color = vec4(fract(vec3(id) * vec3(0.127, 0.373, 0.513)), 1);
}`;
const fs = `
precision mediump float;
varying vec2 v_texcoord;
varying vec4 v_color;
float circle(in vec2 st, in float radius) {
vec2 dist = st - vec2(0.5);
return 1.0 - smoothstep(
radius - (radius * 0.01),
radius +(radius * 0.01),
dot(dist, dist) * 4.0);
}
void main() {
gl_FragColor = mix(
vec4(0),
v_color,
circle(v_texcoord, 1.0));
}
`;
// compile shaders, link program, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const maxCount = 250000;
const ids = new Float32Array(maxCount);
for (let i = 0; i < ids.length; ++i) {
ids[i] = i;
}
const x = 16 / 300 * 2;
const y = 16 / 150 * 2;
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: [
-x, -y,
x, -y,
-x, y,
-x, y,
x, -y,
x, y,
],
},
texcoord: [
0, 1,
1, 1,
0, 0,
0, 0,
1, 1,
1, 0,
],
id: {
numComponents: 1,
data: ids,
divisor: 1,
}
});
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
const fpsElem = document.querySelector('#fps');
const countElem = document.querySelector('#count');
let count;
function getCount() {
count = Math.min(maxCount, parseInt(countElem.value));
}
countElem.addEventListener('input', getCount);
getCount();
const maxHistory = 60;
const fpsHistory = new Array(maxHistory).fill(0);
let historyNdx = 0;
let historyTotal = 0;
let then = 0;
function render(now) {
const deltaTime = now - then;
then = now;
historyTotal += deltaTime - fpsHistory[historyNdx];
fpsHistory[historyNdx] = deltaTime;
historyNdx = (historyNdx + 1) % maxHistory;
fpsElem.textContent = (1000 / (historyTotal / maxHistory)).toFixed(1);
gl.useProgram(programInfo.program);
twgl.setUniforms(programInfo, {time: now * 0.001});
ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, count);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
canvas { display: block; border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
<div>fps: <span id="fps"></span></div>
<div>count: <input type="number" id="count" min="0" max="1000000" value="25000"></div>
私は再び測定可能な違いはありません。注:上で述べたように、WebGLでは非常に一貫性のない結果が得られます。最初のテストを実行したとき、60fpsで28kを取得しました。2番目を実行したとき、私は23kを得ました。2回目が速いと思っていたのでびっくりしたので、1回目をもう一度走って23kしか取れませんでした。最後のものは29kを取得し、再び驚きましたが、その後、前に戻って29kを取得しました。基本的に、これはWebGLでタイミングをテストすることはほぼ不可能であることを意味します。すべてがマルチプロセスであるため、可動部分が非常に多いため、一定の結果を得るのは不可能に思えます。
破棄してみてください
function main() {
const gl = document.querySelector('canvas').getContext('webgl');
const ext = gl.getExtension('ANGLE_instanced_arrays');
if (!ext) {
return alert('need ANGLE_instanced_arrays');
}
twgl.addExtensionsToContext(gl);
const vs = `
attribute float id;
attribute vec4 position;
attribute vec2 texcoord;
uniform float time;
varying vec2 v_texcoord;
varying vec4 v_color;
void main() {
float o = id + time;
gl_Position = position + vec4(
vec2(
fract(o * 0.1373),
fract(o * 0.5127)) * 2.0 - 1.0,
0, 0);
v_texcoord = texcoord;
v_color = vec4(fract(vec3(id) * vec3(0.127, 0.373, 0.513)), 1);
}`;
const fs = `
precision mediump float;
varying vec2 v_texcoord;
varying vec4 v_color;
float circle(in vec2 st, in float radius) {
vec2 dist = st - vec2(0.5);
return 1.0 - smoothstep(
radius - (radius * 0.01),
radius +(radius * 0.01),
dot(dist, dist) * 4.0);
}
void main() {
if (circle(v_texcoord, 1.0) < 0.5) {
discard;
}
gl_FragColor = v_color;
}
`;
// compile shaders, link program, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const maxCount = 250000;
const ids = new Float32Array(maxCount);
for (let i = 0; i < ids.length; ++i) {
ids[i] = i;
}
const x = 16 / 300 * 2;
const y = 16 / 150 * 2;
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
numComponents: 2,
data: [
-x, -y,
x, -y,
-x, y,
-x, y,
x, -y,
x, y,
],
},
texcoord: [
0, 1,
1, 1,
0, 0,
0, 0,
1, 1,
1, 0,
],
id: {
numComponents: 1,
data: ids,
divisor: 1,
}
});
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
const fpsElem = document.querySelector('#fps');
const countElem = document.querySelector('#count');
let count;
function getCount() {
count = Math.min(maxCount, parseInt(countElem.value));
}
countElem.addEventListener('input', getCount);
getCount();
const maxHistory = 60;
const fpsHistory = new Array(maxHistory).fill(0);
let historyNdx = 0;
let historyTotal = 0;
let then = 0;
function render(now) {
const deltaTime = now - then;
then = now;
historyTotal += deltaTime - fpsHistory[historyNdx];
fpsHistory[historyNdx] = deltaTime;
historyNdx = (historyNdx + 1) % maxHistory;
fpsElem.textContent = (1000 / (historyTotal / maxHistory)).toFixed(1);
gl.useProgram(programInfo.program);
twgl.setUniforms(programInfo, {time: now * 0.001});
ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, count);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
canvas { display: block; border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
<div>fps: <span id="fps"></span></div>
<div>count: <input type="number" id="count" min="0" max="1000000" value="25000"></div>
タイミングに一貫性がないため、確信は持てませんが、破棄が遅いという印象があります。IIRCの破棄は遅いです。なぜなら、破棄しないと、GPUはフラグメントシェーダーを実行する前でもzバッファーを更新することを知っているのに対し、破棄と同様に、シェーダーが実行されるまではわかりません。その違いは、特定のものができないことを意味します。同様に最適化されます。
試してみることができる組み合わせが多すぎるので、そこで停止します。
ブレンドしてみることができます。ブレンド(背景を読む)が必要なため、ブレンドも一般的に遅くなりますが、破棄するよりも遅いですか?知りません。
深度テストはありますか?もしそうなら、描画順序が重要になります。
テストするもう1つのことは、ヘクスゴンやオクトゴンなどの非クワッドを使用することです。これにより、フラグメントシェーダーを通過するピクセルが少なくなります。それを確認するには、円を大きくする必要があると思いますが、100x100ピクセルのクワッドがある場合は10kピクセルです。約pi * r ^ 2または〜7853または21%少ないピクセルの完全な円ジオメトリがある場合。六角形は約8740ピクセル、つまり11%少なくなります。中間のどこかに八角形。通常、11%から21%少ないピクセルを描画するのが効果的ですが、もちろん、六角形の場合は3倍、八角形の場合は4倍の三角形を描画します。基本的に、これらすべてのケースをテストする必要があります。
これは別の問題を指摘しています。円あたりのピクセル数が多いため、大きなキャンバス上で大きな円を使用すると相対的な結果が異なるため、描画される円の数に応じて、ピクセルの描画に費やされる時間の割合が増えると思います。頂点の計算が少なくなり、GPUを再起動して次の円を描く時間が短くなります。
ChromeとFirefoxでのテスト同じマシンのChromeですべてのケースで60k〜66kを取得しました。WebGL自体がほとんど何もしていないことを考えると、なぜその違いが非常に大きいのかわかりません。4つのテストはすべて、フレームごとに1回の描画呼び出ししかありません。しかし、少なくとも2019-10年の時点で、Chromeはこの特定のケースでFirefoxの2倍以上の速さです。
1つのアイデアは、デュアルGPUラップトップを持っているということです。コンテキストを作成するときは、次のpowerPreference
ようにコンテキスト作成属性を渡すことで、ターゲットにしているものをWebGLに伝えることができます。
const gl = document.createContext('webgl', {
powerPreference: 'high-performance',
});
オプションは、「デフォルト」、「低電力」、「高性能」です。「デフォルト」は「ブラウザに決定させる」ことを意味しますが、最終的にはすべて「ブラウザに決定させる」ことを意味します。いずれにせよ、上記の設定は私にとってFirefoxでは何も変わりませんでした。
Reba McEntire が息子の Shelby Blackstock と共有しているクリスマスの伝統について学びましょう。
メーガン・マークルとマライア・キャリーが自然な髪の上でどのように結合したかについて、メーガンの「アーキタイプ」ポッドキャストのエピソードで学びましょう.
ハリー王子が家族、特にチャールズ王とウィリアム王子との関係について望んでいると主張したある情報源を発見してください。
ワイノナ・ジャッドが、母親のナオミ・ジャッドが亡くなってから初めての感謝祭のお祝いを主催しているときに、彼女が今では家長であることをどのように認識したかを学びましょう.
Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
Tomorrow's Kitchen シリコンストレッチ蓋 12個パック | $14 | アマゾン | プロモーション コード 20OFFKINJALids は基本的にキッチンの靴下です。常に迷子になり、二度と閉じられない孤立したコンテナーが残ります。しかし、蓋が伸びて、残った容器、鍋、フライパン、さらには大きなスライスされた果物のすべてに適合するとしたらどうでしょうか? その非常に特殊な蓋を失うことを二度と心配する必要はありません。
ある小売業者は、プラスサイズのセクションを缶詰にしています。しかし、彼らはこのカテゴリーをオンラインのみにとどめたり、完全に廃止したりしているわけではありません。
ロシアのフィギュアスケーター、カミラ・バリエバが関与したドーピング事件が整理されているため、チームは2022年北京冬季オリンピックで獲得したメダルを待っています。
何千人ものAmazonの買い物客がMulberry Silk Pillowcaseを推奨しており、現在販売中. シルクの枕カバーにはいくつかの色があり、髪を柔らかく肌を透明に保ちます。Amazonで最大46%オフになっている間にシルクの枕カバーを購入してください
ラファイエット警察署は、「不審な男性が女性に近づいた」という複数の苦情を受けて、12 月にパデュー大学の教授の捜査を開始しました。
私たちの周りの世界と同じように、言語は常に変化しています。以前の時代では、言語の変化は数年または数十年にわたって発生していましたが、現在では数日または数時間で変化する可能性があります。
認知症を患っている 91 歳のアジア人女性が最近、47 番街のアウター サンセット地区でロメオ ロレンゾ パーハムに襲われました。伝えられるところによると、被害者はサンフランシスコの通りを歩いていたところ、容疑者に近づき、攻撃を受け、暴行を受けました。
“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.
人々にチャンスを与えることは、人生で少し遅すぎると私は信じています。寛大に。