function getRotation(angle) {
let rotation = [];
const angleInRadians = angle * Math.PI / 180;
rotation[0] = Math.sin(angleInRadians);
rotation[1] = Math.cos(angleInRadians);
return rotation;
}
/**
* 加载图片
* @param imageName
* @param pork
* @param callback
*/
function loadImage(imageName, pork, callback) {
const image = new Image();
image.src = "http://127.0.0.1:" + pork + "/WebGLDemo/textures/" + imageName;
image.onload = () => {
callback(image);
};
}
function setTexture(gl, image) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); //gl.LINEAR
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); //gl.NEAREST
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
}
function setRectangle(gl, x, y, width, height) {
const x1 = x;
const x2 = x + width;
const y1 = y;
const y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2,
]), gl.STATIC_DRAW);
}
/**
* 获得绘图上下文gl WebGLRenderingContext
* @param {Object} width
* @param {Object} height
*/
function getWebGLRenderingContext(width, height) {
const canvas = document.createElement("canvas");
document.getElementsByTagName("body")[0].appendChild(canvas);
canvas.width = width;
canvas.height = height;
const gl = canvas.getContext("webgl");
if (!gl) {
console.log("%c不支持webgl", "color:#F00");
return null;
}
return gl;
}
function getShaderSource(isVertex) {
let source;
if (isVertex) {
source = document.querySelector("#vertex-shader-2d").text;
} else {
source = document.querySelector("#fragment-shader-2d").text;
}
return source;
}
/**
* @param {Object} gl WebGLReanderingContext
* @param {Object} type gl.VERTEX_SHADER/gl.FRAGMENT_SHADER
* @param {Object} source source string
*/
function createShader(gl, type, source) {
const shader = gl.createShader(type); //创建相关类型的shader
gl.shaderSource(shader, source); //提供shader的资源
gl.compileShader(shader); //编译shader
const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (success) {
return shader;
}
console.log(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
}
/**
* 链接(link)2个shader,得到着色程序program
* @param {Object} gl WebGLReanderingContext
* @param {Object} vertexShader 顶点着色器
* @param {Object} fragmentShader 片段着色器
*/
function createProgram(gl, vertexShader, fragmentShader) {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
const success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success) {
return program;
}
console.log(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
}
function render(gl, program, image) {
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
const texCoordAttributeLocation = gl.getAttribLocation(program, "a_texCoord");
const resolutionUniformLocation = gl.getUniformLocation(program, "u_resolution");
const translationUniformLocation = gl.getUniformLocation(program, "u_translation");
const rotationUniformLocation = gl.getUniformLocation(program, "u_rotation");
const scaleUniformLocation = gl.getUniformLocation(program, "u_scale");
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
setRectangle(gl, 0, 0, image.width, image.height); //矩形(2个三角形)
const texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0
]), gl.STATIC_DRAW);
//开始渲染
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(program);
// uniform: 设置全局属性
gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);
gl.enableVertexAttribArray(positionAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const size = 2; //每次迭代运行提取2个单位数据
const type = gl.FLOAT; //每个单位数据是32位的浮点数
const normaliza = false; //不需要归一化数据
const stride = 0; //0 = 移动单位数量 * 每个单位占用的内存(sizeof(type))
const offset = 0; //每次迭代运行运动多少内存到下一个数据开始点,从缓冲起始位置开始读取
gl.vertexAttribPointer(positionAttributeLocation, size, type, normaliza, stride, offset);
gl.enableVertexAttribArray(texCoordAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.vertexAttribPointer(texCoordAttributeLocation, 2, gl.FLOAT, false, 0, 0);
setTexture(gl, image);
const primitiveType = gl.TRIANGLES; //绘制三角形
const pOffset = 0; //从第一个点开始绘制
const count = 6; //绘制6个点(运行6次)
let angle = 50;
let scale = 0.7;
let isScaleAdd = true;
setInterval(() => {
if (isScaleAdd) {
scale += 0.01;
if (scale >= 1.4) {
isScaleAdd = false;
}
} else {
scale -= 0.01;
if (scale <= 0.7) {
isScaleAdd = true;
}
}
gl.uniform2fv(translationUniformLocation, [150, 150]);
gl.uniform2fv(rotationUniformLocation, getRotation(angle));
gl.uniform2fv(scaleUniformLocation, [scale, scale]);
gl.drawArrays(primitiveType, pOffset, count);
}, 15);
}
function main() {
const WIDTH = 400;
const HEIGHT = 300;
const gl = getWebGLRenderingContext(WIDTH, HEIGHT);
if (!gl) return;
//#region 构建2个shader
const vertexShader = createShader(gl, gl.VERTEX_SHADER, getShaderSource(true));
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, getShaderSource(false));
//#endregion
//#region link2个shader
const program = createProgram(gl, vertexShader, fragmentShader);
//#endregiopn
loadImage("cocos.png", 8848, (image) => {
render(gl, program, image);
});
}
main();