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

相關文章
相關標籤/搜索