UNPKG

matrix-engine-wgpu

Version:

Networking implemented - based on kurento openvidu server. fix arcball camera,instanced draws added also effect pipeline blend with instancing option.Normalmap added, Fixed shadows casting vs camera/video texture, webGPU powered pwa application. Crazy fas

636 lines (599 loc) 23 kB
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/png" href="rotation-icon.png"> <link rel="apple-touch-icon" type="image/png" href="rotation-icon.png"> <title>3D Rotation Converter</title> <style> @media all { html { font-family: Garamond, Palatino, serif; font-size: 18px; line-height: 1.3; } .dcol { float: left; width: 50%; padding-right: 1.5rem; box-sizing: border-box; } } @media all and (max-width:1200px) { html { font-size: 16px; } } @media all and (max-width:980px) { html { font-size: 16px; } .dcol { width: 100%; } } @media all and (max-width:800px) { html { font-size: 15px; } } @media all and (max-width:600px) { html { font-size: 13px; } } @media all and (max-width:400px) { html { font-size: 11px; } } select, input, textarea, label { font-family: "Lucida Console", "DejaVu Sans Mono", monospace; font-size: 0.9rem; background: #dfdff5; border: 1px solid #323296; color: #000; margin: 0.1rem; } textarea { background: #fff; font-weight: bold; } select, label { font-family: Garamond, Palatino, Times; font-size: 1rem; margin: 0rem 0.2rem; padding: 0.1rem 0.2rem; } body { margin: 0.5rem auto; max-width: 1800px; padding: 1.5rem; padding-right: 0rem; position: relative; } .pi, textarea { padding: 0.3rem; } input { width: 5rem; } input[type="radio"] { height: auto; width: auto; } input, select { margin-right: 0.5rem; margin-top: 0.5rem; } .pi { background: #eee; transition: border-color 0.6s; -webkit-transition: border-color 0.6s; border: 1px solid #fff; } .phigh { border: 1px solid #323296; } .phigh input { font-weight: bold; } .dl, .dl2 { display: inline-block; text-align: right; min-width: 5rem; margin-right: 0.3rem; } .dl2 { min-width: 1rem; } textarea { width: 100%; } input[type=number]::-webkit-outer-spin-button, input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; appearance: none; margin: 0; } input[type=number] { -moz-appearance: textfield; } </style> </head> <body> <div class="main"> <div> <form novalidate> <h1><img src="rotation-icon.svg" style="height:1.2em; width:1.2em; margin-right:0.5em;" onerror="this.onerror=null; this.src='rotation-icon.png';" /> 3D Rotation Converter</h1> <div class="dcol"> <h2>Input</h2> <p>Input angle format <label><input type="radio" id="iformatrad" name="iformat" value="0" checked onchange="update(inputMode)" />Radians</label> <label><input type="radio" id="iformatdeg" name="iformat" value="1" onchange="update(inputMode)" />Degrees</label> <p class="pi" id="ip0">Rotation matrix <br /><span class="dl"></span><input type="number" pattern="\d+(\.\d*)?" id="m00" value="1" oninput="update(0)" /> <span class="dl2"></span><input type="number" pattern="\d+(\.\d*)?" id="m01" value="0" oninput="update(0)" /> <span class="dl2"></span><input type="number" pattern="\d+(\.\d*)?" id="m02" value="0" oninput="update(0)" /> &nbsp; <br /><span class="dl"></span><input type="number" pattern="\d+(\.\d*)?" id="m10" value="0" oninput="update(0)" /> <span class="dl2"></span><input type="number" pattern="\d+(\.\d*)?" id="m11" value="1" oninput="update(0)" /> <span class="dl2"></span><input type="number" pattern="\d+(\.\d*)?" id="m12" value="0" oninput="update(0)" /> &nbsp; <br /><span class="dl"></span><input type="number" pattern="\d+(\.\d*)?" id="m20" value="0" oninput="update(0)" /> <span class="dl2"></span><input type="number" pattern="\d+(\.\d*)?" id="m21" value="0" oninput="update(0)" /> <span class="dl2"></span><input type="number" pattern="\d+(\.\d*)?" id="m22" value="1" oninput="update(0)" /> <p class="pi" id="ip1">Quaternion <br /> <span class="dl">x</span><input type="number" pattern="\d+(\.\d*)?" id="q0" value="0" oninput="update(1)" /> <span class="dl2">y</span><input type="number" pattern="\d+(\.\d*)?" id="q1" value="0" oninput="update(1)" /> <span class="dl2">z</span><input type="number" pattern="\d+(\.\d*)?" id="q2" value="0" oninput="update(1)" /> <span class="dl">w (real part) <input type="number" pattern="\d+(\.\d*)?" id="q3" value="1" oninput="update(1)" /></span> <p class="pi" id="ip2">Axis-angle <br /> <span class="dl">Axis x</span><input type="number" pattern="\d+(\.\d*)?" id="a0" value="0" oninput="update(2)" /> <span class="dl2">y</span><input type="number" pattern="\d+(\.\d*)?" id="a1" value="0" oninput="update(2)" /> <span class="dl2">z</span><input type="number" pattern="\d+(\.\d*)?" id="a2" value="0" oninput="update(2)" /> <span class="dl">Angle<span name="spananglei"> (radians)</span> <input type="number" pattern="\d+(\.\d*)?" id="a3" value="0" oninput="update(2)" /></span> <p class="pi" id="ip3">Axis with angle magnitude<span name="spananglei"> (radians)</span> <br /><span class="dl">Axis x</span><input type="number" pattern="\d+(\.\d*)?" id="r0" value="0" oninput="update(3)" /> <span class="dl2">y</span><input type="number" pattern="\d+(\.\d*)?" id="r1" value="0" oninput="update(3)" /> <span class="dl2">z</span><input type="number" pattern="\d+(\.\d*)?" id="r2" value="0" oninput="update(3)" /> <p class="pi" id="ip4">Euler angles of multiple axis rotations<span name="spananglei"> (radians)</span> <br /> <span class="dl"><select id="euler" onchange="update(4)"> <option value="XYZ" selected>XYZ</option> <option value="XZY">XZY</option> <option value="YXZ">YXZ</option> <option value="YZX">YZX</option> <option value="ZXY">ZXY</option> <option value="ZYX">ZYX</option> </select></span> <span class="dl2">x</span><input type="number" pattern="\d+(\.\d*)?" id="e0" value="0" oninput="update(4)" /> <span class="dl2">y</span><input type="number" pattern="\d+(\.\d*)?" id="e1" value="0" oninput="update(4)" /> <span class="dl2">z</span><input type="number" pattern="\d+(\.\d*)?" id="e2" value="0" oninput="update(4)" /> <p class="pi" id="ip5">Triple of points, P, Q, R, such that X &#x2225; (Q&minus;P), &nbsp; Z &#x2225; X &times; (R&minus;P), &nbsp;and Y &#x2225; Z &times; X. <br /> P: <span class="dl2">x</span><input type="number" pattern="\d+(\.\d*)?" id="Px" value="0" oninput="update(5)" /> <span class="dl2">y</span><input type="number" pattern="\d+(\.\d*)?" id="Py" value="0" oninput="update(5)" /> <span class="dl2">z</span><input type="number" pattern="\d+(\.\d*)?" id="Pz" value="0" oninput="update(5)" /> <br /> Q: <span class="dl2">x</span><input type="number" pattern="\d+(\.\d*)?" id="Qx" value="1" oninput="update(5)" /> <span class="dl2">y</span><input type="number" pattern="\d+(\.\d*)?" id="Qy" value="0" oninput="update(5)" /> <span class="dl2">z</span><input type="number" pattern="\d+(\.\d*)?" id="Qz" value="0" oninput="update(5)" /> <br /> R: <span class="dl2">x</span><input type="number" pattern="\d+(\.\d*)?" id="Rx" value="0" oninput="update(5)" /> <span class="dl2">y</span><input type="number" pattern="\d+(\.\d*)?" id="Ry" value="1" oninput="update(5)" /> <span class="dl2">z</span><input type="number" pattern="\d+(\.\d*)?" id="Rz" value="0" oninput="update(5)" /> <br /> </div> <div class="dcol"> <h2>Output</h2> <script src="three-test.js"></script> <script> var quat = new THREE.Quaternion(); var highlightedId = 'ip0'; var inputMode = 0; function matrixToString(m) { var r = m.elements; var s = '[ ' + toFixedWidth(r[0]) + ', ' + toFixedWidth(r[4]) + ', ' + toFixedWidth(r[8]) + ';\n' + ' ' + toFixedWidth(r[1]) + ', ' + toFixedWidth(r[5]) + ', ' + toFixedWidth(r[9]) + ';\n' + ' ' + toFixedWidth(r[2]) + ', ' + toFixedWidth(r[6]) + ', ' + toFixedWidth(r[10]) + ' ]'; return s; } function highlight(id) { if (document.getElementById(highlightedId)) document.getElementById(highlightedId).classList.remove('phigh'); highlightedId = id; document.getElementById(id).classList.add('phigh'); } function setQ(q) { q.normalize(); quat = q; doOutput(); } function doOutput() { var q = quat; var m = new THREE.Matrix4(); m.makeRotationFromQuaternion(q); document.getElementById("resmatrix").value = matrixToString(m); document.getElementById("resq").value = '[ ' + toReal(q.x) + ', ' + toReal(q.y) + ', ' + toReal(q.z) + ', ' + toReal(q.w) + ' ]'; var axis = [0, 0, 0]; var angle = 2 * Math.acos(q.w); if(1 - (q.w * q.w) < 0.000001) { axis[0] = q.x; axis[1] = q.y; axis[2] = q.z; } else { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/ var s = Math.sqrt(1 - (q.w * q.w)); axis[0] = q.x / s; axis[1] = q.y / s; axis[2] = q.z / s; } document.getElementById("resa").value = '{ [ ' + toReal(axis[0]) + ', ' + toReal(axis[1]) + ', ' + toReal(axis[2]) + ' ], ' + toReal(toAngle(angle)) + ' }'; document.getElementById("resr").value = '[ ' + toReal(toAngle(axis[0] * angle)) + ', ' + toReal(toAngle(axis[1] * angle)) + ', ' + toReal(toAngle(axis[2] * angle)) + ' ]'; var eu = new THREE.Euler(); eu.setFromRotationMatrix(m, document.getElementById("reseuler").value); document.getElementById("rese").value = '[ x: ' + toReal(toAngle(eu.toArray()[0])) + ', y: ' + toReal(toAngle(eu.toArray()[1])) + ', z: ' + toReal(toAngle(eu.toArray()[2])) + ' ]'; var spansi = document.getElementsByName('spananglei'); for(var i = 0;i < spansi.length;i++) { if(document.getElementById('iformatrad').checked) { spansi[i].textContent = ' (radians)'; } else { spansi[i].textContent = ' (degrees)'; } } var spansres = document.getElementsByName('spanangleres'); for(var i = 0;i < spansres.length;i++) { if(document.getElementById('resformatrad').checked) { spansres[i].textContent = ' (radians)'; } else { spansres[i].textContent = ' (degrees)'; } } } function update(mode) { inputMode = mode; var q = new THREE.Quaternion(); if(inputMode == 0) { var m = new THREE.Matrix4(); var m00 = document.getElementById("m00").value; var m01 = document.getElementById("m01").value; var m02 = document.getElementById("m02").value; var m10 = document.getElementById("m10").value; var m11 = document.getElementById("m11").value; var m12 = document.getElementById("m12").value; var m20 = document.getElementById("m20").value; var m21 = document.getElementById("m21").value; var m22 = document.getElementById("m22").value; m.set(m00, m01, m02, 1, m10, m11, m12, 1, m20, m21, m22, 1, 0, 0, 0, 1); q.setFromRotationMatrix(m); } else if(inputMode == 1) { q = new THREE.Quaternion(document.getElementById("q0").value, document.getElementById("q1").value, document.getElementById("q2").value, document.getElementById("q3").value); } else if(inputMode == 2) { q = new THREE.Quaternion(); var axis = new THREE.Vector3(document.getElementById("a0").value, document.getElementById("a1").value, document.getElementById("a2").value); axis.normalize(); q.setFromAxisAngle(axis, toRad(document.getElementById("a3").value)); } else if(inputMode == 3) { var axis = new THREE.Vector3(document.getElementById("r0").value, document.getElementById("r1").value, document.getElementById("r2").value); var angle = toRad(axis.length()); axis.normalize(); q.setFromAxisAngle(axis, angle); } else if(inputMode == 4) { var e = new THREE.Euler(toRad(document.getElementById("e0").value), toRad(document.getElementById("e1").value), toRad(document.getElementById("e2").value), document.getElementById("euler").value); q.setFromEuler(e); } else if(inputMode == 5) { var m = new THREE.Matrix4(); var P = getVector("P"); var Q = getVector("Q"); var R = getVector("R"); var x = new THREE.Vector3(); var y = new THREE.Vector3(); var z = new THREE.Vector3(); x.subVectors(Q, P).normalize(); y.subVectors(R, P); z.crossVectors(x, y).normalize(); y.crossVectors(z, x).normalize(); m.set(x.x, y.x, z.x, 1, x.y, y.y, z.y, 1, x.z, y.z, z.z, 1, 0, 0, 0, 1); q.setFromRotationMatrix(m); } setQ(q); highlight('ip' + inputMode); } function getVector(root) { vx = document.getElementById(root + "x").value; vy = document.getElementById(root + "y").value; vz = document.getElementById(root + "z").value; return new THREE.Vector3(vx, vy, vz); } function toRad(x) { if(document.getElementById("iformatdeg").checked) { return x / 180 * Math.PI; } else { return x; } } function toAngle(x) { if(document.getElementById("resformatdeg").checked) { return x * 180 / Math.PI; } else { return x; } } function toReal(x) { if(!isNaN(parseFloat(x)) && isFinite(parseFloat(x))) { return parseFloat(parseFloat(x).toFixed(7)); } else { return x; } } function toFixedWidth(x) { if(!isNaN(parseFloat(x)) && isFinite(parseFloat(x))) { var s = x.toFixed(7); if(x >= 0) s = ' ' + s; return s; } else { return x; } } </script> <p>Output angle format <label><input type="radio" id="resformatrad" name="resformat" value="0" checked onchange="doOutput()" />Radians</label> <label><input type="radio" id="resformatdeg" name="resformat" value="1" onchange="doOutput()" />Degrees</label> <p>Rotation matrix <br /><textarea id="resmatrix" rows="3" cols="70" readonly></textarea> <p>Quaternion [x, y, z, w] <br /><textarea id="resq" rows="1" cols="85" readonly></textarea> <p>Axis-Angle {[x, y, z], angle<span name="spanangleres"> (radians)</span>} <br /><textarea id="resa" rows="1" cols="85" readonly></textarea> <p>Axis with angle magnitude<span name="spanangleres"> (radians)</span> [x, y, z] <br /><textarea id="resr" rows="1" cols="85" readonly></textarea> <p>Euler angles<span name="spanangleres"> (radians)</span> <select id="reseuler" onchange="doOutput()"> <option value="XYZ" selected>XYZ</option> <option value="XZY">XZY</option> <option value="YXZ">YXZ</option> <option value="YZX">YZX</option> <option value="ZXY">ZXY</option> <option value="ZYX">ZYX</option> </select> <br /> <textarea id="rese" rows="1" cols="70" readonly></textarea> </div> <br style="clear: left;" /> <div class="dcol"> <h2>Details</h2> <p> Please note that rotation formats vary. For quaternions, it is not uncommon to denote the real part first. Euler angles can be defined with many different combinations (see <a href="https://en.wikipedia.org/wiki/Euler_angles#Tait.E2.80.93Bryan_angles">definition of Cardan angles</a>). All input is normalized to unit quaternions and may therefore mapped to different ranges. The converter can therefore also be used to normalize a rotation matrix or a quaternion. Results are rounded to seven digits. </div> <div class="dcol"> <h2>Software</h2> <p> This calculator for 3D rotations is open-source software. If there are any bugs, please push fixes to the <a href="https://github.com/gaschler/rotationconverter">Rotation Converter git repo</a>. For almost all conversions, <a href="https://threejs.org/docs/index.html#api/math/Quaternion">three.js Math</a> is used internally. </div> </form> </div> </div> </body> </html>