在hexo中嵌入three.js运行shader或者three.js的场景

clone代码后查看运行时效果,或当即访问这里查看效果https://moshuying.top仓库连接,点个免费的星星感激涕零。javascript

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

最近想在hexo中嵌入一些shader,折腾了一些时间后终于完善,实际上用这种方法不只能够在hexo中嵌入shader,也能够嵌入babylonjs,pxixjs,Layabox,Egret,Cocos2等,先看效果,原理什么的其实很简单。css

因为一些shader特别消耗显卡性能,在 glsl_snippets.js中断定若是第一帧渲染时间超过 0.4秒就再也不渲染了。

也能够点击shader暂停渲染html

嵌入shader

shader来源shaderToy
彻底支持shadertoy的代码,参考自大神的代码stackoverflow,在这位大神的代码里获取到彻底兼容shaderToy的思路。并将其改为更适用在hexo中。前端

示例代码java

<!-- 至少须要一个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场景

通常状况下不建议在一个页面放多个效果若有必要,能够经过交互时渲染,在视图内渲染等方法优化,避免页面卡死node

建议clone下这个仓库并运行起来,这两个效果都是能够交互的,也能够直接访问个人小站查看效果https://moshuying.topgit

实现原理

缘由就是hexo对md文件中的script会渲染到页面上,可是不会显示出来,这就有充足的操做空间了。github

这里使用iframe的主要缘由就是防止来回切换页面致使的webgl上下文问题。否则也不至于这么麻烦。web

// 建立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()函数直接引入在线文件便可hexo

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的完整代码

相关文章
相关标签/搜索