split code and add ui for changing fragment shader

This commit is contained in:
gbrochar 2020-11-24 12:10:57 +01:00
parent ed902a2ed2
commit 55cb25f291
8 changed files with 290 additions and 132 deletions

20
package-lock.json generated
View File

@ -1288,6 +1288,15 @@
"@types/range-parser": "*"
}
},
"@types/jquery": {
"version": "3.5.4",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.4.tgz",
"integrity": "sha512-//9CHhaUt/rurMJTxGI+I6DmsNHgYU6d8aSLFfO5dB7+10lwLnaWT0z5GY/yY82Q/M+B+0Qh3TixlJ8vmBeqIw==",
"dev": true,
"requires": {
"@types/sizzle": "*"
}
},
"@types/json-schema": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
@ -1353,6 +1362,12 @@
"@types/node": "*"
}
},
"@types/sizzle": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
"integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==",
"dev": true
},
"@typescript-eslint/eslint-plugin": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.8.1.tgz",
@ -3694,6 +3709,11 @@
}
}
},
"jquery": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz",
"integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg=="
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",

View File

@ -41,6 +41,7 @@
"@babel/preset-typescript": "^7.12.7",
"@babel/runtime-corejs3": "^7.12.5",
"@types/express": "^4.17.9",
"@types/jquery": "^3.5.4",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^4.8.1",
@ -63,6 +64,7 @@
"ejs": "^3.1.5",
"express": "^4.17.1",
"gl-mat4": "^1.2.0",
"jquery": "^3.5.1",
"react": "^17.0.1",
"react-dom": "^17.0.1"
}

View File

@ -14,5 +14,10 @@ body {
}
#glCanvas {
display: block;
max-width: 100%;
}
#ui {
display: inline-block;
}

91
src/client/buffers.ts Normal file
View File

@ -0,0 +1,91 @@
/**
* init buffers to create a square
* @param {any} gl the web gl context
* @param {Array<number>} positions the position buffer to be loaded
* @param {Array<number>} indices the index buffer to be loaded
* @param {Array<number>} normals the normal buffer to be loaded
* @return {any} the buffers
*/
export function initBuffers(
gl: any,
positions: Array<number>,
indices: Array<number>,
normals: Array<number>) {
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(positions),
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 myColors = [
[1.0, 1.0, 1.0, 1.0],
[1.0, 0.0, 0.0, 1.0],
[0.0, 1.0, 0.0, 1.0],
[0.0, 0.0, 1.0, 1.0],
[1.0, 1.0, 0.0, 1.0],
[1.0, 0.0, 1.0, 1.0],
[0.0, 0.0, 0.0, 1.0],
[0.0, 1.0, 1.0, 1.0],
];
let faceColors: any = [];
for (let i = 0; i < 70; i++) {
faceColors = faceColors.concat(myColors);
}
// Convert the array of colors into a table for all the vertices.
const colors: any = [];
for (let j = 0; j < indices.length; ++j) {
const c = [
myColors[Math.floor(Math.random() * 8)],
faceColors[Math.floor(Math.random() * 8)],
faceColors[Math.floor(Math.random() * 8)],
faceColors[Math.floor(Math.random() * 8)],
];
// Repeat each color four times for the four vertices of the face
// colors = colors.concat([1.0, 1.0, 1.0, 1.0]);
colors.push(c[0][0]);
colors.push(c[0][1]);
colors.push(c[0][2]);
colors.push(c[0][3]);
}
const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
new Uint16Array(indices), gl.STATIC_DRAW);
// Now send the element array to GL
return {
position: positionBuffer,
color: colorBuffer,
indices: indexBuffer,
normals: normalBuffer,
};
}
/**
* init buffers to create a square
* @param {any} gl the web gl context
* @param {any} buffers the buffers to delete
*/
export function deleteBuffers(gl: any, buffers: any) {
for (const buffer of Object.entries(buffers)) {
gl.deleteBuffer(buffer);
}
}

View File

