'use strict';
/* global twgl,requestAnimationFrame,document */
const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texcoord;
uniform mat4 projection;
uniform mat4 modelView;
uniform float uAnimationStep;
const float ease_out = 0.0;
varying vec3 v_normal;
varying vec2 v_texcoord;
#define PI radians(180.0)
mat4 rotY(float angleInRadians) {
float s = sin(angleInRadians);
float c = cos(angleInRadians);
return mat4(
c,-s,1,s,c,1);
}
void main() {
vec2 aTextureCoord = texcoord;
float curve = mix(0.0,0.25,aTextureCoord.y);
float y_rot = mix(uAnimationStep,ease_out + curve,aTextureCoord.x) * -PI;
mat4 effectiveModelView = modelView * rotY(y_rot);
gl_Position = projection * effectiveModelView * position;
v_normal = mat3(effectiveModelView) * normal;
v_texcoord = texcoord;
}
`;
const fs = `
precision highp float;
varying vec3 v_normal;
varying vec2 v_texcoord;
varying float v_modelId;
uniform sampler2D tex;
void main() {
vec3 lightDirection = normalize(vec3(1,2,30)); // arbitrary light direction
vec3 color = texture2D(tex,v_texcoord).rgb;
float l = dot(lightDirection,normalize(v_normal)) * .5 + .5;
gl_FragColor = vec4(color * l,1);
}
`;
// compile shader,link,look up locations
const programInfo = twgl.createProgramInfo(gl,[vs,fs]);
// make some vertex data
// calls gl.createBuffer,gl.bindBuffer,gl.bufferData
const bufferInfo = twgl.primitives.createPlaneBufferInfo(
gl,32,// width
32,// depth
32,// width subdivisions
32,// height subdivisions
m4.rotationX(Math.PI / 2),// matrix to apply (plane is XZ,make it XY)
);
const tex = twgl.createTexture(gl,{src: 'https://i.imgur.com/ZKMnXce.png'});
function render(time) {
time *= 0.001; // seconds
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0,gl.canvas.width,gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
const fov = Math.PI * 0.25;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const near = 0.1;
const far = 100;
const projection = m4.perspective(fov,aspect,near,far);
const eye = [0,30,35];
const target = [0,0];
const up = [0,0];
const camera = m4.lookAt(eye,target,up);
const view = m4.inverse(camera);
let modelView = m4.rotateY(view,0.2 * time);
modelView = m4.translate(modelView,[0,0]);
gl.useProgram(programInfo.program);
// calls gl.bindBuffer,gl.enableVertexAttribArray,gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl,programInfo,bufferInfo);
// calls gl.activeTexture,gl.bindTexture,gl.uniformXXX
twgl.setUniforms(programInfo,{
projection,modelView,tex,uAnimationStep: Math.sin(time),});
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl,bufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>