├── src ├── react-app-env.d.ts ├── state.tsx ├── Logo.tsx ├── index.tsx ├── index.css ├── Sun.tsx ├── App.tsx ├── PostProcessing.tsx ├── Scene.tsx ├── Planet.tsx └── vfx │ ├── Nebula.tsx │ └── AsteroidBelt.tsx ├── public ├── favicon.ico ├── logo192.png ├── logo512.png ├── robots.txt ├── textures │ ├── smoke.png │ ├── spark1.png │ ├── lensdirt.jpg │ ├── particle.png │ └── skybox │ │ ├── back.png │ │ ├── left.png │ │ ├── top.png │ │ ├── bottom.png │ │ ├── front.png │ │ └── right.png ├── models │ ├── asteroid03.bin │ ├── ImphenziaPalette01-256-GradientX4.png │ ├── ImphenziaPalette01-256-GradientX4-Emission.png │ └── asteroid03.gltf ├── manifest.json └── index.html ├── vercel.json ├── .editorconfig ├── .gitignore ├── tsconfig.json ├── README.md └── package.json /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/logo512.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/textures/smoke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/textures/smoke.png -------------------------------------------------------------------------------- /public/textures/spark1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/textures/spark1.png -------------------------------------------------------------------------------- /public/models/asteroid03.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/models/asteroid03.bin -------------------------------------------------------------------------------- /public/textures/lensdirt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/textures/lensdirt.jpg -------------------------------------------------------------------------------- /public/textures/particle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/textures/particle.png -------------------------------------------------------------------------------- /public/textures/skybox/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/textures/skybox/back.png -------------------------------------------------------------------------------- /public/textures/skybox/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/textures/skybox/left.png -------------------------------------------------------------------------------- /public/textures/skybox/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/textures/skybox/top.png -------------------------------------------------------------------------------- /public/textures/skybox/bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/textures/skybox/bottom.png -------------------------------------------------------------------------------- /public/textures/skybox/front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/textures/skybox/front.png -------------------------------------------------------------------------------- /public/textures/skybox/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/textures/skybox/right.png -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "rewrites": [{ "source": "/(.*)", "destination": "/" }], 3 | "github": { 4 | "silent": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /public/models/ImphenziaPalette01-256-GradientX4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/models/ImphenziaPalette01-256-GradientX4.png -------------------------------------------------------------------------------- /src/state.tsx: -------------------------------------------------------------------------------- 1 | import { makeStore } from "statery" 2 | import { Mesh } from "three" 3 | 4 | export const store = makeStore({ 5 | sun: null as Mesh | null 6 | }) 7 | -------------------------------------------------------------------------------- /public/models/ImphenziaPalette01-256-GradientX4-Emission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmans/space-scene-sandbox/HEAD/public/models/ImphenziaPalette01-256-GradientX4-Emission.png -------------------------------------------------------------------------------- /src/Logo.tsx: -------------------------------------------------------------------------------- 1 | export const Logo = () => ( 2 | 7 | ) 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | tab_width = 2 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App"; 4 | import "./index.css"; 5 | 6 | const root = ReactDOM.createRoot( 7 | document.getElementById("root") as HTMLElement 8 | ); 9 | root.render( 10 | 11 | 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100vh; 4 | width: 100vw; 5 | margin: 0; 6 | padding: 0; 7 | overflow: hidden; 8 | } 9 | 10 | body { 11 | background-color: #000; 12 | } 13 | 14 | div#root { 15 | height: 100%; 16 | width: 100%; 17 | overflow: hidden; 18 | } 19 | 20 | div#logo { 21 | position: fixed; 22 | bottom: 30px; 23 | left: 30px; 24 | color: white; 25 | font: 50px/1 sans-serif; 26 | text-shadow: 4px 2px 3px rgba(0, 0, 0, 0.8); 27 | z-index: 1; 28 | } 29 | 30 | a { 31 | color: inherit; 32 | font: inherit; 33 | text-decoration: none; 34 | } 35 | -------------------------------------------------------------------------------- /src/Sun.tsx: -------------------------------------------------------------------------------- 1 | import { MeshProps } from "@react-three/fiber" 2 | import { bitmask, Layers } from "render-composer" 3 | import { Color } from "three" 4 | import { store } from "./state" 5 | 6 | export const Sun = (props: MeshProps) => { 7 | return ( 8 | store.set({ sun })} {...props}> 9 | 13 | 14 | 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { Loader } from "@react-three/drei" 2 | import { Suspense } from "react" 3 | import * as RC from "render-composer" 4 | import { Logo } from "./Logo" 5 | import { PostProcessing } from "./PostProcessing" 6 | import { Scene } from "./Scene" 7 | 8 | export default function App() { 9 | return ( 10 | <> 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/PostProcessing.tsx: -------------------------------------------------------------------------------- 1 | import { useTexture } from "@react-three/drei" 2 | import { useControls } from "leva" 3 | import * as RC from "render-composer" 4 | import { useStore } from "statery" 5 | import { store } from "./state" 6 | 7 | export const PostProcessing = () => { 8 | const { sun } = useStore(store) 9 | const texture = useTexture("/textures/lensdirt.jpg") 10 | 11 | const controls = useControls("Post Processing", { 12 | smaa: true, 13 | bloom: true, 14 | godRays: true, 15 | lensDirt: true 16 | }) 17 | 18 | return ( 19 | 20 | {controls.smaa && } 21 | {controls.bloom && ( 22 | 27 | )} 28 | {controls.godRays && sun && } 29 | {controls.lensDirt && } 30 | 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /src/Scene.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Environment, 3 | OrbitControls, 4 | PerspectiveCamera 5 | } from "@react-three/drei" 6 | import { bitmask, Layers } from "render-composer" 7 | import { Planet } from "./Planet" 8 | import { Sun } from "./Sun" 9 | 10 | export const Scene = () => { 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {/* Environment */} 20 | 31 | 32 | {/* Lights */} 33 | 37 | 38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /src/Planet.tsx: -------------------------------------------------------------------------------- 1 | import { GroupProps } from "@react-three/fiber" 2 | import { composable, Layer, modules } from "material-composer-r3f" 3 | import { Fresnel, Vec3 } from "shader-composer" 4 | import { Color } from "three" 5 | import { AsteroidBelt } from "./vfx/AsteroidBelt" 6 | import { Nebula } from "./vfx/Nebula" 7 | 8 | export const Planet = (props: GroupProps) => { 9 | return ( 10 | 11 | {/* The actual planet */} 12 | 13 | 14 | 15 | 16 | {/* Base color of the planet */} 17 | 18 | 19 | {/* Fresnel effect */} 20 | 21 | 22 | 23 | 24 | 25 | 26 | {/* Some funky clouds! */} 27 | 36 | 37 | {/* The asteroid belt. */} 38 | 39 | 40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SPACE SCENE SANDBOX 2 | 3 | ## Introduction 4 | 5 | This is a small demo scene built with the help of Three.js, React, React-Three-Fiber, and a couple of libraries from my own Open Source project, [The Composer Suite](https://github.com/hmans/composer-suite), a collection of libraries for building games in the browser. 6 | 7 | Notably, the asteroid rings and the "space fog" around the planet are built with the help of Shader Composer (build shaders with JavaScript), Material Composer (create Three.js materials from shader modules), and VFX Composer (a high-performance particles system engine that uses the other two libraries under the hood.) 8 | 9 | ## Running the demo 10 | 11 | The running demo can be seen here in all its glory: 12 | 13 | - https://space-scene-sandbox.vercel.app/ 14 | 15 | If you want to hack around in the code and instantly see the results, you can launch it in one of the many code sandbox services out there. Please note that these can be a little finicky, with one often working better than the others at any given time. Give it a try: 16 | 17 | - [Open in StackBlitz](https://stackblitz.com/github/hmans/space-scene-sandbox) 18 | - [Open in CodeSandbox](https://codesandbox.io/s/github/hmans/space-scene-sandbox) 19 | - [Open in CodeSandbox Projects](https://codesandbox.io/p/github/hmans/space-scene-sandbox) 20 | 21 | Alternatively, feel free to just clone this repository and run: 22 | 23 | ```sh 24 | npm install 25 | npm start 26 | ``` 27 | 28 | ## Want more? 29 | 30 | Do drop by the [Composer Suite repository](https://github.com/hmans/composer-suite) and my [Twitter account](https://twitter.com/hmans) if you want to stay up to date. Please also consider [a sponsorship](https://github.com/sponsors/hmans); my lovely sponsors help me keep the lights on and the code flowing. 31 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asteroid-ring-sandbox", 3 | "version": "0.1.0", 4 | "private": true, 5 | "prettier": { 6 | "trailingComma": "none", 7 | "tabWidth": 2, 8 | "useTabs": false, 9 | "semi": false, 10 | "singleQuote": false, 11 | "arrowParens": "always" 12 | }, 13 | "dependencies": { 14 | "@react-three/drei": "^9.31.1", 15 | "@react-three/fiber": "^8.7.4", 16 | "@testing-library/jest-dom": "^5.16.5", 17 | "@testing-library/react": "^13.4.0", 18 | "@testing-library/user-event": "^13.5.0", 19 | "@types/jest": "^27.5.2", 20 | "@types/node": "^16.11.59", 21 | "@types/react": "^18.0.20", 22 | "@types/react-dom": "^18.0.6", 23 | "fp-ts": "^2.12.3", 24 | "leva": "^0.9.31", 25 | "material-composer": "^0.2.2", 26 | "material-composer-r3f": "^0.2.3", 27 | "postprocessing": "^6.28.7", 28 | "react": "^18.2.0", 29 | "react-dom": "^18.2.0", 30 | "react-scripts": "5.0.1", 31 | "render-composer": "^0.2.2", 32 | "shader-composer": "^0.4.4", 33 | "shader-composer-r3f": "^0.4.0", 34 | "statery": "^0.6.2", 35 | "three": "^0.144.0", 36 | "typescript": "^4.8.3", 37 | "vfx-composer": "^0.2.4", 38 | "vfx-composer-r3f": "^0.2.4" 39 | }, 40 | "scripts": { 41 | "start": "react-scripts start", 42 | "build": "react-scripts build", 43 | "test": "react-scripts test", 44 | "eject": "react-scripts eject" 45 | }, 46 | "eslintConfig": { 47 | "extends": [ 48 | "react-app", 49 | "react-app/jest" 50 | ] 51 | }, 52 | "browserslist": { 53 | "production": [ 54 | ">0.2%", 55 | "not dead", 56 | "not op_mini all" 57 | ], 58 | "development": [ 59 | "last 1 chrome version", 60 | "last 1 firefox version", 61 | "last 1 safari version" 62 | ] 63 | }, 64 | "devDependencies": { 65 | "@types/three": "^0.144.0" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/vfx/Nebula.tsx: -------------------------------------------------------------------------------- 1 | import { useTexture } from "@react-three/drei" 2 | import { GroupProps } from "@react-three/fiber" 3 | import { pipe } from "fp-ts/function" 4 | import { composable, modules } from "material-composer-r3f" 5 | import { bitmask, Layers, useRenderPipeline } from "render-composer" 6 | import { 7 | Add, 8 | Float, 9 | GlobalTime, 10 | Input, 11 | InstanceID, 12 | Mul, 13 | Rotation3DZ, 14 | ScaleAndOffset, 15 | Sub, 16 | Vec3 17 | } from "shader-composer" 18 | import { useUniformUnit } from "shader-composer-r3f" 19 | import { Random } from "shader-composer-toybox" 20 | import { Color } from "three" 21 | import { Emitter, Particles } from "vfx-composer-r3f" 22 | 23 | export type NebulaProps = { 24 | dimensions?: Input<"vec3"> 25 | amount?: number 26 | rotationSpeed?: Input<"float"> 27 | minSize?: Input<"float"> 28 | maxSize?: Input<"float"> 29 | opacity?: Input<"float"> 30 | color?: Input<"vec3"> 31 | } & GroupProps 32 | 33 | export const Nebula = ({ 34 | amount = 25, 35 | dimensions = Vec3([10, 10, 10]), 36 | rotationSpeed = 0.03, 37 | minSize = 2, 38 | maxSize = 8, 39 | opacity = 0.5, 40 | color = new Color("#ccc"), 41 | ...props 42 | }: NebulaProps) => { 43 | const texture = useTexture("/textures/smoke.png") 44 | 45 | const { depth } = useRenderPipeline() 46 | 47 | const u_depth = useUniformUnit("sampler2D", depth) 48 | 49 | const InstanceRandom = (offset: Input<"float">) => 50 | Random(Add(Mul(Float(InstanceID), 1.23), offset)) 51 | 52 | return ( 53 | 54 | 55 | 56 | 57 | 62 | {/* Apply a random rotation */} 63 | 66 | 67 | {/* Rotate over time */} 68 | ScaleAndOffset(v, 2, -1), 72 | (v) => Mul(v, rotationSpeed), 73 | (v) => Mul(v, GlobalTime), 74 | Rotation3DZ 75 | )} 76 | /> 77 | 78 | 79 | 80 | 87 | 88 | Sub(v, Vec3([0.5, 0.5, 0.5])), 92 | (v) => Mul(v, dimensions) 93 | )} 94 | space="local" 95 | /> 96 | 97 | {/* Color and alpha */} 98 | Mul(c, color)} /> 99 | Mul(a, opacity)} /> 100 | 101 | {/* Soft particles */} 102 | 103 | 104 | 105 | 106 | 107 | 108 | ) 109 | } 110 | -------------------------------------------------------------------------------- /src/vfx/AsteroidBelt.tsx: -------------------------------------------------------------------------------- 1 | import { useGLTF } from "@react-three/drei" 2 | import { GroupProps } from "@react-three/fiber" 3 | import { pipe } from "fp-ts/lib/function" 4 | import { composable, modules } from "material-composer-r3f" 5 | import { 6 | $, 7 | Add, 8 | GlobalTime, 9 | Input, 10 | InstanceID, 11 | Mat3, 12 | Mul, 13 | Pow, 14 | RotateY, 15 | Rotation3D, 16 | ScaleAndOffset, 17 | Vec3 18 | } from "shader-composer" 19 | import { Random } from "shader-composer-toybox" 20 | import { DoubleSide, Material, Mesh } from "three" 21 | import { Emitter, Particles } from "vfx-composer-r3f" 22 | 23 | export const AsteroidBelt = (props: GroupProps) => ( 24 | 25 | 26 | 27 | 28 | ) 29 | 30 | const SmallAsteroids = ({ amount = 10_000 }: { amount?: number }) => { 31 | const random = (offset: Input<"float">) => 32 | Random($`${offset} + float(${InstanceID}) * 1.1005`) 33 | 34 | return ( 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | ) 47 | } 48 | 49 | const LargeAsteroids = ({ amount = 10_000 }: { amount?: number }) => { 50 | /* Load our asteroid model. */ 51 | const gltf = useGLTF("/models/asteroid03.gltf") 52 | const mesh = gltf.scene.children[0] as Mesh 53 | 54 | /* A small helper that will return pseudo-random numbers based off of 55 | the instance ID. */ 56 | const random = (offset: Input<"float">) => 57 | Random($`${offset} + float(${InstanceID}) * 7.3`) 58 | 59 | /* Determine the instance's rotation axis. */ 60 | const rotationAxis = ScaleAndOffset( 61 | Vec3([random(12), random(84), random(1)]), 62 | 2, 63 | -1 64 | ) 65 | 66 | return ( 67 | 68 | {/* We can hook into the material loaded from the GLTF. \o/ */} 69 | 70 | {/* Rotation */} 71 | 75 | 76 | {/* Scale */} 77 | 78 | 79 | {/* Common Belt modules */} 80 | 81 | 82 | 83 | {/* Emit all asteroids all at once. */} 84 | 85 | 86 | ) 87 | } 88 | 89 | type BeltProps = { 90 | width?: Input<"float"> 91 | height?: Input<"float"> 92 | distance?: Input<"float"> 93 | } 94 | 95 | const BeltModules = ({ width = 40, distance = 15, height = 5 }: BeltProps) => { 96 | const random = (offset: Input<"float">) => 97 | Random($`${offset} + float(${InstanceID}) * 1.1005`) 98 | 99 | const offset = Vec3([ 100 | Add(Mul(random(0.2), width), distance), 101 | ScaleAndOffset(random(0.3), height, Mul(height, -0.5)), 102 | 0 103 | ]) 104 | 105 | const speed = ScaleAndOffset(Pow(random(0.25), 3), 0.05, 0.01) 106 | 107 | return ( 108 | RotateY(v, Mul(random(0.4), Math.PI * 2)), 112 | (v) => RotateY(v, Mul(GlobalTime, speed)) 113 | )} 114 | /> 115 | ) 116 | } 117 | 118 | const RotateOverTime = ({ 119 | axis = Vec3([0, 0, 1]), 120 | speed = 1 121 | }: { 122 | axis: Input<"vec3"> 123 | speed?: Input<"float"> 124 | }) => ( 125 | 126 | ) 127 | -------------------------------------------------------------------------------- /public/models/asteroid03.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset" : { 3 | "generator" : "Khronos glTF Blender I/O v1.7.33", 4 | "version" : "2.0" 5 | }, 6 | "scene" : 0, 7 | "scenes" : [ 8 | { 9 | "name" : "Scene", 10 | "nodes" : [ 11 | 0 12 | ] 13 | } 14 | ], 15 | "nodes" : [ 16 | { 17 | "mesh" : 0, 18 | "name" : "Cube" 19 | } 20 | ], 21 | "materials" : [ 22 | { 23 | "doubleSided" : true, 24 | "emissiveFactor" : [ 25 | 1, 26 | 1, 27 | 1 28 | ], 29 | "emissiveTexture" : { 30 | "index" : 0 31 | }, 32 | "name" : "Rock", 33 | "pbrMetallicRoughness" : { 34 | "baseColorTexture" : { 35 | "index" : 1 36 | }, 37 | "metallicFactor" : 0, 38 | "roughnessFactor" : 0.9205992221832275 39 | } 40 | } 41 | ], 42 | "meshes" : [ 43 | { 44 | "name" : "Cube", 45 | "primitives" : [ 46 | { 47 | "attributes" : { 48 | "POSITION" : 0, 49 | "NORMAL" : 1, 50 | "TEXCOORD_0" : 2 51 | }, 52 | "indices" : 3, 53 | "material" : 0 54 | } 55 | ] 56 | } 57 | ], 58 | "textures" : [ 59 | { 60 | "sampler" : 0, 61 | "source" : 0 62 | }, 63 | { 64 | "sampler" : 0, 65 | "source" : 1 66 | } 67 | ], 68 | "images" : [ 69 | { 70 | "mimeType" : "image/png", 71 | "name" : "ImphenziaPalette01-256-GradientX4-Emission", 72 | "uri" : "ImphenziaPalette01-256-GradientX4-Emission.png" 73 | }, 74 | { 75 | "mimeType" : "image/png", 76 | "name" : "ImphenziaPalette01-256-GradientX4", 77 | "uri" : "ImphenziaPalette01-256-GradientX4.png" 78 | } 79 | ], 80 | "accessors" : [ 81 | { 82 | "bufferView" : 0, 83 | "componentType" : 5126, 84 | "count" : 222, 85 | "max" : [ 86 | 1.5393568277359009, 87 | 1.4672664403915405, 88 | 1.903890609741211 89 | ], 90 | "min" : [ 91 | -1.393629550933838, 92 | -1.146217703819275, 93 | -1.6278616189956665 94 | ], 95 | "type" : "VEC3" 96 | }, 97 | { 98 | "bufferView" : 1, 99 | "componentType" : 5126, 100 | "count" : 222, 101 | "type" : "VEC3" 102 | }, 103 | { 104 | "bufferView" : 2, 105 | "componentType" : 5126, 106 | "count" : 222, 107 | "type" : "VEC2" 108 | }, 109 | { 110 | "bufferView" : 3, 111 | "componentType" : 5123, 112 | "count" : 258, 113 | "type" : "SCALAR" 114 | } 115 | ], 116 | "bufferViews" : [ 117 | { 118 | "buffer" : 0, 119 | "byteLength" : 2664, 120 | "byteOffset" : 0 121 | }, 122 | { 123 | "buffer" : 0, 124 | "byteLength" : 2664, 125 | "byteOffset" : 2664 126 | }, 127 | { 128 | "buffer" : 0, 129 | "byteLength" : 1776, 130 | "byteOffset" : 5328 131 | }, 132 | { 133 | "buffer" : 0, 134 | "byteLength" : 516, 135 | "byteOffset" : 7104 136 | } 137 | ], 138 | "samplers" : [ 139 | { 140 | "magFilter" : 9728, 141 | "minFilter" : 9984 142 | } 143 | ], 144 | "buffers" : [ 145 | { 146 | "byteLength" : 7620, 147 | "uri" : "asteroid03.bin" 148 | } 149 | ] 150 | } 151 | --------------------------------------------------------------------------------