@ -0,0 +1,44 @@
import {initShaderProgram,
unlinkShaderProgram} from './shaders';
/**
*
* @param {any} gl the gl context
* @param {any} shaderProgram the shader program
* @param {any} fragmentShader the current fragment shader
* @param {string} fsSource new fragment shader source
* @param {string} vsSource current vsSource
* @return {any} the program info object
*/
export function changeFragmentShader(gl: any,
shaderProgram: any,
fragmentShader: any,
fsSource: string,
vsSource: string) {
shaderProgram = unlinkShaderProgram(gl,
fragmentShader,
shaderProgram);
[shaderProgram, fragmentShader] = initShaderProgram(gl,
vsSource,
fsSource)!;
const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram,
'aVertexPosition'),
vertexColor: gl.getAttribLocation(shaderProgram,
'aVertexColor'),
vertexNormal: gl.getAttribLocation(shaderProgram,
'aVertexNormal'),
},
uniformLocations: {
projectionMatrix: gl.getUniformLocation(
shaderProgram, 'uProjectionMatrix'),
viewMatrix: gl.getUniformLocation(
shaderProgram, 'uviewMatrix'),
modelMatrix: gl.getUniformLocation(
shaderProgram, 'umodelMatrix'),
},
};
return programInfo;
}

View File

