乐趣区

关于hexo:在hexo中嵌入threejs运行shader或者threejs的场景

clone 代码后查看运行时成果, 或立刻拜访这里查看成果 https://moshuying.top 仓库链接,点个收费的星星感激不尽。

主题文件默认状况下仿佛不会主动 clone 能够切到主题目录下下载主题,能够自行 clone 主题

最近想在 hexo 中嵌入一些 shader,折腾了一些工夫后终于欠缺,实际上用这种办法不仅能够在 hexo 中嵌入 shader, 也能够嵌入 babylonjs,pxixjs,Layabox,Egret,Cocos2 等,先看成果,原理什么的其实很简略。

因为一些 shader 特地耗费显卡性能,在 glsl_snippets.js 中断定如果第一帧渲染工夫超过 0.4 秒 就不再渲染了。

也能够点击 shader 暂停渲染

嵌入 shader

shader 起源 shaderToy
齐全反对 shadertoy 的代码,参考自大神的代码 stackoverflow,在这位大神的代码里获取到齐全兼容 shaderToy 的思路。并将其改成更实用在 hexo 中。

示例代码

<!-- 至多须要一个 div 来搁置 iframe,这样能够不便的将代码移入文章底部 -->
<div id="three"></div>
<script type="module" id="threeMain">
if (!(self.frameElement && self.frameElement.tagName == "IFRAME")) {import("http://localhost:4000/uploads/createTHREE.js").then((result) => result.initHexoThreeModule(document.getElementById("three"),document.getElementById("threeMain")));
} else {
  // 这里的代码会被间接执行,window 指向 iframe 内的 window(其实就是把代码整个挪动到了 iframe 内)import('http://localhost:4000/uploads/glsl_snippets.js').then(async res=>res.glsl_snippets(res.anotherGlsl))
}
</script>

显示成果

嵌入 threejs3D 场景

个别状况下不倡议在一个页面放多个成果 如有必要,能够通过交互时渲染,在视图内渲染等办法优化,防止页面卡死

倡议 clone 下这个仓库并运行起来,这两个成果都是能够交互的,也能够间接拜访我的小站查看成果 https://moshuying.top

实现原理

起因就是 hexo 对 md 文件中的 script 会渲染到页面上,然而不会显示进去,这就有短缺的操作空间了。

这里应用 iframe 的次要起因就是避免来回切换页面导致的 webgl 上下文问题。不然也不至于这么麻烦。

// 创立 iframe 并返回 iframe 内的 window 对象
function createIframe(divNode) {return new Promise((resolve) => {let iframe = document.createElement("iframe");
    // ...
    iframe.style =
      "position: absolute; width: 100%; height: 100%; left: 0; top: 0;border:none;";
    iframe.onload = () => resolve(iframe.contentWindow);
    divNode.style = "position: relative; width: 100%; height: 0; padding-bottom: 75%;";
    divNode.appendChild(iframe);
  });
}

创立完 iframe 后能够为 iframe 中加载对象了,之前应用的是经典前端的 script src 加载形式,思考到可能会被用到,这里保留了函数不便后续批改。
理论应用中利用 module 中的 import() 函数间接引入在线文件即可

function cdnLoadTHREE(divNode) {return createIframe(divNode).then((iframe_window) => {
    // 创立完 iframe 才有了 iframe 内的 iframe_window 对象
    let link = document.createElement('link')
    link.href = createCss() // 这里对一些款式做了简略批改。link.rel = 'stylesheet'
    link.type = 'text/css'
    iframe_window.document.head.appendChild(link);
    return new Promise((resolve)=>resolve(iframe_window));
  });
}

最初将整个 script 标签复制到 iframe 内,代码会在复制完后立刻执行,因为代码曾经在 iframe 内了,所以 window 也指向了 iframe 中,这一步才使得能够不便的应用 module 保障了向前兼容的同时,也能对老式的代码向下兼容。不至于呈现一些奇奇怪怪的问题。

function initHexoThreeModule(divNode,scriptNode) {let link = document.createElement("link");
  link.href = createCss();
  link.rel = "stylesheet";
  link.type = "text/css";
  document.head.appendChild(link);
  if(divNode && scriptNode){cdnLoadTHREE(divNode).then((iframe_window)=>{let script = document.createElement('script')
      script.src = createBlob(scriptNode.text,'application/javascript')
      iframe_window.document.head.appendChild(script)
    })
  }
}

加载 iframe 到 hexo 中的残缺代码
在 iframe 中加载 shader 的残缺代码

退出移动版