UNPKG

rollup-plugin-element3-webgl

Version:
315 lines (279 loc) 8.23 kB
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;