@ -2,6 +2,11 @@
import mat4 from 'gl-mat4';
// @ts-ignore
import convert from './objparser';
import $ from 'jquery';
import {initBuffers} from './buffers';
import {initShaderProgram} from './shaders';
import {changeFragmentShader} from './changeshader';
let squareRotation = 0.0;
@ -83,6 +88,42 @@ function main() {
gl_FragColor = vec4((texture * diffuse * 0.9) + (texture * 0.1) + (specular * vec3(1.)), 1.0);
}`;
const fsSource2 = `
precision highp float;
varying highp vec4 vColor;
varying highp vec4 vNormal;
varying highp vec3 vPosition;
vec3 extremize(vec3 v, float n) {
if (v.x > n / 2.)
v.x = n;
else
v.x = 0.;
if (v.y > n / 2.)
v.y = n;
else
v.y = 0.;
if (v.z > n / 2.)
v.z = n;
else
v.z = 0.;
return v;
}
void main() {
vec3 n = normalize(vec3(-500., 1000., 500.) - vPosition);
float diffuse = max(dot(vNormal.xyz, n), 0.);
float specular = pow(
max(dot(
reflect(n, vNormal.xyz),
normalize(vec3(0., 0., -50.) - vPosition)),
0.), 10.);
vec3 tmp = extremize(mod(vPosition.xyz + vec3(100.), vec3(3.)), 3.);
vec3 texture = vec3(tmp.x / 3., tmp.y / 3., tmp.z / 3.);
gl_FragColor = vec4((texture * diffuse * 0.9) + (texture * vec3(0.1)) + (specular * vec3(1.)), 1.0);
}`;
/* eslint-enable */
fetch('/static/objs/teapot_normals.obj').then((response) => {
@ -96,8 +137,8 @@ function main() {
] = convert(data);
console.log(uvs);
console.log(squareRotation);
const normals = [];
const positions = [];
const normals: any = [];
const positions: any = [];
for (let i = 0; i < convertedNormals.length; i++) {
if (i % 4 != 0) {
normals.push(convertedNormals[i]);
@ -108,9 +149,11 @@ function main() {
positions.push(convertedPositions[i]);
}
}
const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
const [shaderProgram, fragmentShader]: any = initShaderProgram(gl,
vsSource,
fsSource);
const programInfo: any = {
let programInfo: any = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram,
@ -132,6 +175,7 @@ function main() {
const buffers = initBuffers(gl, positions, indices, normals);
let then = 0;
let changed = false;
/**
* Draws the scene repeatedly
@ -140,142 +184,28 @@ function main() {
function render(now: any) {
now *= 0.001;
const deltaTime = now - then;
if (now >= 1 && changed == false) {
changed = true;
}
then = now;
drawScene(gl, programInfo, buffers, deltaTime, indices.length);
requestAnimationFrame(render);
}
$(function() {
$('#button1').on('click', function() {
programInfo = changeFragmentShader(gl,
shaderProgram, fragmentShader, fsSource, vsSource);
});
$('#button2').on('click', function() {
programInfo = changeFragmentShader(gl,
shaderProgram, fragmentShader, fsSource2, vsSource);
});
});
requestAnimationFrame(render);
});
}
/**
* Initialize a shader program, so WebGL knows how to draw our data
* @param {any} gl the WebGL context
* @param {string} vsSource the vertex shader source
* @param {string} fsSource the fragment shader source
* @return {any} the shader program
*/
function initShaderProgram(gl: any, vsSource: string, fsSource: string) {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
// Create the shader program
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
// If creating the shader program failed, alert
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Unable to initialize the shader program: ' +
gl.getProgramInfoLog(shaderProgram));
return null;
}
return shaderProgram;
}
/**
* load a GL shader
* @param {any} gl the WebGL context
* @param {any} type type of shader to load
* @param {string} source source code of shader
* @return {any} the loaded shader
*/
function loadShader(gl: any, type: any, source: string) {
const shader = gl.createShader(type);
// Send the source to the shader object
gl.shaderSource(shader, source);
// Compile the shader program
gl.compileShader(shader);
// See if it compiled successfully
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('An error occurred compiling the shaders: ' +
gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
/**
* init buffers to create a square
* @param {any} gl the web gl context
* @param {Array<number>} positions the position buffer to be loaded
* @param {Array<number>} indices the index buffer to be loaded
* @param {Array<number>} normals the normal buffer to be loaded
* @return {any} the buffer
*/
function initBuffers(
gl: any,
positions: Array<number>,
indices: Array<number>,
normals: Array<number>) {
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(positions),
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 myColors = [
[1.0, 1.0, 1.0, 1.0],
[1.0, 0.0, 0.0, 1.0],
[0.0, 1.0, 0.0, 1.0],
[0.0, 0.0, 1.0, 1.0],
[1.0, 1.0, 0.0, 1.0],
[1.0, 0.0, 1.0, 1.0],
[0.0, 0.0, 0.0, 1.0],
[0.0, 1.0, 1.0, 1.0],
];
let faceColors: any = [];
for (let i = 0; i < 70; i++) {
faceColors = faceColors.concat(myColors);
}
// Convert the array of colors into a table for all the vertices.
const colors: any = [];
for (let j = 0; j < indices.length; ++j) {
const c = [
myColors[Math.floor(Math.random() * 8)],
faceColors[Math.floor(Math.random() * 8)],
faceColors[Math.floor(Math.random() * 8)],
faceColors[Math.floor(Math.random() * 8)],
];
// Repeat each color four times for the four vertices of the face
// colors = colors.concat([1.0, 1.0, 1.0, 1.0]);
colors.push(c[0][0]);
colors.push(c[0][1]);
colors.push(c[0][2]);
colors.push(c[0][3]);
}
const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
new Uint16Array(indices), gl.STATIC_DRAW);
// Now send the element array to GL
return {
position: positionBuffer,
color: colorBuffer,
indices: indexBuffer,
normals: normalBuffer,
};
}
/**
* Draw a webgl scene

62
src/client/shaders.ts Normal file
View File

@ -0,0 +1,62 @@
/**
* Initialize a shader program, so WebGL knows how to draw our data
* @param {any} gl the WebGL context
* @param {any} shader the shader to unlink
* @param {any} shaderProgram the existing shaderprogram
* @return {any} the shader program
*/
export function unlinkShaderProgram(gl: any, shader: any, shaderProgram: any) {
// Create the shader program
gl.detachShader(shaderProgram, shader);
gl.deleteShader(shader);
return shaderProgram;
}
/**
* Initialize a shader program, so WebGL knows how to draw our data
* @param {any} gl the WebGL context
* @param {string} vsSource the vertex shader source
* @param {string} fsSource the fragment shader source
* @return {any} the shader program
*/
export function initShaderProgram(gl: any, vsSource: string, fsSource: string) {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
// Create the shader program
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
// If creating the shader program failed, alert
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Unable to initialize the shader program: ' +
gl.getProgramInfoLog(shaderProgram));
return null;
}
return [shaderProgram, fragmentShader];
}
/**
* load a GL shader
* @param {any} gl the WebGL context
* @param {any} type type of shader to load
* @param {string} source source code of shader
* @return {any} the loaded shader
*/
export function loadShader(gl: any, type: any, source: string) {
const shader = gl.createShader(type);
// Send the source to the shader object
gl.shaderSource(shader, source);
// Compile the shader program
gl.compileShader(shader);
// See if it compiled successfully
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('An error occurred compiling the shaders: ' +
gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}

View File

@ -13,6 +13,10 @@
<body>
<div id="root">
<canvas id='glCanvas' width='640' height='640'></canvas>
<div id='ui'>
<button id='button1'>Change Shader to black and white</button>
<button id='button2'>Change Shader to colored</button>
</div>
</div>
<script src="js/bundle.js"></script>
</body>