rollup-plugin-element3-webgl
Version:
rollup plugin for parsing webgl
315 lines (279 loc) • 8.23 kB
JavaScript
import fs from 'fs';
var t = (vertexShader, fragmentShader, watchers, properties,uniformInit) => `
import { h, onMounted, ref, watchEffect,watch } from "vue";
export default {
name: "webgl-renderer",
props: {
width: String,
height: String,
indicesCount: {
default: () => 5,
},
indicesStart: {
default: () => 0,
},
${properties}
},
setup(props) {
const canvas = ref(null);
let gl;
let glProgram;
watchEffect(() => {
if (!gl || !glProgram) return;
gl.drawArrays(gl.TRIANGLE_STRIP, props.indicesStart, props.indicesCount);
});
onMounted(() => {
//获取webgl上下文
gl = canvas.value.getContext("webgl");
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, \`${vertexShader}\`);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, \`${fragmentShader}\`);
gl.compileShader(fragShader);
glProgram = gl.createProgram();
gl.attachShader(glProgram, vertShader);
gl.attachShader(glProgram, fragShader);
gl.linkProgram(glProgram);
gl.useProgram(glProgram);
var a_PointSize = gl.getAttribLocation(glProgram, "a_PointSize");
gl.vertexAttrib1f(a_PointSize, 30.0);
//1.创建缓冲区对象
var vertexBuffer = gl.createBuffer();
// 2.绑定缓冲区对象(表明了缓冲区对象的用途)
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 3.向缓冲区对象中写入数据
var tempData = new Float32Array([-1, -1, -1, 1, 1, 1, 1, -1, -1, -1]);
gl.bufferData(gl.ARRAY_BUFFER, tempData, gl.STATIC_DRAW);
// 4.获取变量存储位置
var a_Position = gl.getAttribLocation(glProgram, "a_Position");
// 5.把缓冲区对象分配给a_Position变量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
// 6.连接缓冲区对象和a_Position变量
gl.enableVertexAttribArray(a_Position);
gl.drawArrays(
gl.TRIANGLE_STRIP,
props["indicesStart"],
props["indicesCount"]
);
//gl.drawArrays(gl.POINTS, 0, 3);
${uniformInit}
});
${watchers}
return {
canvas,
};
},
render: function() {
return h("canvas", {
ref: "canvas",
width: this.$props["width"],
height: this.$props["height"],
});
},
};
`;
function compileFileToComponent (fragmentShaderSource, map) {
var hasVertexShader = false;
try {
var vertexShaderSource = fs.readFileSync(
this.resourcePath.replace(/.frag$/, ".vert2"),
"utf8"
);
hasVertexShader = true;
} catch (err) {
var vertexShaderSource = `attribute vec4 a_Position;
void main(){
gl_Position=a_Position;
}
`;
hasVertexShader = false;
}
var typeMapping = {
bool: {
jsType: "Boolean",
ctxMethod: "uniform1fv",
},
bvec2: {
jsType: "Float32Array",
ctxMethod: "uniform2fv",
},
bvec3: {
jsType: "Float32Array",
ctxMethod: "uniform3fv",
},
bvec4: {
jsType: "Float32Array",
ctxMethod: "uniform4fv",
},
float: {
jsType: "Number",
ctxMethod: "uniform1f",
},
vec2: {
jsType: "Array",
ctxMethod: "uniform2fv",
},
vec3: {
jsType: "Array",
ctxMethod: "uniform3fv",
},
vec4: {
jsType: "Array",
ctxMethod: "uniform4fv",
},
int: {
jsType: "Number",
ctxMethod: "uniform1i",
},
ivec2: {
jsType: "Int32Array",
ctxMethod: "uniform2iv",
},
ivec3: {
jsType: "Int32Array",
ctxMethod: "uniform3iv",
},
ivec4: {
jsType: "Int32Array",
ctxMethod: "uniform4iv",
},
mat2: {
jsType: "Float32Array",
ctxMethod: "uniformMatrix2fv",
},
mat3: {
jsType: "Float32Array",
ctxMethod: "uniformMatrix3fv",
},
mat4: {
jsType: "Float32Array",
ctxMethod: "uniformMatrix4fv",
},
sampler2D: {
jsType: "Float32Array",
},
samplerCube: {
//TODO
},
};
var uniformInitTemplate = (name, jsType, ctxMethod) => `
let ${name} = gl.getUniformLocation(glProgram,'${name}');
gl.${ctxMethod}(${name}, ${jsType}(props.${name}));
gl.drawArrays(gl.TRIANGLE_STRIP, props['indicesStart'], props['indicesCount']);
`;
var watcherTemplate = (name, jsType, ctxMethod) => `
watch(()=>props.${name},(newVal)=>{
if(!gl||!glProgram)
return;
let ${name} = gl.getUniformLocation(glProgram,'${name}');
gl.${ctxMethod}(${name}, ${jsType}(newVal));
gl.drawArrays(gl.TRIANGLE_STRIP, props['indicesStart'], props['indicesCount']);
},
{
immediate: true
})
`;
var sampler2DTemplate = (name) => `
watch(()=> props.${name},(newVal)=>{
var image = new Image();
image.src = newVal;
image.onload = () => {
if(!gl||!glProgram)
return;
let ${name} = gl.getUniformLocation(glProgram,'${name}');
var texture = gl.createTexture();
//1.对纹理图像进行Y轴反转
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
//2.开启0号纹理单元
gl.activeTexture(gl.TEXTURE0);
//3.向target绑定纹理对象
gl.bindTexture(gl.TEXTURE_2D, texture);
//4.配置纹理参数
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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);
//5.配置纹理图像
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
//6.将0号纹理图像传递给着色器
gl.uniform1i(${name}, 0);
gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, props['indicesStart'], props['indicesCount']);
}
},{
immediate: true,
})
`;
function* getUniforms(code) {
var uniformPattern = /uniform ([a-z1-9A-Z]+) ([_a-zA-Z0-9]+)/g;
var uniform;
while ((uniform = uniformPattern.exec(code))) {
yield uniform;
}
}
var watchersCode = "";
var propertiesCode = "";
var uniformInit = "";
for (let uniform of getUniforms(vertexShaderSource)) {
watchersCode += watcherTemplate(
uniform[2],
typeMapping[uniform[1]].jsType,
typeMapping[uniform[1]].ctxMethod
);
propertiesCode += ` ${uniform[2]} : {},\n`;
uniformInit += uniformInitTemplate(
uniform[2],
typeMapping[uniform[1]].jsType,
typeMapping[uniform[1]].ctxMethod
);
}
for (let uniform of getUniforms(fragmentShaderSource)) {
if (uniform[1] === "sampler2D") {
watchersCode += sampler2DTemplate(
uniform[2],
typeMapping[uniform[1]].jsType,
typeMapping[uniform[1]].ctxMethod
);
propertiesCode += ` ${uniform[2]} : {},\n`;
continue;
}
watchersCode += watcherTemplate(
uniform[2],
typeMapping[uniform[1]].jsType,
typeMapping[uniform[1]].ctxMethod
);
propertiesCode += ` ${uniform[2]} : {},\n`;
uniformInit += uniformInitTemplate(
uniform[2],
typeMapping[uniform[1]].jsType,
typeMapping[uniform[1]].ctxMethod
);
}
return {
code: t(
vertexShaderSource,
fragmentShaderSource,
watchersCode,
propertiesCode,
uniformInit
),
map,
};
}
const fileRegex = /\.frag$/;
function webglLoader() {
return {
name: "element3-webgl",
transform(rawCode, id) {
if (fileRegex.test(id)) {
const { code } = compileFileToComponent(rawCode, null);
return { code };
} else {
return rawCode;
}
},
};
}
export default webglLoader;