diff --git a/.gitignore b/.gitignore index 6521db3..4d24604 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ _site .sass-cache .jekyll-cache .jekyll-metadata +.jampack/ .obsidian/ Gemfile.lock vendor diff --git a/_posts/2023-11-9-this-site.md b/_posts/2023-11-9-this-site.md index d5d885a..c6786a3 100644 --- a/_posts/2023-11-9-this-site.md +++ b/_posts/2023-11-9-this-site.md @@ -9,4 +9,12 @@ excerpt: | The site is build by a github action based on the [jekyll recommendation](https://jekyllrb.com/docs/continuous-integration/github-actions/). I did this because I wanted to be able to use `npm install` like all the cool kids which lead to adding [jekyll-node-module](https://github.com/mintbit/jekyll-node-module#jekyll-node-module) to the site to be able to copy things in from `node_packages` without committing it all to the repo. -The 3D outline rendered images on the [projects pages](/projects) are done with code from [Omaha Shehata](https://omar-shehata.medium.com/better-outline-rendering-using-surface-ids-with-webgl-e13cdab1fd94). \ No newline at end of file +The 3D outline rendered images on the [projects pages](/projects) are done with code from [Omaha Shehata](https://omar-shehata.medium.com/better-outline-rendering-using-surface-ids-with-webgl-e13cdab1fd94). + +## Future +There are a few plugins I'm thinking of adding: +- [jekyll-auto-image](https://github.com/merlos/jekyll-auto-image) to simply choosing a representative image for a particular post. +- I'd like to write a jekyll plugin for [D2](https://github.com/terrastruct/d2) diagrams. It doesn't [look too difficult](https://jekyllrb.com/docs/plugins/tags/). +- I'm wondering if I should switch the rendering to use pandoc, I used pandoc in the past to convert my thesis to multiple output formats and I suspect it is now a more active project than jekyll itself, for example someone has already written a D2 pandoc filter. + +There's a good list of jekyll plugins [here](https://github.com/planetjekyll/awesome-jekyll-plugins). \ No newline at end of file diff --git a/_posts/2024-03-04-book-shelf.md b/_posts/2024-03-04-book-shelf.md index ed16a84..fd348eb 100644 --- a/_posts/2024-03-04-book-shelf.md +++ b/_posts/2024-03-04-book-shelf.md @@ -10,6 +10,7 @@ assets: /assets/blog/bookshelf/ alt: head: --- + Here's a little weekend project. We have this mezzanine bed with windows and window shelves around it. I'd like to put books there but sometimes condensation pools so I need something to raise the books a little above the level of the shelf.
diff --git a/_posts/2024-05-17-threejs-earth.md b/_posts/2024-05-17-threejs-earth.md new file mode 100644 index 0000000..9e48c7a --- /dev/null +++ b/_posts/2024-05-17-threejs-earth.md @@ -0,0 +1,26 @@ +--- +title: ThreeJS Earth +layout: post +excerpt: A small earth renderer made using ThreeJS + +image: +thumbnail: +assets: +alt: + +head: | + + + +--- +A small earth renderer made using ThreeJS. + \ No newline at end of file diff --git a/assets/blog/sphere_geodesics/earthbump10k.jpg b/assets/blog/sphere_geodesics/earthbump10k.jpg new file mode 100644 index 0000000..db38269 Binary files /dev/null and b/assets/blog/sphere_geodesics/earthbump10k.jpg differ diff --git a/assets/blog/sphere_geodesics/earthbump1k.jpg b/assets/blog/sphere_geodesics/earthbump1k.jpg new file mode 100644 index 0000000..7b1a989 Binary files /dev/null and b/assets/blog/sphere_geodesics/earthbump1k.jpg differ diff --git a/assets/blog/sphere_geodesics/earthcloudmap.jpg b/assets/blog/sphere_geodesics/earthcloudmap.jpg new file mode 100644 index 0000000..db94d15 Binary files /dev/null and b/assets/blog/sphere_geodesics/earthcloudmap.jpg differ diff --git a/assets/blog/sphere_geodesics/earthcloudmaptrans.jpg b/assets/blog/sphere_geodesics/earthcloudmaptrans.jpg new file mode 100644 index 0000000..575ba82 Binary files /dev/null and b/assets/blog/sphere_geodesics/earthcloudmaptrans.jpg differ diff --git a/assets/blog/sphere_geodesics/earthlights10k.jpg b/assets/blog/sphere_geodesics/earthlights10k.jpg new file mode 100644 index 0000000..b503993 Binary files /dev/null and b/assets/blog/sphere_geodesics/earthlights10k.jpg differ diff --git a/assets/blog/sphere_geodesics/earthlights1k.jpg b/assets/blog/sphere_geodesics/earthlights1k.jpg new file mode 100644 index 0000000..ff77ffd Binary files /dev/null and b/assets/blog/sphere_geodesics/earthlights1k.jpg differ diff --git a/assets/blog/sphere_geodesics/earthmap10k.jpg b/assets/blog/sphere_geodesics/earthmap10k.jpg new file mode 100644 index 0000000..812458c Binary files /dev/null and b/assets/blog/sphere_geodesics/earthmap10k.jpg differ diff --git a/assets/blog/sphere_geodesics/earthmap1k.jpg b/assets/blog/sphere_geodesics/earthmap1k.jpg new file mode 100644 index 0000000..7dcab8a Binary files /dev/null and b/assets/blog/sphere_geodesics/earthmap1k.jpg differ diff --git a/assets/blog/sphere_geodesics/earthspec10k.jpg b/assets/blog/sphere_geodesics/earthspec10k.jpg new file mode 100644 index 0000000..c2eea0e Binary files /dev/null and b/assets/blog/sphere_geodesics/earthspec10k.jpg differ diff --git a/assets/blog/sphere_geodesics/earthspec1k.jpg b/assets/blog/sphere_geodesics/earthspec1k.jpg new file mode 100644 index 0000000..1d71646 Binary files /dev/null and b/assets/blog/sphere_geodesics/earthspec1k.jpg differ diff --git a/assets/blog/sphere_geodesics/index.js b/assets/blog/sphere_geodesics/index.js new file mode 100644 index 0000000..836c9db --- /dev/null +++ b/assets/blog/sphere_geodesics/index.js @@ -0,0 +1,254 @@ +import * as THREE from 'three'; + +import GUI from 'lil-gui' + +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; +import { TransformControls } from 'three/addons/controls/TransformControls.js'; +import Stats from "three/examples/libs/stats.module.js"; +// node_modules/three/examples/jsm/libs/stats.module.js + +// previously this feature is .legacyMode = false, see https://www.donmccurdy.com/2020/06/17/color-management-in-threejs/ +// turning this on has the benefit of doing certain automatic conversions (for hexadecimal and CSS colors from sRGB to linear-sRGB) +THREE.ColorManagement.enabled = true + +class SphereViewer extends HTMLElement { + constructor() { + super(); + + let component_rect = this.getBoundingClientRect(); + console.log("component_rect", component_rect); + + this.shadow = this.attachShadow({ mode: "open" }); + this.render(component_rect.height); + + const container = this.shadow.querySelector("div#container"); + const canvas = this.shadow.querySelector("canvas"); + + let canvas_rect = canvas.getBoundingClientRect(); + + // determine the outline and bg colors + const body = document.getElementsByTagName("body")[0]; + const style = window.getComputedStyle(body); + const outline_color = style.getPropertyValue("--theme-model-line-color"); + const model_color = style.getPropertyValue("--theme-model-bg-color"); + + // // Init scene + const scene = new THREE.Scene(); + scene.background = new THREE.Color( model_color); + + const camera = new THREE.PerspectiveCamera( 70, canvas_rect.width / canvas_rect.height, 0.01, 1000 ); + camera.position.set( 0, 200, 200 ); + camera.lookAt(0,0,0); + scene.add( camera ); + + scene.add( new THREE.AmbientLight( 0xf0f0f0, 3 ) ); + const light = new THREE.SpotLight( 0xffffff, 4.5 ); + light.position.set( 0, 1500, 200 ); + light.angle = Math.PI * 0.2; + light.decay = 0; + light.castShadow = true; + light.shadow.camera.near = 200; + light.shadow.camera.far = 2000; + light.shadow.bias = - 0.000222; + light.shadow.mapSize.width = 1024; + light.shadow.mapSize.height = 1024; + scene.add( light ); + + // Texture loading + const loader = new THREE.TextureLoader(); + + function load_texture(url) { + const texture = loader.load(url); + texture.colorSpace = THREE.SRGBColorSpace; + texture.minFilter = THREE.LinearMipmapLinearFilter; + return texture; + } + + // Sphere + const geometry = new THREE.SphereGeometry( 100, 1000, 1000 ); + const earth_materials = { + earth1k: new THREE.MeshPhongMaterial({ + color: 0xffffff, + map: load_texture("/assets/blog/sphere_geodesics/earthmap1k.jpg"), + bumpMap: load_texture("/assets/blog/sphere_geodesics/earthbump1k.jpg"), + displacementMap: load_texture("/assets/blog/sphere_geodesics/earthbump1k.jpg"), + emissiveMap: load_texture("/assets/blog/sphere_geodesics/earthlights1k.jpg"), + specularMap: load_texture("/assets/blog/sphere_geodesics/earthspec1k.jpg"), + emissive: 0xffffff, + }), + earth10k: new THREE.MeshPhongMaterial({ + color: 0xffffff, + map: load_texture("/assets/blog/sphere_geodesics/earthmap10k.jpg"), + bumpMap: load_texture("/assets/blog/sphere_geodesics/earthbump10k.jpg"), + displacementMap: load_texture("/assets/blog/sphere_geodesics/earthbump10k.jpg"), + emissiveMap: load_texture("/assets/blog/sphere_geodesics/earthlights10k.jpg"), + specularMap: load_texture("/assets/blog/sphere_geodesics/earthspec10k.jpg"), + emissive: 0xffffff, + }), + checkerboard: new THREE.MeshBasicMaterial({ + onBeforeCompile: shader => { + shader.fragmentShader = `${shader.fragmentShader}` + .replace( + `vec4 diffuseColor = vec4( diffuse, opacity );`, + ` + float chCount = 15.; + float checker = (1. / chCount); + float actualCheckers = 1. - checker; + float halfChecker = checker * 0.5; + vec2 bUv = (vUv * actualCheckers) - halfChecker; + vec2 cUv = fract((bUv) * (chCount * 0.5)) - 0.5; + float checkerVal = clamp(step(cUv.x * cUv.y, 0.), 0.5, 1.); + vec3 col = vec3(checkerVal); + vec4 diffuseColor = vec4( col, opacity ); + ` + );}, + opacity: 0.9, + transparent: true, + side: THREE.DoubleSide, + }) + }; + + earth_materials["checkerboard"].defines = {"USE_UV":""}; + + const sphere = new THREE.Mesh(geometry, earth_materials["earth1k"]); + scene.add( sphere ); + + + // const planeGeometry = new THREE.PlaneGeometry( 2000, 2000 ); + // planeGeometry.rotateX( - Math.PI / 2 ); + // const planeMaterial = new THREE.ShadowMaterial( { color: 0x000000, opacity: 0.2 } ); + + // const plane = new THREE.Mesh( planeGeometry, planeMaterial ); + // plane.position.y = - 200; + // plane.receiveShadow = true; + // scene.add( plane ); + + // const helper = new THREE.GridHelper( 2000, 100 ); + // helper.position.y = - 199; + // helper.material.opacity = 0.25; + // helper.material.transparent = true; + // scene.add( helper ); + + const renderer = new THREE.WebGLRenderer( {canvas: canvas, antialias: true}, + (_renderer) => { + // best practice: ensure output colorspace is in sRGB, see Color Management documentation: + // https://threejs.org/docs/#manual/en/introduction/Color-management + _renderer.outputColorSpace = THREE.SRGBColorSpace + }) + renderer.setPixelRatio( window.devicePixelRatio ); + renderer.setSize(canvas_rect.width, canvas_rect.height, false); + renderer.shadowMap.enabled = true; + + // Controls + const controls = new OrbitControls(camera, canvas); + controls.damping = 0.2; + controls.autoRotate = true; + controls.autoRotateSpeed = 2; + controls.target.set(0, 0, 0); + + // If not using render loop, render on changes + // controls.addEventListener( 'change', render); + // window.addEventListener('resize', render); + + renderer.render(scene, camera); + + // Render single frame + function render() { + renderer.render(scene, camera); + } + + // Render loop + function loop() { + requestAnimationFrame(loop); + controls.update(); + renderer.render(scene, camera); + } + loop(); + + const gui = new GUI({ + title: "Settings", + container: container, + injectStyles: false, + closeFolders: true, + }); + const params = { + Material: "earth1k", + rotate: true, + emissiveIntensity: 0, + emissiveColor: 0xffcd75, + specularColor: 0xfbf9c1, + displacementScale: 1, + bumpScale: 1, + } + gui.add(params, "Material", earth_materials) + .onChange(material => {sphere.material = material}); + + gui.add(params, 'rotate') + .onChange(value => {controls.autoRotate = value}); + + gui.add(params, 'emissiveIntensity', 0, 10) + .onChange(value => {sphere.material.emissiveIntensity = value}); + + gui.add(params, 'displacementScale', 0, 10) + .onChange(value => {sphere.material.displacementScale = value}); + + gui.add(params, 'bumpScale', 0, 10) + .onChange(value => {sphere.material.bumpScale = value}); + + gui.addColor(params, 'emissiveColor') + .onChange(color => {sphere.material.emissive = new THREE.Color(color)}); + + gui.addColor(params, 'specularColor') + .onChange(color => {sphere.material.specular = new THREE.Color(color)}); + + + } + + render(height) { + this.shadow.innerHTML = ` +
+ +
+ + + `; + } +} + +customElements.define("sphere-viewer", SphereViewer); \ No newline at end of file