Add gyro and webgl demo
This commit is contained in:
parent
611cee6f40
commit
1635eb9ede
43
cg/webgl/index.html
Normal file
43
cg/webgl/index.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.view {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media (max-aspect-ratio: 1) {
|
||||
.view-canvas {
|
||||
width: 100vw;
|
||||
height: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-aspect-ratio: 1) {
|
||||
.view-canvas {
|
||||
width: 100vh;
|
||||
height: 100vh;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="view">
|
||||
<canvas id="canvas" class="view-canvas" width="64" height="64"></canvas>
|
||||
</div>
|
||||
<script src="./m4.js"></script>
|
||||
<script src="./webgl.js"></script>
|
||||
</body>
|
||||
</html>
|
1467
cg/webgl/m4.js
Normal file
1467
cg/webgl/m4.js
Normal file
File diff suppressed because it is too large
Load Diff
323
cg/webgl/webgl.js
Normal file
323
cg/webgl/webgl.js
Normal file
@ -0,0 +1,323 @@
|
||||
"use strict";
|
||||
|
||||
const v3 = {
|
||||
add: function (v1, v2) {
|
||||
return [v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]];
|
||||
},
|
||||
normalize: function (v) {
|
||||
return v3.scale(v, 1 / v3.norm(v));
|
||||
},
|
||||
norm: function (v) {
|
||||
return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2) + Math.pow(v[2], 2));
|
||||
},
|
||||
scale: function (v, f) {
|
||||
return [v[0] * f, v[1] * f, v[2] * f];
|
||||
},
|
||||
};
|
||||
|
||||
function getGyroPermission(){
|
||||
if(!DeviceOrientationEvent.requestPermission){
|
||||
return Promise.resolve("granted")
|
||||
}
|
||||
else{
|
||||
return DeviceOrientationEvent.requestPermission()
|
||||
}
|
||||
}
|
||||
|
||||
function createShader(gl, type, source) {
|
||||
const shader = gl.createShader(type);
|
||||
gl.shaderSource(shader, source);
|
||||
gl.compileShader(shader);
|
||||
|
||||
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
||||
throw new Error(gl.getShaderInfoLog(shader));
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
function createProgram(gl, shaders) {
|
||||
const program = gl.createProgram();
|
||||
for (const shader of shaders) {
|
||||
gl.attachShader(program, shader);
|
||||
}
|
||||
gl.linkProgram(program);
|
||||
|
||||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||
throw new Error(gl.getProgramInfoLog(program));
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
function initIsocahedron(vertices, elements) {
|
||||
const t = 1 + Math.sqrt(5) / 2;
|
||||
|
||||
vertices.push(
|
||||
v3.normalize([-1, t, 0]),
|
||||
v3.normalize([1, t, 0]),
|
||||
v3.normalize([-1, -t, 0]),
|
||||
v3.normalize([1, -t, 0]),
|
||||
v3.normalize([0, -1, t]),
|
||||
v3.normalize([0, 1, t]),
|
||||
v3.normalize([0, -1, -t]),
|
||||
v3.normalize([0, 1, -t]),
|
||||
v3.normalize([t, 0, -1]),
|
||||
v3.normalize([t, 0, 1]),
|
||||
v3.normalize([-t, 0, -1]),
|
||||
v3.normalize([-t, 0, 1]),
|
||||
);
|
||||
|
||||
elements.push(
|
||||
0, 11, 5,
|
||||
0, 5, 1,
|
||||
0, 1, 7,
|
||||
0, 7, 10,
|
||||
0, 10, 11,
|
||||
1, 5, 9,
|
||||
5, 11, 4,
|
||||
11, 10, 2,
|
||||
10, 7, 6,
|
||||
7, 1, 8,
|
||||
3, 9, 4,
|
||||
3, 4, 2,
|
||||
3, 2, 6,
|
||||
3, 6, 8,
|
||||
3, 8, 9,
|
||||
4, 9, 5,
|
||||
2, 4, 11,
|
||||
6, 2, 10,
|
||||
8, 6, 7,
|
||||
9, 8, 1,
|
||||
);
|
||||
}
|
||||
|
||||
function getMidpoint(vertices, midpoints, i0, i1) {
|
||||
const k = `${i0}_${i1}`;
|
||||
if (midpoints.has(k)) {
|
||||
return vertices[midpoints[k]];
|
||||
}
|
||||
|
||||
const p0 = vertices[i0];
|
||||
const p1 = vertices[i1];
|
||||
|
||||
const midpoint = v3.normalize(v3.scale(v3.add(p0, p1), 0.5));
|
||||
const midpointIndex = vertices.length;
|
||||
midpoints.set(k, midpointIndex);
|
||||
vertices.push(midpoint);
|
||||
return midpointIndex;
|
||||
}
|
||||
|
||||
function subdivideIsocahedron(vertices, elements, midpoints) {
|
||||
const newElements = [];
|
||||
for (let i = 0; i < elements.length; i += 3) {
|
||||
const p0 = elements[i];
|
||||
const p1 = elements[i + 1];
|
||||
const p2 = elements[i + 2];
|
||||
const m0 = getMidpoint(vertices, midpoints, p0, p1);
|
||||
const m1 = getMidpoint(vertices, midpoints, p1, p2);
|
||||
const m2 = getMidpoint(vertices, midpoints, p2, p0);
|
||||
|
||||
newElements.push(
|
||||
m0, m1, m2,
|
||||
p0, m0, m2,
|
||||
p1, m1, m0,
|
||||
p2, m2, m1
|
||||
);
|
||||
}
|
||||
return newElements;
|
||||
}
|
||||
|
||||
function generateIsocahedron() {
|
||||
const r = 1;
|
||||
const n = 3;
|
||||
const tau = 2 * Math.PI;
|
||||
|
||||
const vertices = [];
|
||||
const normals = [];
|
||||
let elements = [];
|
||||
|
||||
initIsocahedron(vertices, elements);
|
||||
const midpoints = new Map();
|
||||
for (let i = 0; i < 1; i++) {
|
||||
elements = subdivideIsocahedron(vertices, elements, midpoints);
|
||||
}
|
||||
|
||||
return {
|
||||
vertices: [].concat(...vertices),
|
||||
// as we want to approximate a unit sphere, all the vertices are unit vectors
|
||||
normals: [].concat(...vertices),
|
||||
elements
|
||||
};
|
||||
}
|
||||
|
||||
const canvas = document.querySelector("#canvas");
|
||||
const gl = canvas.getContext("webgl");
|
||||
|
||||
const vertexShader = createShader(gl, gl.VERTEX_SHADER, `
|
||||
attribute vec4 a_position;
|
||||
attribute vec3 a_normal;
|
||||
|
||||
uniform mat4 u_matrix;
|
||||
uniform mat4 u_world;
|
||||
uniform mat4 u_worldIT;
|
||||
uniform vec3 u_light;
|
||||
uniform vec3 u_camera;
|
||||
|
||||
varying vec3 v_normal;
|
||||
varying vec3 v_surfaceToLight;
|
||||
varying vec3 v_surfaceToView;
|
||||
varying vec3 v_pos;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_matrix * a_position;
|
||||
v_pos = a_position.rgb;
|
||||
v_pos.r = abs(v_pos.r);
|
||||
v_pos.g = abs(v_pos.g);
|
||||
v_pos.b = abs(v_pos.b);
|
||||
|
||||
v_normal = mat3(u_worldIT) * a_normal;
|
||||
|
||||
vec3 surfaceWorldPos = (u_world * a_position).xyz;
|
||||
v_surfaceToLight = u_light - surfaceWorldPos;
|
||||
|
||||
v_surfaceToView = u_camera - surfaceWorldPos;
|
||||
}
|
||||
`);
|
||||
|
||||
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, `
|
||||
precision highp float;
|
||||
|
||||
varying vec3 v_normal;
|
||||
varying vec3 v_surfaceToLight;
|
||||
varying vec3 v_surfaceToView;
|
||||
varying vec3 v_pos;
|
||||
|
||||
void main() {
|
||||
vec3 halfVector = normalize(normalize(v_surfaceToLight) + normalize(v_surfaceToView));
|
||||
|
||||
float ka = 0.3;
|
||||
float kd = 0.8;
|
||||
float ks = 0.6;
|
||||
float gamma = 100.0;
|
||||
|
||||
gl_FragColor = vec4(v_pos, 1.0);
|
||||
gl_FragColor.rgb *= ka + (kd * dot(normalize(v_normal), normalize(v_surfaceToLight)));
|
||||
gl_FragColor.rgb += ks * pow(max(0.0, dot(normalize(v_normal), halfVector)), gamma);
|
||||
}
|
||||
`);
|
||||
|
||||
const program = createProgram(gl, [vertexShader, fragmentShader]);
|
||||
|
||||
const {vertices, normals, elements} = generateIsocahedron();
|
||||
|
||||
const positionBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
|
||||
|
||||
const normalBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
|
||||
|
||||
const elementBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
|
||||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(elements), gl.STATIC_DRAW);
|
||||
|
||||
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
||||
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
gl.enable(gl.CULL_FACE);
|
||||
|
||||
const positionAttribLocation = gl.getAttribLocation(program, "a_position");
|
||||
const normalAttribLocation = gl.getAttribLocation(program, "a_normal");
|
||||
|
||||
const matrixLocation = gl.getUniformLocation(program, "u_matrix");
|
||||
const worldMatrixLocation = gl.getUniformLocation(program, "u_world");
|
||||
const worldITMatrixLocation = gl.getUniformLocation(program, "u_worldIT");
|
||||
const lightVecLocation = gl.getUniformLocation(program, "u_light");
|
||||
const cameraVecLocation = gl.getUniformLocation(program, "u_camera");
|
||||
|
||||
const aspectRatio = gl.canvas.width / gl.canvas.height;
|
||||
const zNear = 1;
|
||||
const zFar = 2000;
|
||||
|
||||
const rotation = [0, 0, 0];
|
||||
|
||||
gl.useProgram(program);
|
||||
|
||||
gl.enableVertexAttribArray(positionAttribLocation);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
||||
gl.vertexAttribPointer(
|
||||
positionAttribLocation,
|
||||
3, // element size
|
||||
gl.FLOAT,
|
||||
false, // normalize
|
||||
0, // stride
|
||||
0 // offset
|
||||
);
|
||||
|
||||
gl.enableVertexAttribArray(normalAttribLocation);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
|
||||
gl.vertexAttribPointer(normalAttribLocation, 3, gl.FLOAT, false, 0, 0);
|
||||
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementBuffer);
|
||||
|
||||
function drawScene () {
|
||||
window.requestAnimationFrame(drawScene);
|
||||
|
||||
const t = performance.now() / 1000;
|
||||
|
||||
const lightPos = [10, 10, 30];
|
||||
const projectionMatrix = m4.perspective(Math.PI / 180 * 60, aspectRatio, zNear, zFar);
|
||||
const cameraPos = [0, 0, 30];
|
||||
const target = [0, 0, 0];
|
||||
const up = [0, 1, 0];
|
||||
const cameraMatrix = m4.lookAt(cameraPos, target, up);
|
||||
const viewMatrix = m4.inverse(cameraMatrix);
|
||||
let worldMatrix = m4.identity();
|
||||
worldMatrix = m4.xRotate(worldMatrix, rotation[0]);
|
||||
worldMatrix = m4.yRotate(worldMatrix, rotation[1]);
|
||||
worldMatrix = m4.zRotate(worldMatrix, rotation[2]);
|
||||
worldMatrix = m4.scale(worldMatrix, 12, 12, 12);
|
||||
|
||||
const worldITMatrix = m4.transpose(m4.inverse(worldMatrix));
|
||||
const viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);
|
||||
const worldViewProjectionMatrix = m4.multiply(viewProjectionMatrix, worldMatrix);
|
||||
|
||||
/*
|
||||
let matrix = projectionMatrix;
|
||||
matrix = m4.translate(matrix, 0, 0, -30);
|
||||
matrix = m4.xRotate(matrix, rotation[0]);
|
||||
matrix = m4.yRotate(matrix, rotation[1]);
|
||||
matrix = m4.zRotate(matrix, rotation[2]);
|
||||
matrix = m4.scale(matrix, 10, 10, 10);
|
||||
*/
|
||||
gl.uniformMatrix4fv(matrixLocation, false, worldViewProjectionMatrix);
|
||||
gl.uniformMatrix4fv(worldMatrixLocation, false, worldMatrix);
|
||||
gl.uniformMatrix4fv(worldITMatrixLocation, false, worldITMatrix);
|
||||
gl.uniform3fv(lightVecLocation, lightPos);
|
||||
gl.uniform3fv(cameraVecLocation, cameraPos);
|
||||
|
||||
gl.clearColor(0, 0, 0, 1);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
|
||||
gl.drawElements(
|
||||
gl.TRIANGLES,
|
||||
elements.length, // count
|
||||
gl.UNSIGNED_SHORT,
|
||||
0, // offset
|
||||
);
|
||||
}
|
||||
|
||||
drawScene();
|
||||
|
||||
canvas.addEventListener("click", e => {
|
||||
getGyroPermission()
|
||||
.then(response => {
|
||||
window.addEventListener("deviceorientation", e => {
|
||||
rotation[0] = 2 * (-e.beta / 180 * Math.PI);
|
||||
rotation[1] = 2 * (-e.gamma / 180 * Math.PI);
|
||||
rotation[2] = 2 * (-e.alpha / 180 * Math.PI + Math.PI / 2);
|
||||
});
|
||||
});
|
||||
});
|
BIN
gyro/AufnahmeLIna.mp3
Normal file
BIN
gyro/AufnahmeLIna.mp3
Normal file
Binary file not shown.
130
gyro/Untitled-1.html
Normal file
130
gyro/Untitled-1.html
Normal file
@ -0,0 +1,130 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
|
||||
|
||||
|
||||
<h1>colles gyro dingens</h1>
|
||||
|
||||
<marquee>ich bin der Davidmann2</marquee>
|
||||
|
||||
<fieldset>
|
||||
<legend>
|
||||
status
|
||||
</legend>
|
||||
<strong id="status">
|
||||
loading
|
||||
</strong>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>
|
||||
gyro
|
||||
</legend>
|
||||
<strong id="gyro">
|
||||
loading
|
||||
</strong>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>
|
||||
gyro
|
||||
</legend>
|
||||
<strong id="gyro2">
|
||||
loading
|
||||
</strong>
|
||||
</fieldset>
|
||||
|
||||
<script>
|
||||
function loadAudioFile(fileName){
|
||||
return (
|
||||
fetch(fileName)
|
||||
.then(response=>{
|
||||
return(response.arrayBuffer())
|
||||
})
|
||||
.then(arrayBuffer=>{
|
||||
return(ctx.decodeAudioData(arrayBuffer))
|
||||
})
|
||||
.then(audioBuffer=>{
|
||||
loaded++
|
||||
document.getElementById("status").innerHTML = "loaded " + loaded + "/" + fileNames.length
|
||||
return(audioBuffer)
|
||||
})
|
||||
)
|
||||
}
|
||||
const fileNames = ["AufnahmeLIna.mp3", "blatters.mp3"]
|
||||
let buffers = null
|
||||
let loaded = 0
|
||||
Promise.all(fileNames.map(loadAudioFile))
|
||||
.then(audioBuffers=>{
|
||||
document.getElementById("status").innerHTML = "Done loading"
|
||||
buffers = audioBuffers
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
let samples = null
|
||||
const ctx = new AudioContext()
|
||||
function playStuff(){
|
||||
console.log("imStuff")
|
||||
if(samples == null){
|
||||
samples = []
|
||||
for(const buffer of buffers){
|
||||
const sample = ctx.createBufferSource()
|
||||
sample.buffer = buffer
|
||||
|
||||
const gain = ctx.createGain()
|
||||
|
||||
sample.connect(gain)
|
||||
gain.connect(ctx.destination)
|
||||
|
||||
sample.start()
|
||||
samples.push({sample:sample, gainNode:gain})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function stopStuff(){
|
||||
for(sample of samples){
|
||||
sample.sample.stop()
|
||||
}
|
||||
samples = null
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function getGyroPermission(){
|
||||
if(!DeviceOrientationEvent.requestPermission){
|
||||
return Promise.resolve("granted")
|
||||
}
|
||||
else{
|
||||
return DeviceOrientationEvent.requestPermission()
|
||||
}
|
||||
}
|
||||
function initGyro(){
|
||||
//alert(DeviceOrientationEvent.requestPermission())
|
||||
getGyroPermission().then(response => {
|
||||
window.addEventListener("deviceorientation", e => {
|
||||
document.querySelector("#gyro").innerHTML = e.alpha / 360
|
||||
document.querySelector("#gyro2").innerHTML = (e.beta + 180) / 360
|
||||
if(samples != null){
|
||||
samples[0].gainNode.gain.value = e.alpha / 360
|
||||
samples[1].gainNode.gain.value = (e.beta + 180) / 360
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick="playStuff()">PLAY</button>
|
||||
|
||||
<button onclick="stopStuff()">STOP</button>
|
||||
|
||||
<button onclick="initGyro()">START GYRO</button>
|
||||
|
||||
</body>
|
||||
</html>
|
BIN
gyro/blatters.mp3
Normal file
BIN
gyro/blatters.mp3
Normal file
Binary file not shown.
26
gyro/index.html
Normal file
26
gyro/index.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<h1>Is it working?</h1>
|
||||
<button id="perm">click me for permissions</button>
|
||||
<div style="color: red" id="disp">lalala</div>
|
||||
<script>
|
||||
document.querySelector("#perm").addEventListener("click", e => {
|
||||
const ac = new AudioContext();
|
||||
const osc = ac.createOscillator();
|
||||
|
||||
osc.type = "square";
|
||||
osc.frequency.setValueAtTime(440, ac.currentTime);
|
||||
osc.connect(ac.destination);
|
||||
osc.start();
|
||||
|
||||
DeviceMotionEvent.requestPermission().then(response => {
|
||||
window.addEventListener("devicemotion", e => {
|
||||
document.querySelector("#disp").innerHTML = Math.round(e.acceleration.x);
|
||||
osc.frequency.setValueAtTime(440 * Math.pow(2, e.acceleration.x / 10), ac.currentTime);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user