texture support

This commit is contained in:
gbrochar 2020-11-24 19:18:45 +01:00
parent b1168ca920
commit ce7914732e
9 changed files with 198 additions and 90 deletions

BIN
public/textures/fox.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
public/textures/ice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
public/textures/noise.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
public/textures/wall.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 KiB

View File

@ -5,13 +5,15 @@
* @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
* @param {Array<number>} uvs the texture buffer to be loaded
* @return {any} the buffers
*/
export function initBuffers(
gl: any,
positions: Array<number>,
indices: Array<number>,
normals: Array<number>) {
normals: Array<number>,
uvs: Array<number>) {
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(
@ -32,10 +34,17 @@ export function initBuffers(
new Uint16Array(indices), gl.STATIC_DRAW);
// Now send the element array to GL
const uvBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
gl.bufferData(gl.ARRAY_BUFFER,
new Float32Array(uvs),
gl.STATIC_DRAW);
return {
position: positionBuffer,
positions: positionBuffer,
indices: indexBuffer,
normals: normalBuffer,
uvs: uvBuffer,
};
}
@ -45,8 +54,8 @@ export function initBuffers(
* @param {any} buffers the buffers to delete
*/
export function deleteBuffers(gl: any, buffers: any) {
gl.deleteBuffer(buffers.color);
gl.deleteBuffer(buffers.position);
gl.deleteBuffer(buffers.uvs);
gl.deleteBuffer(buffers.positions);
gl.deleteBuffer(buffers.normals);
gl.deleteBuffer(buffers.indices);
}

View File

@ -30,6 +30,8 @@ export function changeFragmentShader(gl: any,
'aVertexColor'),
vertexNormal: gl.getAttribLocation(shaderProgram,
'aVertexNormal'),
textureCoord: gl.getAttribLocation(shaderProgram,
'aTextureCoord'),
},
uniformLocations: {
projectionMatrix: gl.getUniformLocation(
@ -38,6 +40,8 @@ export function changeFragmentShader(gl: any,
shaderProgram, 'uviewMatrix'),
modelMatrix: gl.getUniformLocation(
shaderProgram, 'umodelMatrix'),
uSampler: gl.getUniformLocation(
shaderProgram, 'uSampler'),
},
};
return [programInfo, fragmentShader];

View File

@ -1,12 +1,13 @@
// @ts-ignore
import mat4 from 'gl-mat4';
// @ts-ignore
import convert from './objparser';
import {convert} from './objparser';
import $ from 'jquery';
import {initBuffers, deleteBuffers} from './buffers';
import {initShaderProgram} from './shaders';
import {changeFragmentShader} from './changeshader';
import {loadTexture} from './texture';
let squareRotation = 0.0;
@ -31,6 +32,7 @@ async function main() {
const vsSource = `
attribute vec4 aVertexPosition;
attribute vec4 aVertexNormal;
attribute vec2 aTextureCoord;
uniform mat4 uProjectionMatrix;
uniform mat4 uviewMatrix;
@ -38,6 +40,8 @@ async function main() {
varying highp vec4 vNormal;
varying highp vec3 vPosition;
varying highp vec2 vTextureCoord;
void main()
{
gl_Position = uProjectionMatrix *
@ -46,6 +50,7 @@ async function main() {
aVertexPosition;
vPosition = vec3(aVertexPosition);
vNormal = umodelMatrix * aVertexNormal;
vTextureCoord = aTextureCoord;
}
`;
@ -151,6 +156,27 @@ async function main() {
vec3 texture = extremize(mod(vPosition.xyz + vec3(1000.), vec3(2.)), 2.) / vec3(2);
gl_FragColor = vec4((diffuse * 0.8) + (vec3(0.2)) + (specular * vec3(1.)), 1.0);
}`;
const fsSource4 = `
precision highp float;
varying highp vec2 vTextureCoord;
varying highp vec4 vNormal;
varying highp vec3 vPosition;
uniform sampler2D uSampler;
void main() {
highp vec4 texelColor = texture2D(uSampler, vTextureCoord);
vec3 n = normalize(vec3(-50000., 100000., 50000.) - vPosition);
float diffuse = max(dot(normalize(vNormal.xyz), n), 0.);
float specular = pow(
max(dot(
reflect(n, normalize(vNormal.xyz)),
normalize(vec3(0., 0., -50.) - vPosition)),
0.), 10.);
gl_FragColor = vec4((texelColor.xyz * diffuse * 0.8) + (texelColor.xyz * vec3(0.2)) + (specular * vec3(1.)), 1.0);
}`;
/* eslint-enable */
@ -165,7 +191,7 @@ async function main() {
return data;
}
const data = await getObj('/static/objs/teapot.obj');
const data = await getObj('/static/objs/fox.obj');
let distance: any = $('#input1').val();
let circleSize: any = $('#input2').val();
distance = parseFloat(distance);
@ -177,10 +203,9 @@ async function main() {
indices,
] = convert(data);
let length = indices.length;
console.log(uvs);
let [shaderProgram, fragmentShader]: any = initShaderProgram(gl,
vsSource,
fsSource3);
fsSource4);
let programInfo: any = {
program: shaderProgram,
@ -189,6 +214,8 @@ async function main() {
'aVertexPosition'),
vertexNormal: gl.getAttribLocation(shaderProgram,
'aVertexNormal'),
textureCoord: gl.getAttribLocation(shaderProgram,
'aTextureCoord'),
},
uniformLocations: {
projectionMatrix: gl.getUniformLocation(
@ -197,10 +224,13 @@ async function main() {
shaderProgram, 'uviewMatrix'),
modelMatrix: gl.getUniformLocation(
shaderProgram, 'umodelMatrix'),
uSampler: gl.getUniformLocation(
shaderProgram, 'uSampler'),
},
};
let buffers = initBuffers(gl, positions, indices, normals);
let texture = loadTexture(gl, '/static/textures/fox.png');
let buffers = initBuffers(gl, positions, indices, normals, uvs);
let then = 0;
let changed = false;
@ -221,7 +251,8 @@ async function main() {
deltaTime,
length,
distance,
circleSize);
circleSize,
texture);
requestAnimationFrame(render);
}
@ -236,10 +267,9 @@ async function main() {
uvs,
indices,
] = convert(data);
console.log(uvs);
length = indices.length;
deleteBuffers(gl, buffers);
buffers = initBuffers(gl, positions, indices, normals);
buffers = initBuffers(gl, positions, indices, normals, uvs);
}
$(function() {
@ -255,18 +285,22 @@ async function main() {
$('#changecirclesize').click();
}
});
$('#button1').on('click', function() {
$('#s_blackandwhite').on('click', function() {
[programInfo, fragmentShader] = changeFragmentShader(gl,
shaderProgram, fragmentShader, fsSource, vsSource);
});
$('#button2').on('click', function() {
$('#s_color').on('click', function() {
[programInfo, fragmentShader] = changeFragmentShader(gl,
shaderProgram, fragmentShader, fsSource2, vsSource);
});
$('#button3').on('click', function() {
$('#s_flat').on('click', function() {
[programInfo, fragmentShader] = changeFragmentShader(gl,
shaderProgram, fragmentShader, fsSource3, vsSource);
});
$('#s_texture').on('click', function() {
[programInfo, fragmentShader] = changeFragmentShader(gl,
shaderProgram, fragmentShader, fsSource4, vsSource);
});
$('#changedistance').on('click', function() {
distance = $('#input1').val();
distance = parseFloat(distance);
@ -287,6 +321,18 @@ async function main() {
const data = await getObj('/static/objs/fox.obj');
updateObj(data);
});
$('#t_wall').on('click', async function() {
texture = loadTexture(gl, '/static/textures/wall.png');
});
$('#t_ice').on('click', async function() {
texture = loadTexture(gl, '/static/textures/ice.png');
});
$('#t_noise').on('click', async function() {
texture = loadTexture(gl, '/static/textures/noise.png');
});
$('#t_fox').on('click', async function() {
texture = loadTexture(gl, '/static/textures/fox.png');
});
});
requestAnimationFrame(render);
}
@ -300,6 +346,7 @@ async function main() {
* @param {number} length the index buffer length
* @param {number} distance distance of camera
* @param {number} circleSize size of circle the object is rotating around
* @param {any} texture the texture to load
*/
function drawScene(gl: any,
programInfo: any,
@ -307,7 +354,8 @@ function drawScene(gl: any,
deltaTime: number,
length: number,
distance: number,
circleSize: number) {
circleSize: number,
texture: any) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clearDepth(1.0);
gl.enable(gl.DEPTH_TEST);
@ -374,7 +422,7 @@ function drawScene(gl: any,
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.positions);
gl.vertexAttribPointer(
programInfo.attribLocations.vertexPosition,
numComponents,
@ -405,6 +453,30 @@ function drawScene(gl: any,
programInfo.attribLocations.vertexNormal);
}
// tell webgl how to pull out the texture coordinates from buffer
{
const num = 2; // every coordinate composed of 2 values
const type = gl.FLOAT; // the data in the buffer is 32 bit float
const normalize = false; // don't normalize
const stride = 0; // how many bytes to get from one set to the next
const offset = 0; // how many bytes inside the buffer to start from
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.uvs);
gl.vertexAttribPointer(programInfo.attribLocations.textureCoord,
num,
type,
normalize,
stride,
offset);
gl.enableVertexAttribArray(programInfo.attribLocations.textureCoord);
}
// Tell WebGL we want to affect texture unit 0
gl.activeTexture(gl.TEXTURE0);
// Bind the texture to texture unit 0
gl.bindTexture(gl.TEXTURE_2D, texture);
// Tell the shader we bound the texture to texture unit 0
gl.uniform1i(programInfo.uniformLocations.uSampler, 0);
// Tell WebGL which indices to use to index the vertices
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);

View File

@ -1,6 +1,5 @@
export default function convert (objText) {
export function convert (objText) {
const lines = objText.split("\n");
let smoothing = false;
const positions = [];
@ -11,67 +10,87 @@ export default function convert (objText) {
const indices = [];
for (let i = 0; i < lines.length; i++) {
if (lines[i] != '')
{
const rawchunks = lines[i].split(" ").map(x => x.trim());
const chunks = [];
for (let i = 0; i < rawchunks.length; i++) {
if (rawchunks[i] != '') {
chunks.push(rawchunks[i]);
}
}
switch (chunks[0]) {
case "v": {
positions.push(chunks.splice(1).map(parseFloat));
break;
}
case "vt": {
const uv = chunks.splice(1);
uvs.push([parseFloat(uv[0]), parseFloat(uv[1])]);
break;
}
case "vn": {
normals.push(chunks.splice(1).map(parseFloat));
break;
}
case "s": {
if (chunks[1] > 0) {
smoothing = true;
} else {
smoothing = false;
}
break;
}
case "f": {
const c1 = (smoothing ? "s" : "") + chunks[1];
const c2 = (smoothing ? "s" : "") + chunks[2];
const c3 = (smoothing ? "s" : "") + chunks[3];
let index1 = vertices.indexOf(c1);
if (index1 === -1) {
index1 = vertices.length;
vertices.push(c1);
}
let index2 = vertices.indexOf(c2);
if (index2 === -1) {
index2 = vertices.length;
vertices.push(c2);
}
let index3 = vertices.indexOf(c3);
if (index3 === -1) {
index3 = vertices.length;
vertices.push(c3);
}
indices.push(index1, index2, index3);
break;
}
const line = lines[i];
const rawchunks = line.split(" ").map(x => x.trim());
const chunks = [];
for (let i = 0; i < rawchunks.length; i++) {
if (rawchunks[i] != '') {
chunks.push(rawchunks[i]);
}
}
switch (chunks[0]) {
case "v": {
positions.push(chunks.splice(1).map(parseFloat));
break;
}
case "vt": {
const uv = chunks.splice(1);
uvs.push([parseFloat(uv[0]), parseFloat(uv[1])]);
break;
}
case "vn": {
normals.push(chunks.splice(1).map(parseFloat));
break;
}
case "s": {
if (chunks[1] > 0) {
smoothing = true;
} else {
smoothing = false;
}
break;
}
case "f": {
const c1 = (smoothing ? "s" : "") + chunks[1];
const c2 = (smoothing ? "s" : "") + chunks[2];
const c3 = (smoothing ? "s" : "") + chunks[3];
let index1 = vertices.indexOf(c1);
if (index1 === -1) {
index1 = vertices.length;
vertices.push(c1);
}
let index2 = vertices.indexOf(c2);
if (index2 === -1) {
index2 = vertices.length;
vertices.push(c2);
}
let index3 = vertices.indexOf(c3);
if (index3 === -1) {
index3 = vertices.length;
vertices.push(c3);
}
indices.push(index1, index2, index3);
break;
}
}
}
const avgNormals = [];
for (let i = 0; i < vertices.length; i++) {
if (vertices[i].startsWith("s")) {
const d = vertices[i].substr(1).split("/");
const normal = normals[d[2] - 1];
const index = d[0] - 1;
if (avgNormals[index]) {
avgNormals[index][0] += normal[0];
avgNormals[index][1] += normal[1];
avgNormals[index][2] += normal[2];
} else {
avgNormals[index] = normal;
}
}
}
for (let n of avgNormals) {
const len = Math.hypot(...n);
avgNormals[avgNormals.indexOf(n)] = n.map(x => x / len);
}
const outPositions = [];
@ -82,12 +101,16 @@ export default function convert (objText) {
const d = (vertices[i].startsWith("s") ? vertices[i].substr(1) : vertices[i]).split("/");
outPositions.push(...positions[d[0] - 1]);
if (normals.length) {
if (vertices[i].startsWith("s")) {
outNormals.push(...avgNormals[d[0] - 1]);
} else {
outNormals.push(...normals[d[2] - 1]);
}
if (uvs.length) {
outUVs.push(...uvs[d[1] - 1]);
}
outUVs.push(...uvs[d[1] - 1]);
}
console.log(indices);
return [outPositions, outNormals, outUVs, indices];
};

View File

@ -15,18 +15,18 @@
<canvas id='glCanvas' width='640' height='640'></canvas>
<div id='ui'>
<div class='ui-block'>
<button id='button1'>Change Shader to black and white</button>
<button id='button2'>Change Shader to colored</button>
<button id='button3'>Change Shader to flat</button>
<button id='button3'>Change Shader to texture</button>
<button id='s_blackandwhite'>Change Shader to black and white</button>
<button id='s_color'>Change Shader to colored</button>
<button id='s_flat'>Change Shader to flat</button>
<button id='s_texture'>Change Shader to texture</button>
</div>
<div class='ui-block'>
<input id='input1' value='50'></input>
<input id='input1' value='250'></input>
<button id='changedistance'>Change camera distance</button>
<div style='display: inline'>Max distance is 1000</div>
</div>
<div class='ui-block'>
<input id='input2' value='5'></input>
<input id='input2' value='30'></input>
<button id='changecirclesize'>Change circle size</button>
</div>
<div class='ui-block'>
@ -35,10 +35,10 @@
<button id='o_fox'>Set object to fox</button>
</div>
<div class='ui-block'>
<button id='t_grey'>Set texture to white</button>
<button id='t_wall'>Set texture to wall</button>
<button id='t_fox'>Set texture to fox</button>
<button id='t_ice'>Set texture to ice</button>
<button id='t_noise'>Set texture to noise</button>
<button id='t_fox'>Set texture to fox</button>
</div>
</div>
</div>