diff --git a/.gitignore b/.gitignore index 14145ab32..0f022a4c9 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,4 @@ yarn-error.log* scripts/pixiVersions.json -.ghtoken \ No newline at end of file +.ghtoken diff --git a/README.md b/README.md index 9fa0b284c..9e7073cf2 100644 --- a/README.md +++ b/README.md @@ -101,4 +101,4 @@ $ npm run switch-snapshot-pixi-version-config where both come with an interactive list of all the snapshots for selection to be actioned on accordingly. -The `update-pixi-version-configs` script is also called pre-build and pre-deploy to update all the outdated labels or metadata on the `pixi-version.json` config on all the docs directories. +The `update-pixi-version-configs` script is also called pre-build and pre-deploy to update all the outdated labels or metadata on the `pixi-version.json` config on all the docs directories. \ No newline at end of file diff --git a/scripts/generate-example-docs.js b/scripts/generate-example-docs.js index 90dc92a3b..ac773d14d 100755 --- a/scripts/generate-example-docs.js +++ b/scripts/generate-example-docs.js @@ -116,15 +116,13 @@ async function go() 'hide_table_of_contents: true', 'hide_edit_this_page: true', `sidebar_position: ${sidebarPosition++}`, - 'hide_title: true', 'custom_edit_url: null', + `title: ${exampleTitle}`, '---', '', 'import Example from \'@site/src/components/Example/index\';', 'import version from \'../../pixi-version.json\';', '', - `# ${exampleTitle}`, - '', ``, '', ].join('\n'); diff --git a/src/examples/v7.0.0/events/nestedBoundaryWithProjection.js b/src/examples/v7.0.0/events/nestedBoundaryWithProjection.js index 430a192ca..7abe4b4d4 100644 --- a/src/examples/v7.0.0/events/nestedBoundaryWithProjection.js +++ b/src/examples/v7.0.0/events/nestedBoundaryWithProjection.js @@ -44,9 +44,6 @@ class Projector extends PIXI.DisplayObject // Then bring global coords into content's world this.worldTransform.applyInverse(to.global, to.global); - // TODO: Remove after https://github.com/pixijs/pixi.js/pull/7381 - // is merged! - to.target = this.boundary.hitTest(to.global.x, to.global.y); }; // Propagate these events down into the content's scene graph! diff --git a/src/examples/v8.0.0/advanced/spinners/index.js b/src/examples/v8.0.0/advanced/spinners/index.js new file mode 100644 index 000000000..a442d2d72 --- /dev/null +++ b/src/examples/v8.0.0/advanced/spinners/index.js @@ -0,0 +1,43 @@ +import { Application, Assets, Container, Sprite, Point, Graphics } from 'pixi.js'; +import { generateSpinner1 } from './spinner1'; +import { generateSpinner2 } from './spinner2'; +import { generateSpinner3 } from './spinner3'; +import { generateSpinner4 } from './spinner4'; +import { generateSpinner5 } from './spinner5'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ antialias: true, background: '#1099bb', resizeTo: window }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + // Load the textures + await Assets.load([ + 'https://pixijs.com/assets/bg_scene_rotate.jpg', + 'https://pixijs.com/assets/bg_rotate.jpg', + 'https://pixijs.com/assets/circle.png', + ]); + + const onTick = [ + generateSpinner1(app, new Point(50, 50)), + generateSpinner2(app, new Point(160, 50)), + generateSpinner3(app, new Point(270, 50)), + generateSpinner4(app, new Point(380, 50)), + generateSpinner5(app, new Point(490, 50)), + ]; + + // Listen for animate update + app.ticker.add((time) => + { + // Call tick handling for each spinner. + onTick.forEach((cb) => + { + cb(time.deltaTime); + }); + }); +})(); diff --git a/src/examples/v8.0.0/advanced/spinners/intersect.js b/src/examples/v8.0.0/advanced/spinners/intersect.js new file mode 100644 index 000000000..e3cceb137 --- /dev/null +++ b/src/examples/v8.0.0/advanced/spinners/intersect.js @@ -0,0 +1,40 @@ +/** + * Helper functions + +line intercept math by Paul Bourke http://paulbourke.net/geometry/pointlineplane/ +Determine the intersection point of two line segments +Return FALSE if the lines don't intersect + +Code modified from original to match pixi examples linting rules. +*/ +export function intersect(x1, y1, x2, y2, x3, y3, x4, y4) +{ + // Check if none of the lines are of length 0 + if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) + { + return false; + } + + const denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); + + // Lines are parallel + if (denominator === 0) + { + return false; + } + + const ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator; + const ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator; + + // is the intersection along the segments + if (ua < 0 || ua > 1 || ub < 0 || ub > 1) + { + return false; + } + + // Return a object with the x and y coordinates of the intersection + const x = x1 + ua * (x2 - x1); + const y = y1 + ua * (y2 - y1); + + return { x, y }; +} diff --git a/src/examples/v8.0.0/advanced/spinners/spinner1.js b/src/examples/v8.0.0/advanced/spinners/spinner1.js new file mode 100644 index 000000000..fa5d16ae3 --- /dev/null +++ b/src/examples/v8.0.0/advanced/spinners/spinner1.js @@ -0,0 +1,99 @@ +import { Container, Graphics, Sprite } from 'pixi.js'; +import { intersect } from './intersect'; + +/* --------------------------------------- +Spinner 1. Square with radial completion. +-------------------------------------- */ +export function generateSpinner1(app, position) +{ + const container = new Container(); + + container.position = position; + app.stage.addChild(container); + + const base = Sprite.from('https://pixijs.com/assets/bg_scene_rotate.jpg'); + const size = 100; + + base.width = size; + base.height = size; + + const bottom = Sprite.from('https://pixijs.com/assets/bg_rotate.jpg'); + + bottom.width = size; + bottom.height = size; + + const mask = new Graphics(); + + mask.position.set(size / 2, size / 2); + base.mask = mask; + window.mask = mask; + + container.addChild(bottom); + container.addChild(base); + container.addChild(mask); + + let phase = 0; + + return (delta) => + { + // Update phase + phase += delta / 60; + phase %= Math.PI * 2; + + // Calculate target point. + const x = Math.cos(phase - Math.PI / 2) * size; + const y = Math.sin(phase - Math.PI / 2) * size; + + const segments = [ + [-size / 2, -size / 2, size / 2, -size / 2], // top segment + [size / 2, -size / 2, size / 2, size / 2], // right + [-size / 2, size / 2, size / 2, size / 2], // bottom + [-size / 2, -size / 2, -size / 2, size / 2], // left + ]; + + // Find the intersecting segment. + let intersection = null; + let winding = 0; + + for (let i = 0; i < segments.length; i++) + { + const segment = segments[i]; + const hit = intersect(0, 0, x, y, segment[0], segment[1], segment[2], segment[3]); + + if (hit) + { + intersection = hit; + if (i === 0) winding = hit.x > 0 ? 0 : 4; + else winding = i; + break; + } + } + + const corners = [ + size / 2, + -size / 2, // Top right + size / 2, + size / 2, // Bottom right + -size / 2, + size / 2, // Bottom left + -size / 2, + -size / 2, // Top left, + 0, + -size / 2, // End point + ]; + + // Redraw mask + mask.clear() + .moveTo(0, -size / 2) + .lineTo(0, 0) + .lineTo(intersection.x, intersection.y); + + // fill the corners + for (let i = winding; i < corners.length / 2; i++) + { + mask.lineTo(corners[i * 2], corners[i * 2 + 1]); + } + + mask.fill({ color: 0xff0000 }); + }; +} diff --git a/src/examples/v8.0.0/advanced/spinners/spinner2.js b/src/examples/v8.0.0/advanced/spinners/spinner2.js new file mode 100644 index 000000000..e94589124 --- /dev/null +++ b/src/examples/v8.0.0/advanced/spinners/spinner2.js @@ -0,0 +1,47 @@ +const { Container, Sprite } = require('pixi.js'); + +/* ----------------------- +Spinner 2. Scaling balls. +---------------------- */ +export function generateSpinner2(app, position) +{ + const container = new Container(); + + container.position = position; + app.stage.addChild(container); + + const size = 100; + const ballAmount = 7; + const balls = []; + + for (let i = 0; i < ballAmount; i++) + { + const ball = Sprite.from('https://pixijs.com/assets/circle.png'); + + ball.anchor.set(0.5); + container.addChild(ball); + ball.position.set( + size / 2 + (Math.cos((i / ballAmount) * Math.PI * 2) * size) / 3, + size / 2 + (Math.sin((i / ballAmount) * Math.PI * 2) * size) / 3, + ); + balls.push(ball); + } + + let phase = 0; + + return (delta) => + { + // Update phase + phase += delta / 60; + phase %= Math.PI * 2; + + // Update ball scales + balls.forEach((b, i) => + { + const sin = Math.sin((i / ballAmount) * Math.PI - phase); + // Multiply sin with itself to get more steeper edge. + + b.scale.set(Math.abs(sin * sin * sin * 0.5) + 0.5); + }); + }; +} diff --git a/src/examples/v8.0.0/advanced/spinners/spinner3.js b/src/examples/v8.0.0/advanced/spinners/spinner3.js new file mode 100644 index 000000000..0184d4a36 --- /dev/null +++ b/src/examples/v8.0.0/advanced/spinners/spinner3.js @@ -0,0 +1,51 @@ +import { Container, Graphics, Sprite } from 'pixi.js'; + +/* --------------------- +Spinner 3. Radial mask. +-------------------- */ +export function generateSpinner3(app, position) +{ + const container = new Container(); + + container.position = position; + app.stage.addChild(container); + + const base = Sprite.from('https://pixijs.com/assets/bg_scene_rotate.jpg'); + const size = 100; + + base.width = size; + base.height = size; + + const mask = new Graphics(); + + mask.position.set(size / 2, size / 2); + base.mask = mask; + window.mask = mask; + + container.addChild(base); + container.addChild(mask); + + let phase = 0; + + return (delta) => + { + // Update phase + phase += delta / 60; + phase %= Math.PI * 2; + + const angleStart = 0 - Math.PI / 2; + const angle = phase + angleStart; + const radius = 50; + + const x1 = Math.cos(angleStart) * radius; + const y1 = Math.sin(angleStart) * radius; + + // Redraw mask + mask.clear() + .moveTo(0, 0) + .lineTo(x1, y1) + .arc(0, 0, radius, angleStart, angle, false) + .lineTo(0, 0) + .fill({ color: 0xff0000 }); + }; +} diff --git a/src/examples/v8.0.0/advanced/spinners/spinner4.js b/src/examples/v8.0.0/advanced/spinners/spinner4.js new file mode 100644 index 000000000..5b459b9f5 --- /dev/null +++ b/src/examples/v8.0.0/advanced/spinners/spinner4.js @@ -0,0 +1,119 @@ +import { Container, Graphics, Sprite } from 'pixi.js'; +import { intersect } from './intersect'; + +/* --------------------------------- +Spinner 4. Rounded rectangle edges. +------------------------------- */ +export function generateSpinner4(app, position) +{ + const container = new Container(); + + container.position = position; + app.stage.addChild(container); + + const size = 100; + const arcRadius = 15; + + const base = Sprite.from('https://pixijs.com/assets/bg_scene_rotate.jpg'); + + base.width = size; + base.height = size; + + // For better performance having assets prerounded would be better than masking. + const roundingMask = new Graphics(); + + roundingMask.roundRect(0, 0, size, size, arcRadius).fill({ color: 0x0 }); + base.mask = roundingMask; + + // The edge could be replaced with image as well. + const lineSize = 5; + const edge = new Graphics(); + + edge.roundRect(0, 0, size, size, arcRadius).stroke({ width: lineSize, color: 0xff0000 }); + + // Mask in this example works basically the same way as in example 1. + // Except it is reversed and calculates the mask in straight lines in edges. + const mask = new Graphics(); + + mask.position.set(size / 2, size / 2); + edge.mask = mask; + + container.addChild(base); + container.addChild(roundingMask); + container.addChild(edge); + container.addChild(mask); + + let phase = 0; + + return (delta) => + { + // Update phase + phase += delta / 160; + phase %= Math.PI * 2; + + // Calculate target point. + const x = Math.cos(phase - Math.PI / 2) * size; + const y = Math.sin(phase - Math.PI / 2) * size; + // Line segments + const segments = [ + [-size / 2 + lineSize, -size / 2 + lineSize, size / 2 - lineSize, -size / 2 + lineSize], // top segment + [size / 2 - lineSize, -size / 2 + lineSize, size / 2 - lineSize, size / 2 - lineSize], // right + [-size / 2 + lineSize, size / 2 - lineSize, size / 2 - lineSize, size / 2 - lineSize], // bottom + [-size / 2 + lineSize, -size / 2 + lineSize, -size / 2 + lineSize, size / 2 - lineSize], // left + ]; + // To which dir should mask continue at each segment + let outDir = [ + [0, -1], + [1, 0], + [0, 1], + [-1, 0], + ]; + + // Find the intersecting segment. + let intersection = null; + let winding = 0; + // What direction should the line continue after hit has been found before hitting the line size + + for (let i = 0; i < segments.length; i++) + { + const segment = segments[i]; + const hit = intersect(0, 0, x, y, segment[0], segment[1], segment[2], segment[3]); + + if (hit) + { + intersection = hit; + if (i === 0) winding = hit.x < 0 ? 0 : 4; + else winding = 4 - i; + outDir = outDir[i]; + break; + } + } + + const corners = [ + -size / 2 - lineSize, + -size / 2 - lineSize, // Top left, + -size / 2 - lineSize, + size / 2 + lineSize, // Bottom left + size / 2 + lineSize, + size / 2 + lineSize, // Bottom right + size / 2 + lineSize, + -size / 2 - lineSize, // Top right + ]; + + // Redraw mask + mask.clear() + .moveTo(0, 0) + .moveTo(0, -size / 2 - lineSize); + + // fill the corners + for (let i = 0; i < winding; i++) + { + mask.lineTo(corners[i * 2], corners[i * 2 + 1]); + } + + mask.lineTo(intersection.x + outDir[0] * lineSize * 2, intersection.y + outDir[1] * lineSize * 2) + .lineTo(intersection.x, intersection.y) + .lineTo(0, 0) + .fill({ color: 0xff0000 }); + }; +} diff --git a/src/examples/v8.0.0/advanced/spinners/spinner5.js b/src/examples/v8.0.0/advanced/spinners/spinner5.js new file mode 100644 index 000000000..6e4187218 --- /dev/null +++ b/src/examples/v8.0.0/advanced/spinners/spinner5.js @@ -0,0 +1,34 @@ +import { Container, Graphics } from 'pixi.js'; + +/* --------------------- +Spinner 5. Rounded rectangle fixed length spinner by jonlepage +-------------------- */ +export function generateSpinner5(app, position) +{ + const container = new Container(); + + container.position = position; + app.stage.addChild(container); + + const halfCircle = new Graphics().arc(0, 0, 100, 0, Math.PI).fill({ color: 0xff0000 }); + + halfCircle.position.set(50, 50); + + const rectangle = new Graphics().roundRect(0, 0, 100, 100, 16).stroke({ width: 2, color: 0xffffff }); + + rectangle.mask = halfCircle; + + container.addChild(rectangle); + container.addChild(halfCircle); + + let phase = 0; + + return (delta) => + { + // Update phase + phase += delta / 6; + phase %= Math.PI * 2; + + halfCircle.rotation = phase; + }; +} diff --git a/src/examples/v8.0.0/basic/blendModes.js b/src/examples/v8.0.0/basic/blendModes.js index 3dc03bac5..75932bf30 100644 --- a/src/examples/v8.0.0/basic/blendModes.js +++ b/src/examples/v8.0.0/basic/blendModes.js @@ -1,4 +1,6 @@ -import { Application, Assets, Sprite, Rectangle } from 'pixi.js'; +import 'pixi.js/advanced-blend-modes'; + +import { Application, Assets, Container, Sprite } from 'pixi.js'; (async () => { @@ -6,99 +8,86 @@ import { Application, Assets, Sprite, Rectangle } from 'pixi.js'; const app = new Application(); // Initialize the application - await app.init({ resizeTo: window }); + await app.init({ + antialias: true, + backgroundColor: 'white', + resizeTo: window, + // NEEDS TO BE TRUE FOR WEBGL! + useBackBuffer: true, + }); // Append the application canvas to the document body document.body.appendChild(app.canvas); - // Load the textures - const bgTexture = await Assets.load('https://pixijs.com/assets/bg_rotate.jpg'); - const alienTexture = await Assets.load('https://pixijs.com/assets/flowerTop.png'); - - // Create a new background sprite - const background = new Sprite(bgTexture); - - background.width = app.screen.width; - background.height = app.screen.height; - app.stage.addChild(background); - - // Create an array to store references to the dudes - const dudeArray = []; - - const totaldudes = 20; - - for (let i = 0; i < totaldudes; i++) + const pandaTexture = await Assets.load(`https://pixijs.com/assets/panda.png`); + const rainbowGradient = await Assets.load(`https://pixijs.com/assets/rainbow-gradient.png`); + + const allBlendModes = [ + 'normal', + 'add', + 'screen', + 'darken', + 'lighten', + 'color-dodge', + 'color-burn', + 'linear-burn', + 'linear-dodge', + 'linear-light', + 'hard-light', + 'soft-light', + 'pin-light', + 'difference', + 'exclusion', + 'overlay', + 'saturation', + 'color', + 'luminosity', + 'add-npm', + 'subtract', + 'divide', + 'vivid-light', + 'hard-mix', + 'negation', + ]; + + const size = 800 / 5; + + const pandas = []; + + for (let i = 0; i < allBlendModes.length; i++) { - // Create a new alien Sprite - const dude = new Sprite(alienTexture); - - dude.anchor.set(0.5); - - // Set a random scale for the dude - dude.scale.set(0.8 + Math.random() * 0.3); + const container = new Container(); - // Finally let's set the dude to be at a random position... - dude.x = Math.floor(Math.random() * app.screen.width); - dude.y = Math.floor(Math.random() * app.screen.height); + const sprite = new Sprite({ + texture: pandaTexture, + width: 100, + height: 100, + anchor: 0.5, + position: { x: size / 2, y: size / 2 }, + }); - // The important bit of this example, this is how you change the default blend mode of the sprite - dude.blendMode = 'add'; + pandas.push(sprite); - // Create some extra properties that will control movement - dude.direction = Math.random() * Math.PI * 2; + const sprite2 = new Sprite({ + texture: rainbowGradient, + width: size, + height: size, + blendMode: allBlendModes[i], + }); - // This number will be used to modify the direction of the dude over time - dude.turningSpeed = Math.random() - 0.8; + container.addChild(sprite, sprite2); - // Create a random speed for the dude between 0 - 2 - dude.speed = 2 + Math.random() * 2; + app.stage.addChild(container); - // Finally we push the dude into the dudeArray so it it can be easily accessed later - dudeArray.push(dude); - - app.stage.addChild(dude); + container.x = (i % 5) * size; + container.y = Math.floor(i / 5) * size; } - // Create a bounding box for the little dudes - const dudeBoundsPadding = 100; - - const dudeBounds = new Rectangle( - -dudeBoundsPadding, - -dudeBoundsPadding, - app.screen.width + dudeBoundsPadding * 2, - app.screen.height + dudeBoundsPadding * 2, - ); - app.ticker.add(() => { - // Iterate through the dudes and update the positions - for (let i = 0; i < dudeArray.length; i++) + pandas.forEach((panda, i) => { - const dude = dudeArray[i]; - - dude.direction += dude.turningSpeed * 0.01; - dude.x += Math.sin(dude.direction) * dude.speed; - dude.y += Math.cos(dude.direction) * dude.speed; - dude.rotation = -dude.direction - Math.PI / 2; - - // Constrain the dudes' position by testing their bounds... - if (dude.x < dudeBounds.x) - { - dude.x += dudeBounds.width; - } - else if (dude.x > dudeBounds.x + dudeBounds.width) - { - dude.x -= dudeBounds.width; - } - - if (dude.y < dudeBounds.y) - { - dude.y += dudeBounds.height; - } - else if (dude.y > dudeBounds.y + dudeBounds.height) - { - dude.y -= dudeBounds.height; - } - } + panda.rotation += 0.01 * (i % 2 ? 1 : -1); + }); }); })(); diff --git a/src/examples/v8.0.0/basic/renderGroup.js b/src/examples/v8.0.0/basic/renderGroup.js new file mode 100644 index 000000000..ec09c5fbb --- /dev/null +++ b/src/examples/v8.0.0/basic/renderGroup.js @@ -0,0 +1,66 @@ +import { Application, Assets, Container, Sprite } from 'pixi.js'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ + backgroundColor: 'brown', + resizeTo: window, + }); + + const treeTexture = await Assets.load(`https://pixijs.com/assets/tree.png`); + + const worldContainer = new Container({ + // this will make moving this container GPU powered + isRenderGroup: true, + }); + + const worldSize = 5000; + + for (let i = 0; i < 100000; i++) + { + const yPos = Math.random() * worldSize; + + const tree = new Sprite({ + texture: treeTexture, + x: Math.random() * worldSize, + y: yPos, + scale: 0.25, + anchor: 0.5, + }); + + worldContainer.addChild(tree); + } + + // sort the trees by their y position + worldContainer.children.sort((a, b) => a.position.y - b.position.y); + + app.stage.addChild(worldContainer); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + let x = 0; + let y = 0; + + app.canvas.addEventListener('mousemove', (e) => + { + x = e.clientX; + y = e.clientY; + }); + + app.ticker.add(() => + { + const screenWidth = app.renderer.width; + const screenHeight = app.renderer.height; + + const targetX = (x / screenWidth) * (worldSize - screenWidth); + const targetY = (y / screenHeight) * (worldSize - screenHeight); + + worldContainer.x += (-targetX - worldContainer.x) * 0.1; + worldContainer.y += (-targetY - worldContainer.y) * 0.1; + }); +})(); diff --git a/src/examples/v8.0.0/examplesData.json b/src/examples/v8.0.0/examplesData.json index 0d83ababf..74cfda3b6 100644 --- a/src/examples/v8.0.0/examplesData.json +++ b/src/examples/v8.0.0/examplesData.json @@ -6,7 +6,7 @@ "particleContainer", "blendModes", "meshPlane", - "fillGradient" + "renderGroup" ], "advanced": [ "slots", @@ -35,7 +35,12 @@ "graphics": [ "simple", "advanced", - "dynamic" + "dynamic", + "svg", + "svg-load", + "texture", + "fillGradient", + "meshFromPath" ], "events": [ "click", @@ -48,7 +53,6 @@ "hide": true }, "logger", - "nestedBoundaryWithProjection", "pointerTracker", "slider" ], @@ -65,8 +69,7 @@ ], "filtersAdvanced": [ "mouseBlending", - "custom", - "shaderToyFilterRenderTexture" + "custom" ], "meshAndShaders": [ "texturedMeshBasic", @@ -74,13 +77,11 @@ "triangle", "triangleColor", "triangleTextured", - "uniforms", - "sharingGeometry", + "sharedGeometry", "sharedShader", - "mergingGeometry", "instancedGeometry", "shaderToyMesh", - "multiPassShaderGeneratedMesh" + "multipassMesh" ], "textures": [ "textureRotate", diff --git a/src/examples/v8.0.0/filtersAdvanced/custom/custom.frag b/src/examples/v8.0.0/filtersAdvanced/custom/custom.frag new file mode 100644 index 000000000..e46957457 --- /dev/null +++ b/src/examples/v8.0.0/filtersAdvanced/custom/custom.frag @@ -0,0 +1,19 @@ +in vec2 vTextureCoord; +in vec4 vColor; + +uniform sampler2D uTexture; +uniform float uTime; + +void main(void) +{ + vec2 uvs = vTextureCoord.xy; + + vec4 fg = texture2D(uTexture, vTextureCoord); + + + fg.r = uvs.y + sin(uTime); + + + gl_FragColor = fg; + +} \ No newline at end of file diff --git a/src/examples/v8.0.0/filtersAdvanced/custom/custom.vert b/src/examples/v8.0.0/filtersAdvanced/custom/custom.vert new file mode 100644 index 000000000..d0a43575b --- /dev/null +++ b/src/examples/v8.0.0/filtersAdvanced/custom/custom.vert @@ -0,0 +1,27 @@ +in vec2 aPosition; +out vec2 vTextureCoord; + +uniform vec4 uInputSize; +uniform vec4 uOutputFrame; +uniform vec4 uOutputTexture; + +vec4 filterVertexPosition( void ) +{ + vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy; + + position.x = position.x * (2.0 / uOutputTexture.x) - 1.0; + position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z; + + return vec4(position, 0.0, 1.0); +} + +vec2 filterTextureCoord( void ) +{ + return aPosition * (uOutputFrame.zw * uInputSize.zw); +} + +void main(void) +{ + gl_Position = filterVertexPosition(); + vTextureCoord = filterTextureCoord(); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/filtersAdvanced/custom/index.js b/src/examples/v8.0.0/filtersAdvanced/custom/index.js new file mode 100644 index 000000000..8ec8899e5 --- /dev/null +++ b/src/examples/v8.0.0/filtersAdvanced/custom/index.js @@ -0,0 +1,56 @@ +import { Application, Assets, Sprite, Filter, GlProgram } from 'pixi.js'; +import vertex from './custom.vert'; +import fragment from './custom.frag'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ + resizeTo: window, + hello: true, + preference: 'webgl', + }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + // Load the texture + const texture = await Assets.load('https://pixijs.com/assets/bg_grass.jpg'); + + // Create background image + const background = Sprite.from(texture); + + background.width = app.screen.width; + background.height = app.screen.height; + app.stage.addChild(background); + + // Create the new filter, arguments: (vertexShader, framentSource) + const filter = new Filter({ + glProgram: new GlProgram({ + fragment, + vertex, + }), + resources: { + timeUniforms: { + uTime: { value: 0.0, type: 'f32' }, + }, + }, + }); + + // === WARNING === + // specify uniforms in filter constructor + // or set them BEFORE first use + // filter.uniforms.customUniform = 0.0 + + // Add the filter + background.filters = [filter]; + + // Animate the filter + app.ticker.add((ticker) => + { + filter.resources.timeUniforms.uniforms.uTime += 0.04 * ticker.deltaTime; + }); +})(); diff --git a/src/examples/v8.0.0/filtersAdvanced/mouseBlending/index.js b/src/examples/v8.0.0/filtersAdvanced/mouseBlending/index.js new file mode 100644 index 000000000..41b0dce9e --- /dev/null +++ b/src/examples/v8.0.0/filtersAdvanced/mouseBlending/index.js @@ -0,0 +1,56 @@ +import { Application, Assets, Container, Sprite, Rectangle, Filter, Point, GlProgram } from 'pixi.js'; +import vertex from './mouseBlending.vert'; +import fragment from './mouseBlending.frag'; + +/** + * https://github.com/pixijs/pixi.js/wiki/v5-Creating-Filters + */ + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ preference: 'webgl', resizeTo: window }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + // Load the grass texture + const texture = await Assets.load('https://pixijs.com/assets/bg_grass.jpg'); + + // Create background image + const background = new Sprite(texture); + + background.width = app.screen.width; + background.height = app.screen.height; + app.stage.addChild(background); + + // NOTE: this shader wont work on old devices where mediump precision is forced in fragment shader + // because v5 default vertex shader uses `inputSize` in it. Same uniform in fragment and vertex shader + // cant have different precision :( + + const container = new Container(); + + container.filterArea = new Rectangle(100, 100, app.screen.width - 200, app.screen.height - 200); + app.stage.addChild(container); + + const filter = new Filter({ + glProgram: new GlProgram({ vertex, fragment }), + resources: { + localUniforms: { + uMouse: { value: new Point(), type: 'vec2' }, + }, + }, + }); + + container.filters = [filter]; + + app.stage.hitArea = app.screen; + app.stage.eventMode = 'static'; + app.stage.on('pointermove', (event) => + { + filter.resources.localUniforms.uniforms.uMouse.copyFrom(event.global); + }); +})(); diff --git a/src/examples/v8.0.0/filtersAdvanced/mouseBlending/mouseBlending.frag b/src/examples/v8.0.0/filtersAdvanced/mouseBlending/mouseBlending.frag new file mode 100644 index 000000000..47e1ceeed --- /dev/null +++ b/src/examples/v8.0.0/filtersAdvanced/mouseBlending/mouseBlending.frag @@ -0,0 +1,18 @@ + precision highp float; +in vec2 vTextureCoord; +out vec4 finalColor; + +uniform vec2 uMouse; +uniform vec4 uInputSize; +uniform vec4 uOutputFrame; +uniform float uTime; + +void main() { + vec2 screenPos = vTextureCoord * uInputSize.xy + uOutputFrame.xy; + if (length(uMouse - screenPos) < 25.0) { + finalColor = vec4(1.0, 1.0, 0.0, 1.0) * 0.7; //yellow circle, alpha=0.7 + } else { + // blend with underlying image, alpha=0.5 + finalColor = vec4( sin(uTime), (uMouse.xy - uOutputFrame.xy) / uOutputFrame.zw, 1.0) * 0.5; + } +} \ No newline at end of file diff --git a/src/examples/v8.0.0/filtersAdvanced/mouseBlending/mouseBlending.vert b/src/examples/v8.0.0/filtersAdvanced/mouseBlending/mouseBlending.vert new file mode 100644 index 000000000..d0a43575b --- /dev/null +++ b/src/examples/v8.0.0/filtersAdvanced/mouseBlending/mouseBlending.vert @@ -0,0 +1,27 @@ +in vec2 aPosition; +out vec2 vTextureCoord; + +uniform vec4 uInputSize; +uniform vec4 uOutputFrame; +uniform vec4 uOutputTexture; + +vec4 filterVertexPosition( void ) +{ + vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy; + + position.x = position.x * (2.0 / uOutputTexture.x) - 1.0; + position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z; + + return vec4(position, 0.0, 1.0); +} + +vec2 filterTextureCoord( void ) +{ + return aPosition * (uOutputFrame.zw * uInputSize.zw); +} + +void main(void) +{ + gl_Position = filterVertexPosition(); + vTextureCoord = filterTextureCoord(); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/graphics/fillGradient.js b/src/examples/v8.0.0/graphics/fillGradient.js new file mode 100644 index 000000000..51fa8a58c --- /dev/null +++ b/src/examples/v8.0.0/graphics/fillGradient.js @@ -0,0 +1,56 @@ +import { Application, FillGradient, Graphics } from 'pixi.js'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ background: '#1099bb', resizeTo: window }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + // Create a color array for the linear gradient + const colorStops = [0xffffff, 0xff0000, 0x00ff00, 0x0000ff, 0x000000]; + + // Create a fill gradient + const gradientFill = new FillGradient(0, 0, 150, 150); + + // Add the color stops to the fill gradient + colorStops.forEach((number, index) => + { + const ratio = index / colorStops.length; + + gradientFill.addColorStop(ratio, number); + }); + + // Create a fill graphic + const graphic1 = new Graphics().roundRect(0, 0, 150, 150, 50).fill(gradientFill); + + // Create a stroke graphic + const graphic2 = new Graphics().roundRect(0, 0, 150, 150, 50).stroke({ width: 20, fill: gradientFill }); + + graphic1.pivot.set(75, 75); + graphic1.x = 150; + graphic1.y = 200; + + graphic2.x = 350; + graphic2.y = 125; + + app.stage.addChild(graphic1); + app.stage.addChild(graphic2); + + let tick = 0; + + // Animate the graphics + app.ticker.add(() => + { + tick += 0.025; + graphic1.rotation += 0.01; + graphic2 + .clear() + .roundRect(0, 0, 150, 150, 50) + .stroke({ width: Math.sin(tick) * 100, fill: gradientFill }); + }); +})(); diff --git a/src/examples/v8.0.0/graphics/meshFromPath.js b/src/examples/v8.0.0/graphics/meshFromPath.js new file mode 100644 index 000000000..938245e1b --- /dev/null +++ b/src/examples/v8.0.0/graphics/meshFromPath.js @@ -0,0 +1,56 @@ +import { Application, buildGeometryFromPath, Graphics, GraphicsPath, Mesh, Texture } from 'pixi.js'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ + backgroundColor: 'brown', + resizeTo: window, + antialias: true, + }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + const path = new GraphicsPath() + .rect(-50, -50, 100, 100) + .circle(80, 80, 50) + .circle(80, -80, 50) + .circle(-80, 80, 50) + .circle(-80, -80, 50); + + const geometry = buildGeometryFromPath({ + path, + }); + + const meshes = []; + + for (let i = 0; i < 200; i++) + { + const x = Math.random() * app.screen.width; + const y = Math.random() * app.screen.height; + + const mesh = new Mesh({ + geometry, + texture: Texture.WHITE, + x, + y, + tint: Math.random() * 0xffffff, + }); + + app.stage.addChild(mesh); + + meshes.push(mesh); + } + + app.ticker.add(() => + { + meshes.forEach((mesh) => + { + mesh.rotation += 0.01; + }); + }); +})(); diff --git a/src/examples/v8.0.0/graphics/svg-load.js b/src/examples/v8.0.0/graphics/svg-load.js new file mode 100644 index 000000000..67bd35242 --- /dev/null +++ b/src/examples/v8.0.0/graphics/svg-load.js @@ -0,0 +1,37 @@ +import { Application, Assets, Graphics } from 'pixi.js'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ antialias: true, resizeTo: window }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + const tigerSvg = await Assets.load({ + src: 'https://pixijs.com/assets/tiger.svg', + data: { + parseAsGraphicsContext: true, + }, + }); + + const graphics = new Graphics(tigerSvg); + + // line it up as this svg is not centered + const bounds = graphics.getLocalBounds(); + + graphics.pivot.set((bounds.x + bounds.width) / 2, (bounds.y + bounds.height) / 2); + + graphics.position.set(app.screen.width / 2, app.screen.height / 2); + + app.stage.addChild(graphics); + + app.ticker.add((time) => + { + graphics.rotation += 0.01; + graphics.scale.set(2 + Math.sin(graphics.rotation)); + }); +})(); diff --git a/src/examples/v8.0.0/graphics/svg.js b/src/examples/v8.0.0/graphics/svg.js new file mode 100644 index 000000000..b35053527 --- /dev/null +++ b/src/examples/v8.0.0/graphics/svg.js @@ -0,0 +1,36 @@ +import { Application, Assets, Graphics } from 'pixi.js'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ + antialias: true, + backgroundColor: 'white', + resizeTo: window, + }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + const graphics = new Graphics().svg(` + + + + + + + + + + + + + + + `); + + app.stage.addChild(graphics); +})(); diff --git a/src/examples/v8.0.0/graphics/texture.js b/src/examples/v8.0.0/graphics/texture.js new file mode 100644 index 000000000..cd39b915f --- /dev/null +++ b/src/examples/v8.0.0/graphics/texture.js @@ -0,0 +1,41 @@ +import { Application, Assets, Graphics, GraphicsContext } from 'pixi.js'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ + antialias: true, + backgroundColor: 'white', + resizeTo: window, + }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + const pandaTexture = await Assets.load(`https://pixijs.com/assets/panda.png`); + + const pandasContext = new GraphicsContext() + .circle(0, 0, 120) + .fill('green') + .texture(pandaTexture, 0xffffff, -pandaTexture.width / 2, -pandaTexture.height / 2) + // add a baby purple panda + .translate(100, 100) + .scale(0.4) + .texture(pandaTexture, 'yellow'); + + const graphics = new Graphics(pandasContext); + + const graphics2 = new Graphics(pandasContext); + + app.stage.addChild(graphics, graphics2); + + graphics.x = app.screen.width / 2; + graphics.y = app.screen.height / 2; + + graphics2.x = app.screen.width / 2 - 200; + graphics2.y = app.screen.height / 2 - 200; + graphics2.rotation = 0.5; +})(); diff --git a/src/examples/v8.0.0/index.ts b/src/examples/v8.0.0/index.ts index 9ccb7eb3c..6dd8ef691 100644 --- a/src/examples/v8.0.0/index.ts +++ b/src/examples/v8.0.0/index.ts @@ -3,7 +3,13 @@ import mouseTrail from '!!raw-loader!./advanced/mouseTrail.js'; import scratchCard from '!!raw-loader!./advanced/scratchCard.js'; import screenShot from '!!raw-loader!./advanced/screenShot.js'; import slots from '!!raw-loader!./advanced/slots.js'; -import spinners from '!!raw-loader!./advanced/spinners.js'; +import spinners from '!!raw-loader!./advanced/spinners/index.js'; +import spinnersIntersect from '!!raw-loader!./advanced/spinners/intersect.js'; +import spinnerGenerator1 from '!!raw-loader!./advanced/spinners/spinner1.js'; +import spinnerGenerator2 from '!!raw-loader!./advanced/spinners/spinner2.js'; +import spinnerGenerator3 from '!!raw-loader!./advanced/spinners/spinner3.js'; +import spinnerGenerator4 from '!!raw-loader!./advanced/spinners/spinner4.js'; +import spinnerGenerator5 from '!!raw-loader!./advanced/spinners/spinner5.js'; import starWarp from '!!raw-loader!./advanced/starWarp.js'; import async from '!!raw-loader!./assets/async.js'; @@ -18,7 +24,7 @@ import particleContainer from '!!raw-loader!./basic/particleContainer.js'; import meshPlane from '!!raw-loader!./basic/meshPlane.js'; import tinting from '!!raw-loader!./basic/tinting.js'; import transparentBackground from '!!raw-loader!./basic/transparentBackground.js'; -import fillGradient from '!!raw-loader!./basic/fillGradient.js'; +import renderGroup from '!!raw-loader!./basic/renderGroup.js'; import click from '!!raw-loader!./events/click.js'; import customHitarea from '!!raw-loader!./events/customHitarea.js'; @@ -27,13 +33,15 @@ import dragging from '!!raw-loader!./events/dragging.js'; import hitTestingWithSpatialHash from '!!raw-loader!./events/hitTestingWithSpatialHash.js'; import interactivity from '!!raw-loader!./events/interactivity.js'; import logger from '!!raw-loader!./events/logger.js'; -import nestedBoundaryWithProjection from '!!raw-loader!./events/nestedBoundaryWithProjection.js'; import pointerTracker from '!!raw-loader!./events/pointerTracker.js'; import slider from '!!raw-loader!./events/slider.js'; -import custom from '!!raw-loader!./filtersAdvanced/custom.js'; -import mouseBlending from '!!raw-loader!./filtersAdvanced/mouseBlending.js'; -import shaderToyFilterRenderTexture from '!!raw-loader!./filtersAdvanced/shaderToyFilterRenderTexture.js'; +import custom from '!!raw-loader!./filtersAdvanced/custom/index.js'; +import customVert from '!!raw-loader!./filtersAdvanced/custom/custom.vert'; +import customFrag from '!!raw-loader!./filtersAdvanced/custom/custom.frag'; +import mouseBlending from '!!raw-loader!./filtersAdvanced/mouseBlending/index.js'; +import mouseBlendingVert from '!!raw-loader!./filtersAdvanced/mouseBlending/mouseBlending.vert'; +import mouseBlendingFrag from '!!raw-loader!./filtersAdvanced/mouseBlending/mouseBlending.frag'; import blur from '!!raw-loader!./filtersBasic/blur.js'; import colorMatrix from '!!raw-loader!./filtersBasic/colorMatrix.js'; @@ -43,23 +51,49 @@ import displacementMapFlag from '!!raw-loader!./filtersBasic/displacementMapFlag import advanced from '!!raw-loader!./graphics/advanced.js'; import dynamic from '!!raw-loader!./graphics/dynamic.js'; import simple from '!!raw-loader!./graphics/simple.js'; +import svg from '!!raw-loader!./graphics/svg.js'; +import svgLoad from '!!raw-loader!./graphics/svg-load.js'; +import texture from '!!raw-loader!./graphics/texture.js'; +import fillGradient from '!!raw-loader!./graphics/fillGradient.js'; +import meshFromPath from '!!raw-loader!./graphics/meshFromPath.js'; import filter from '!!raw-loader!./masks/filter.js'; import graphics from '!!raw-loader!./masks/graphics.js'; import sprite from '!!raw-loader!./masks/sprite.js'; -import instancedGeometry from '!!raw-loader!./meshAndShaders/instancedGeometry.js'; -import mergingGeometry from '!!raw-loader!./meshAndShaders/mergingGeometry.js'; -import multiPassShaderGeneratedMesh from '!!raw-loader!./meshAndShaders/multiPassShaderGeneratedMesh.js'; -import shaderToyMesh from '!!raw-loader!./meshAndShaders/shaderToyMesh.js'; -import sharedShader from '!!raw-loader!./meshAndShaders/sharedShader.js'; -import sharingGeometry from '!!raw-loader!./meshAndShaders/sharingGeometry.js'; +import instancedGeometry from '!!raw-loader!./meshAndShaders/instancedGeometry/index.js'; +import instancedGeometryVert from '!!raw-loader!./meshAndShaders/instancedGeometry/instancedGeometry.vert'; +import instancedGeometryFrag from '!!raw-loader!./meshAndShaders/instancedGeometry/instancedGeometry.frag'; +import instancedGeometryWgsl from '!!raw-loader!./meshAndShaders/instancedGeometry/instancedGeometry.wgsl'; +import multipassMesh from '!!raw-loader!./meshAndShaders/multipassMesh/index.js'; +import multipassMeshVert from '!!raw-loader!./meshAndShaders/multipassMesh/multipassMesh.vert'; +import multipassMeshGridFrag from '!!raw-loader!./meshAndShaders/multipassMesh/grid.frag'; +import multipassMeshRippleFrag from '!!raw-loader!./meshAndShaders/multipassMesh/ripple.frag'; +import multipassMeshNoiseFrag from '!!raw-loader!./meshAndShaders/multipassMesh/noise.frag'; +import multipassMeshWaveFrag from '!!raw-loader!./meshAndShaders/multipassMesh/wave.frag'; +import multipassMeshCombineFrag from '!!raw-loader!./meshAndShaders/multipassMesh/combine.frag'; +import shaderToyMesh from '!!raw-loader!./meshAndShaders/shaderToyMesh/index.js'; +import shaderToyMeshVert from '!!raw-loader!./meshAndShaders/shaderToyMesh/shaderToy.vert'; +import shaderToyMeshFrag from '!!raw-loader!./meshAndShaders/shaderToyMesh/shaderToy.frag'; +import sharedShader from '!!raw-loader!./meshAndShaders/sharedShader/index.js'; +import sharedShaderVert from '!!raw-loader!./meshAndShaders/sharedShader/sharedShader.vert'; +import sharedShaderFrag from '!!raw-loader!./meshAndShaders/sharedShader/sharedShader.frag'; +import sharedGeometry from '!!raw-loader!./meshAndShaders/sharedGeometry/index.js'; +import sharedGeometryVert from '!!raw-loader!./meshAndShaders/sharedGeometry/sharedGeometry.vert'; +import sharedGeometryFrag from '!!raw-loader!./meshAndShaders/sharedGeometry/sharedGeometry.frag'; import texturedMeshAdvanced from '!!raw-loader!./meshAndShaders/texturedMeshAdvanced.js'; import texturedMeshBasic from '!!raw-loader!./meshAndShaders/texturedMeshBasic.js'; -import triangleColor from '!!raw-loader!./meshAndShaders/triangleColor.js'; -import triangleTextured from '!!raw-loader!./meshAndShaders/triangleTextured.js'; -import triangle from '!!raw-loader!./meshAndShaders/triangle.js'; -import uniforms from '!!raw-loader!./meshAndShaders/uniforms.js'; +import triangleColor from '!!raw-loader!./meshAndShaders/triangleColor/index.js'; +import triangleColorVert from '!!raw-loader!./meshAndShaders/triangleColor/triangleColor.vert'; +import triangleColorFrag from '!!raw-loader!./meshAndShaders/triangleColor/triangleColor.frag'; +import triangleColorWgsl from '!!raw-loader!./meshAndShaders/triangleColor/triangleColor.wgsl'; +import triangleTextured from '!!raw-loader!./meshAndShaders/triangleTextured/index.js'; +import triangleTexturedVert from '!!raw-loader!./meshAndShaders/triangleTextured/triangleTextured.vert'; +import triangleTexturedFrag from '!!raw-loader!./meshAndShaders/triangleTextured/triangleTextured.frag'; +import triangle from '!!raw-loader!./meshAndShaders/triangle/index.js'; +import triangleVert from '!!raw-loader!./meshAndShaders/triangle/triangle.vert'; +import triangleFrag from '!!raw-loader!./meshAndShaders/triangle/triangle.frag'; +import triangleWgsl from '!!raw-loader!./meshAndShaders/triangle/triangle.wgsl'; import offscreenCanvasBasic from '!!raw-loader!./offscreenCanvas/basic.js'; import webWorker from '!!raw-loader!./offscreenCanvas/webWorker.js'; @@ -96,7 +130,7 @@ const examplesSource: ExamplesSourceType = { meshPlane, tinting, transparentBackground, - fillGradient, + renderGroup, }, sprite: { animatedSpriteAnimationSpeed, @@ -117,6 +151,11 @@ const examplesSource: ExamplesSourceType = { advanced, dynamic, simple, + svg, + svgLoad, + texture, + fillGradient, + meshFromPath, }, events: { click, @@ -126,7 +165,6 @@ const examplesSource: ExamplesSourceType = { hitTestingWithSpatialHash, interactivity, logger, - nestedBoundaryWithProjection, pointerTracker, slider, }, @@ -158,9 +196,16 @@ const examplesSource: ExamplesSourceType = { displacementMapFlag, }, filtersAdvanced: { - custom, - mouseBlending, - shaderToyFilterRenderTexture, + custom: { + index: custom, + 'src/custom.vert': customVert, + 'src/custom.frag': customFrag, + }, + mouseBlending: { + index: mouseBlending, + 'src/mouseBlending.vert': mouseBlendingVert, + 'src/mouseBlending.frag': mouseBlendingFrag, + }, }, advanced: { collisionDetection, @@ -168,22 +213,67 @@ const examplesSource: ExamplesSourceType = { scratchCard, screenShot, slots, - spinners, + spinners: { + index: spinners, + 'src/spinner1.js': spinnerGenerator1, + 'src/spinner2.js': spinnerGenerator2, + 'src/spinner3.js': spinnerGenerator3, + 'src/spinner4.js': spinnerGenerator4, + 'src/spinner5.js': spinnerGenerator5, + 'src/intersect.js': spinnersIntersect, + }, starWarp, }, meshAndShaders: { - instancedGeometry, - mergingGeometry, - multiPassShaderGeneratedMesh, - shaderToyMesh, - sharedShader, - sharingGeometry, + instancedGeometry: { + index: instancedGeometry, + 'src/instancedGeometry.vert': instancedGeometryVert, + 'src/instancedGeometry.frag': instancedGeometryFrag, + 'src/instancedGeometry.wgsl': instancedGeometryWgsl, + }, + multipassMesh: { + index: multipassMesh, + 'src/multipassMesh.vert': multipassMeshVert, + 'src/grid.frag': multipassMeshGridFrag, + 'src/ripple.frag': multipassMeshRippleFrag, + 'src/noise.frag': multipassMeshNoiseFrag, + 'src/wave.frag': multipassMeshWaveFrag, + 'src/combine.frag': multipassMeshCombineFrag, + }, + shaderToyMesh: { + index: shaderToyMesh, + 'src/shaderToy.vert': shaderToyMeshVert, + 'src/shaderToy.frag': shaderToyMeshFrag, + }, + sharedShader: { + index: sharedShader, + 'src/sharedShader.vert': sharedShaderVert, + 'src/sharedShader.frag': sharedShaderFrag, + }, + sharedGeometry: { + index: sharedGeometry, + 'src/sharedGeometry.vert': sharedGeometryVert, + 'src/sharedGeometry.frag': sharedGeometryFrag, + }, texturedMeshAdvanced, texturedMeshBasic, - triangleColor, - triangleTextured, - triangle, - uniforms, + triangleColor: { + index: triangleColor, + 'src/triangleColor.vert': triangleColorVert, + 'src/triangleColor.frag': triangleColorFrag, + 'src/triangleColor.wgsl': triangleColorWgsl, + }, + triangleTextured: { + index: triangleTextured, + 'src/triangleTextured.vert': triangleTexturedVert, + 'src/triangleTextured.frag': triangleTexturedFrag, + }, + triangle: { + index: triangle, + 'src/triangle.vert': triangleVert, + 'src/triangle.frag': triangleFrag, + 'src/triangle.wgsl': triangleWgsl, + }, }, }; diff --git a/src/examples/v8.0.0/meshAndShaders/instancedGeometry/index.js b/src/examples/v8.0.0/meshAndShaders/instancedGeometry/index.js new file mode 100644 index 000000000..0e41a2b04 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/instancedGeometry/index.js @@ -0,0 +1,122 @@ +import { Application, Assets, Buffer, BufferUsage, Geometry, GlProgram, Mesh, Shader } from 'pixi.js'; +import vertex from './instancedGeometry.vert'; +import fragment from './instancedGeometry.frag'; +import source from './instancedGeometry.wgsl'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ + resizeTo: window, + preference: 'webgl', + }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + const spinnyBG = await Assets.load('https://pixijs.com/assets/bg_scene_rotate.jpg'); + + const totalTriangles = 1000; + + // need a buffer big enough to store x, y of totalTriangles + const instancePositionBuffer = new Buffer({ + data: new Float32Array(totalTriangles * 2), + usage: BufferUsage.VERTEX | BufferUsage.COPY_DST, + }); + + const triangles = []; + + for (let i = 0; i < totalTriangles; i++) + { + triangles[i] = { + x: 800 * Math.random(), + y: 600 * Math.random(), + speed: 1 + Math.random() * 2, + }; + } + + const geometry = new Geometry({ + attributes: { + aPosition: [ + -10, + -10, // x, y + 10, + -20, // x, y + 10, + 10, + ], + aUV: [ + 0, + 0, // u, v + 1, + 0, // u, v + 1, + 1, + 0, + 1, + ], + aPositionOffset: { + buffer: instancePositionBuffer, + instance: true, + }, + }, + instanceCount: totalTriangles, + }); + + const gl = { vertex, fragment }; + + const gpu = { + vertex: { + entryPoint: 'mainVert', + source, + }, + fragment: { + entryPoint: 'mainFrag', + source, + }, + }; + + const shader = Shader.from({ + gl, + gpu, + resources: { + uTexture: spinnyBG.source, + uSampler: spinnyBG.source.style, + waveUniforms: { + time: { value: 1, type: 'f32' }, + }, + }, + }); + + const triangleMesh = new Mesh({ + geometry, + shader, + }); + + // triangle.position.set(128 / 2, 128 / 2); + + app.stage.addChild(triangleMesh); + + app.ticker.add(() => + { + const data = instancePositionBuffer.data; + + let count = 0; + + for (let i = 0; i < totalTriangles; i++) + { + const triangle = triangles[i]; + + triangle.x += triangle.speed; + triangle.x %= 800; + + data[count++] = triangle.x; + data[count++] = triangle.y; + } + + instancePositionBuffer.update(); + }); +})(); diff --git a/src/examples/v8.0.0/meshAndShaders/instancedGeometry/instancedGeometry.frag b/src/examples/v8.0.0/meshAndShaders/instancedGeometry/instancedGeometry.frag new file mode 100644 index 000000000..634c1d66c --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/instancedGeometry/instancedGeometry.frag @@ -0,0 +1,7 @@ +in vec2 vUV; +uniform sampler2D uTexture; +uniform float time; + +void main() { + gl_FragColor = texture(uTexture, vUV + sin( (time + (vUV.x) * 14.) ) * 0.1 ); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/instancedGeometry/instancedGeometry.vert b/src/examples/v8.0.0/meshAndShaders/instancedGeometry/instancedGeometry.vert new file mode 100644 index 000000000..d0db6d02f --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/instancedGeometry/instancedGeometry.vert @@ -0,0 +1,18 @@ +in vec2 aPosition; +in vec2 aUV; +in vec2 aPositionOffset; + +out vec2 vUV; + +uniform mat3 uProjectionMatrix; +uniform mat3 uWorldTransformMatrix; +uniform mat3 uTransformMatrix; + + +void main() { + + mat3 mvp = uProjectionMatrix * uWorldTransformMatrix * uTransformMatrix; + gl_Position = vec4((mvp * vec3(aPosition + aPositionOffset, 1.0)).xy, 0.0, 1.0); + + vUV = aUV; +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/instancedGeometry/instancedGeometry.wgsl b/src/examples/v8.0.0/meshAndShaders/instancedGeometry/instancedGeometry.wgsl new file mode 100644 index 000000000..08c3142f2 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/instancedGeometry/instancedGeometry.wgsl @@ -0,0 +1,55 @@ +struct GlobalUniforms { + uProjectionMatrix:mat3x3, + uWorldTransformMatrix:mat3x3, + uWorldColorAlpha: vec4, + uResolution: vec2, +} + +struct LocalUniforms { + uTransformMatrix:mat3x3, + uColor:vec4, + uRound:f32, +} + + +@group(0) @binding(0) var globalUniforms : GlobalUniforms; +@group(1) @binding(0) var localUniforms : LocalUniforms; + +struct VertexOutput { + @builtin(position) position: vec4, + @location(0) vUV: vec2, +}; + + +@vertex +fn mainVert( + @location(0) aPosition : vec2, + @location(1) aUV : vec2, + @location(2) aPositionOffset : vec2, +) -> VertexOutput { + var mvp = globalUniforms.uProjectionMatrix + * globalUniforms.uWorldTransformMatrix + * localUniforms.uTransformMatrix; + + var output: VertexOutput; + + output.position = vec4(mvp * vec3(aPosition+aPositionOffset, 1.0), 1.0); + output.vUV = aUV; + + return output; +}; + +struct WaveUniforms { + time:f32, +} + +@group(2) @binding(1) var uTexture : texture_2d; +@group(2) @binding(2) var uSampler : sampler; +@group(2) @binding(3) var waveUniforms : WaveUniforms; + +@fragment +fn mainFrag( + @location(0) vUV: vec2, +) -> @location(0) vec4 { + return textureSample(uTexture, uSampler, vUV + sin( (waveUniforms.time + (vUV.x) * 14.) ) * 0.1); +}; \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/multipassMesh/combine.frag b/src/examples/v8.0.0/meshAndShaders/multipassMesh/combine.frag new file mode 100644 index 000000000..541f71d5a --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/multipassMesh/combine.frag @@ -0,0 +1,16 @@ +precision mediump float; +varying vec2 vUvs; + +uniform sampler2D texRipple; +uniform sampler2D texNoise; +uniform sampler2D texWave; + +void main() +{ + //Read color from all + vec4 ripple = texture2D(texRipple, vUvs); + vec4 noise = texture2D(texNoise, vUvs); + vec4 wave = texture2D(texWave, vUvs); + + gl_FragColor = mix(ripple, wave,noise.r); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/multipassMesh/grid.frag b/src/examples/v8.0.0/meshAndShaders/multipassMesh/grid.frag new file mode 100644 index 000000000..4cb37b0dc --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/multipassMesh/grid.frag @@ -0,0 +1,16 @@ +precision mediump float; +varying vec2 vUvs; +uniform float zoom; + +void main() +{ + //Generate a simple grid. + //Offset uv so that center is 0,0 and edges are -1,1 + vec2 uv = (vUvs-vec2(0.5))*2.0; + vec2 gUv = floor(uv*zoom); + vec4 color1 = vec4(0.8, 0.8, 0.8, 1.0); + vec4 color2 = vec4(0.4, 0.4, 0.4, 1.0); + vec4 outColor = mod(gUv.x + gUv.y, 2.) < 0.5 ? color1 : color2; + finalColor = outColor; + +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/multipassMesh/index.js b/src/examples/v8.0.0/meshAndShaders/multipassMesh/index.js new file mode 100644 index 000000000..354a6c881 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/multipassMesh/index.js @@ -0,0 +1,181 @@ +import { Application, Assets, Container, Geometry, Mesh, RenderTexture, Shader } from 'pixi.js'; +import vertex from './multipassMesh.vert'; +import gridFragment from './grid.frag'; +import rippleFragment from './ripple.frag'; +import noiseFragment from './noise.frag'; +import waveFragment from './wave.frag'; +import combineFragment from './combine.frag'; + +(async () => +{ + const app = new Application(); + + await app.init({ height: 640, resizeTo: window, preference: 'webgl' }); + + document.body.appendChild(app.view); + + // Build geometry. + const geometry = new Geometry({ + attributes: { + aPosition: [ + 0, + 0, // x, y + 200, + 0, // x, y + 200, + 200, // x, y, + 0, + 200, // x, y, + ], + aUV: [0, 0, 1, 0, 1, 1, 0, 1], + }, + indexBuffer: [0, 1, 2, 0, 2, 3], + }); + + // Load a perlinnoise texture for one of the shaders. + const perlinTexture = await Assets.load('https://pixijs.com/assets/perlin.jpg'); + + const gridShader = Shader.from({ + gl: { + // Vertex shader. Use same shader for all passes. + vertex, + // First pass, generates a grid. + fragment: gridFragment, + }, + resources: { + gridUniforms: { + zoom: { type: 'f32', value: 10 }, + }, + }, + }); + + // Sharing textures and meshes is possible. + // But for simplicity each pass has its own output texture and mesh in this example. + const gridTexture = RenderTexture.create({ width: 200, height: 200 }); + const gridQuad = new Mesh({ geometry, shader: gridShader }); + const gridContainer = new Container(); + + gridContainer.addChild(gridQuad); + + const rippleShader = Shader.from({ + gl: { + vertex, + // Second pass. Takes grid as input and makes it ripple. + fragment: rippleFragment, + }, + resources: { + rippleUniforms: { + amount: { type: 'f32', value: 0.5 }, + phase: { type: 'f32', value: 0 }, + }, + texIn: gridTexture.source, + }, + }); + + const rippleTexture = RenderTexture.create({ width: 200, height: 200 }); + const rippleQuad = new Mesh({ geometry, shader: rippleShader }); + const rippleContainer = new Container(); + + rippleContainer.addChild(rippleQuad); + + const noiseShader = Shader.from({ + gl: { + vertex, + // Second effect. Generates a filtered noise. + fragment: noiseFragment, + }, + resources: { + noiseUniforms: { + limit: { type: 'f32', value: 0.5 }, + }, + noise: perlinTexture.source, + }, + }); + + const noiseTexture = RenderTexture.create({ width: 200, height: 200 }); + const noiseQuad = new Mesh({ geometry, shader: noiseShader }); + const noiseContainer = new Container(); + + noiseContainer.addChild(noiseQuad); + + const waveShader = Shader.from({ + gl: { + vertex, + // Third effect + fragment: waveFragment, + }, + resources: { + waveUniforms: { + amplitude: { type: 'f32', value: 0.75 }, + time: { type: 'f32', value: 0 }, + }, + }, + }); + + const waveTexture = RenderTexture.create({ width: 200, height: 200 }); + const waveQuad = new Mesh(geometry, waveShader); + const waveContainer = new Container(); + + waveContainer.addChild(waveQuad); + + const combineShader = Shader.from({ + gl: { + vertex, + // Final combination pass + fragment: combineFragment, + }, + resources: { + texRipple: rippleTexture.source, + texNoise: noiseTexture.source, + texWave: waveTexture.source, + }, + }); + + const combineQuad = new Mesh(geometry, combineShader); + + gridContainer.position.set(10, 10); + rippleContainer.position.set(220, 10); + noiseContainer.position.set(10, 220); + waveContainer.position.set(10, 430); + combineQuad.position.set(430, 220); + + // Add all phases to stage so all the phases can be seen separately. + app.stage.addChild(gridContainer); + app.stage.addChild(rippleContainer); + app.stage.addChild(noiseContainer); + app.stage.addChild(waveContainer); + app.stage.addChild(combineQuad); + + // start the animation.. + let time = 0; + + app.ticker.add(() => + { + time += 1 / 60; + gridQuad.shader.resources.gridUniforms.uniforms.zoom = Math.sin(time) * 5 + 10; + rippleQuad.shader.resources.rippleUniforms.phase = -time; + waveQuad.shader.resources.waveUniforms.uniforms.time = time; + noiseQuad.shader.resources.noiseUniforms.uniforms.limit = Math.sin(time * 0.5) * 0.35 + 0.5; + + // Render the passes to get textures. + app.renderer.render({ + container: gridQuad, + target: gridTexture, + }); + + app.renderer.render({ + container: rippleQuad, + target: rippleTexture, + }); + + app.renderer.render({ + container: noiseQuad, + target: noiseTexture, + }); + + app.renderer.render({ + container: waveQuad, + target: waveTexture, + }); + }); +})(); diff --git a/src/examples/v8.0.0/meshAndShaders/multipassMesh/multipassMesh.vert b/src/examples/v8.0.0/meshAndShaders/multipassMesh/multipassMesh.vert new file mode 100644 index 000000000..761fd4e8a --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/multipassMesh/multipassMesh.vert @@ -0,0 +1,16 @@ +precision mediump float; + +attribute vec2 aPosition; +attribute vec2 aUV; + +uniform mat3 uProjectionMatrix; +uniform mat3 uWorldTransformMatrix; +uniform mat3 uTransformMatrix; + +varying vec2 vUvs; + +void main() { + vUvs = aUV; + mat3 mvp = uProjectionMatrix * uWorldTransformMatrix * uTransformMatrix; + gl_Position = vec4((mvp * vec3(aPosition, 1.0)).xy, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/multipassMesh/noise.frag b/src/examples/v8.0.0/meshAndShaders/multipassMesh/noise.frag new file mode 100644 index 000000000..46b059e1f --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/multipassMesh/noise.frag @@ -0,0 +1,11 @@ +precision mediump float; +varying vec2 vUvs; +uniform float limit; +uniform sampler2D noise; + +void main() +{ + float color = texture2D(noise, vUvs).r; + color = step(limit, color); + gl_FragColor = vec4(color); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/multipassMesh/ripple.frag b/src/examples/v8.0.0/meshAndShaders/multipassMesh/ripple.frag new file mode 100644 index 000000000..72d1b1842 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/multipassMesh/ripple.frag @@ -0,0 +1,16 @@ +precision mediump float; +varying vec2 vUvs; +uniform float amount; +uniform float phase; +uniform sampler2D texIn; + +void main() +{ + //Generate a simple grid. + vec2 uv = vUvs; + //Calculate distance from center + float distance = length( uv - vec2(0.5)); + vec4 color = texture2D(texIn, uv); + color.rgb *= sin(distance*25.0+phase) * amount+1.; + finalColor = color; +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/multipassMesh/wave.frag b/src/examples/v8.0.0/meshAndShaders/multipassMesh/wave.frag new file mode 100644 index 000000000..3e5814d20 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/multipassMesh/wave.frag @@ -0,0 +1,20 @@ +precision mediump float; +varying vec2 vUvs; +uniform float amplitude; +uniform float time; + +void main() +{ + //Offset uv so that center is 0,0 and edges are -1,1 + vec2 uv = (vUvs-vec2(0.5))*2.0; + + vec3 outColor = vec3(0.); + + //Simple wavefunctions inversed and with small offsets. + outColor += 5./length(uv.y*200. - 50.0*sin( uv.x*0.25+ time*0.25)*amplitude); + outColor += 4./length(uv.y*300. - 100.0*sin(uv.x*0.5+time*0.5)*amplitude*1.2); + outColor += 3./length(uv.y*400. - 150.0*sin(uv.x*0.75+time*0.75)*amplitude*1.4); + outColor += 2./length(uv.y*500. - 200.0*sin(uv.x+time)*amplitude*1.6); + + gl_FragColor = vec4(outColor,1.0); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/shaderToyMesh/index.js b/src/examples/v8.0.0/meshAndShaders/shaderToyMesh/index.js new file mode 100644 index 000000000..1f2b124bf --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/shaderToyMesh/index.js @@ -0,0 +1,65 @@ +import { Application, Geometry, Mesh, Shader } from 'pixi.js'; +import vertex from './shaderToy.vert'; +import fragment from './shaderToy.frag'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ + resizeTo: window, + preference: 'webgl', + }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + const quadGeometry = new Geometry({ + attributes: { + aPosition: [ + -100, + -100, // x, y + 100, + -100, // x, y + 100, + 100, // x, y, + -100, + 100, // x, y, + ], + aUV: [0, 0, 1, 0, 1, 1, 0, 1], + }, + indexBuffer: [0, 1, 2, 0, 2, 3], + }); + + const shader = Shader.from({ + gl: { + vertex, + fragment, + }, + resources: { + shaderToyUniforms: { + iResolution: { value: [640, 360, 1], type: 'vec3' }, + iTime: { value: 0, type: 'f32' }, + }, + }, + }); + + const quad = new Mesh({ + geometry: quadGeometry, + shader, + }); + + quad.width = app.screen.width; + quad.height = app.screen.height; + quad.x = app.screen.width / 2; + quad.y = app.screen.height / 2; + + app.stage.addChild(quad); + + app.ticker.add(() => + { + shader.resources.shaderToyUniforms.uniforms.iTime += app.ticker.elapsedMS / 1000; + }); +})(); diff --git a/src/examples/v8.0.0/meshAndShaders/shaderToyMesh/shaderToy.frag b/src/examples/v8.0.0/meshAndShaders/shaderToyMesh/shaderToy.frag new file mode 100644 index 000000000..a0d382471 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/shaderToyMesh/shaderToy.frag @@ -0,0 +1,312 @@ +// code copied from here https://www.shadertoy.com/view/XcS3zK Created by liamegan +#version 300 es +#define HW_PERFORMANCE 1 +uniform vec3 iResolution; +uniform float iTime; +uniform float iChannelTime[4]; +uniform vec4 iMouse; +uniform vec4 iDate; +uniform float iSampleRate; +uniform vec3 iChannelResolution[4]; +uniform int iFrame; +uniform float iTimeDelta; +uniform float iFrameRate; +uniform sampler2D iChannel0; +uniform struct { +sampler2D sampler; +vec3 size; +float time; +int loaded; +} +iCh0; +uniform sampler2D iChannel1; +uniform struct { +sampler2D sampler; +vec3 size; +float time; +int loaded; +} +iCh1; +uniform sampler2D iChannel2; +uniform struct { +sampler2D sampler; +vec3 size; +float time; +int loaded; +} +iCh2; +uniform sampler2D iChannel3; +uniform struct { +sampler2D sampler; +vec3 size; +float time; +int loaded; +} +iCh3; +void mainImage( out vec4 c, in vec2 f ); +void st_assert( bool cond ); +void st_assert( bool cond, int v ); +out vec4 shadertoy_out_color; +void st_assert( bool cond, int v ) { +if(!cond) { +if(v == 0)shadertoy_out_color.x = -1.0; +else if(v == 1)shadertoy_out_color.y = -1.0; +else if(v == 2)shadertoy_out_color.z = -1.0; +else shadertoy_out_color.w = -1.0; +} + +} +void st_assert( bool cond ) { +if(!cond)shadertoy_out_color.x = -1.0; +} +void main( void ) { +shadertoy_out_color = vec4(1.0, 1.0, 1.0, 1.0); +vec4 color = vec4(1e20); +mainImage( color, gl_FragCoord.xy ); +if(shadertoy_out_color.x<0.0) color = vec4(1.0, 0.0, 0.0, 1.0); +if(shadertoy_out_color.y<0.0) color = vec4(0.0, 1.0, 0.0, 1.0); +if(shadertoy_out_color.z<0.0) color = vec4(0.0, 0.0, 1.0, 1.0); +if(shadertoy_out_color.w<0.0) color = vec4(1.0, 1.0, 0.0, 1.0); +shadertoy_out_color = vec4(color.xyz, 1.0); +} +/* Shading constants */ +/* --------------------- */ +const vec3 LP = vec3(-0.6, 0.7, -0.3); // light position + +const vec3 LC = vec3(.85, 0.80, 0.70); // light colour + +const vec3 HC1 = vec3(.5, .4, .3); // hemisphere light colour 1 + +const vec3 HC2 = vec3(0.1, .1, .6)*.5; // hemisphere light colour 2 + +const vec3 HLD = vec3(0, 1, 0); // hemisphere light direction + +const vec3 BC = vec3(0.25, 0.25, 0.25); // back light colour + +const vec3 FC = vec3(1.30, 1.20, 1.00); // fresnel colour + +const float AS = .5; // ambient light strength + +const float DS = 1.; // diffuse light strength + +const float BS = .3; // back light strength + +const float FS = .3; // fresnel strength + +/* Raymarching constants */ +/* --------------------- */ +const float MAX_TRACE_DISTANCE = 10.; // max trace distance + +const float INTERSECTION_PRECISION = 0.0001; // precision of the intersection + +const int NUM_OF_TRACE_STEPS = 64; // max number of trace steps + +const float STEP_MULTIPLIER = 1.; // the step mutliplier - ie, how much further to progress on each step + + +/* Structures */ +/* ---------- */ +struct Camera { +vec3 ro; +vec3 rd; +vec3 forward; +vec3 right; +vec3 up; +float FOV; +}; +struct Surface { +float len; +vec3 position; +vec3 colour; +float id; +float steps; +float AO; +}; +struct Model { +float dist; +vec3 colour; +float id; +}; +/* Utilities */ +/* ---------- */ +vec2 toScreenspace(in vec2 p) { +vec2 uv = (p - 0.5 * iResolution.xy) / min(iResolution.y, iResolution.x); +return uv; +} +mat2 R(float a) { +float c = cos(a); +float s = sin(a); +return mat2(c, -s, s, c); +} +Camera getCamera(in vec2 uv, in vec3 pos, in vec3 target) { +vec3 f = normalize(target - pos); +vec3 r = normalize(vec3(f.z, 0., -f.x)); +vec3 u = normalize(cross(f, r)); +float FOV = 1.+cos(iTime*.1)*.8; +return Camera( +pos, normalize(f + FOV * uv.x * r + FOV * uv.y * u), f, r, u, FOV +); +} +//-------------------------------- +// Modelling +//-------------------------------- +float G( vec3 p ) { +return dot(sin(p.yzx), cos(p.zxy)); +} +Model model(vec3 p) { +float t = iTime*.1; +p.xz *= R(t); +p.xy *= R(.3); +p.xy -= .5; +float d = abs(-(length(vec2(p.y, length(p.xz)-2.))-1.8+cos(t)*.3)); + +// x variability + +//float gs = 3.+p.x; +//float g = G(p.yxz*gs)/max(4., gs); +// mixing on the y +//float g = mix(g, abs(g)-.4, cos(p.y*2.)); +// regular +float g = G(p.yxz*4.)/4.; +d = length(vec2(d, g))-.3; +vec3 colour = vec3(g); +return Model(d, colour, 1.); +} +Model map( vec3 p ) { +return model(p); +} +/* Modelling utilities */ +/* ---------- */ +// I *think* I borrowed this from Shane, but probably orginally comes from IQ. +// Calculates the normal by taking a very small distance, // remapping the function, and getting normal for that +vec3 calcNormal( in vec3 pos ) { +vec3 eps = vec3( 0.001, 0.0, 0.0 ); +vec3 nor = vec3( +map(pos+eps.xyy).dist - map(pos-eps.xyy).dist, map(pos+eps.yxy).dist - map(pos-eps.yxy).dist, map(pos+eps.yyx).dist - map(pos-eps.yyx).dist ); +return normalize(nor); +} +//-------------------------------- +// Raymarcher +//-------------------------------- +Surface march( in Camera cam ) { +float h = 1e4; // local distance + +float d = 0.; // ray depth + +float id = -1.; // surace id + +float s = 0.; // number of steps + +float ao = 0.; // march space AO. Simple weighted accumulator. Not really AO, but ¯\_(ツ)_/¯ + +vec3 p; // ray position + +vec3 c; // surface colour + + +for( int i = 0; i< NUM_OF_TRACE_STEPS ; i++ ) { +if( abs(h) < INTERSECTION_PRECISION || d > MAX_TRACE_DISTANCE ) break; +p = cam.ro+cam.rd*d; +Model m = map( p ); +h = m.dist; +d += h * STEP_MULTIPLIER; +id = m.id; +s += 1.; +ao += max(h, 0.); +c = m.colour; +} +if( d >= MAX_TRACE_DISTANCE ) id = -1.0; +return Surface( d, p, c, id, s, ao ); +} +//-------------------------------- +// Shading +//-------------------------------- +/* +* Soft shadows and AO curtesy of Inigo Quilez +* https://iquilezles.org/articles/rmshadows +*/ +float softshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax ) { +float res = 1.0; +float t = mint; +for( int i = 0; i<16; i++ ) { +float h = map( ro + rd*t ).dist; +res = min( res, 8.0*h/t ); +t += clamp( h, 0.02, 0.10 ); +if( h<0.001 || t>tmax ) break; +} +return clamp( res, 0.0, 1.0 ); +} +float AO( in vec3 pos, in vec3 nor ) { +float occ = 0.0; +float sca = 1.0; +for( int i = 0; i<5; i++ ) { +float hr = 0.01 + 0.12*float(i)/4.0; +vec3 aopos = nor * hr + pos; +float dd = map( aopos ).dist; +occ += -(dd-hr)*sca; +sca *= 0.95; +} +return clamp( 1.0 - 3.0*occ, 0.0, 1.0 ); +} +vec3 shade(vec3 col, vec3 pos, vec3 nor, vec3 ref, Camera cam) { +vec3 plp = LP - pos; // point light + + +float o = AO( pos, nor ); // Ambient occlusion + +vec3 l = normalize( plp ); // light direction + + +float d = clamp( dot( nor, l ), 0.0, 1.0 )*DS; // diffuse component + +float b = clamp( dot( nor, normalize(vec3(-l.x, 0, -l.z))), 0.0, 1.0 )*clamp( 1.0-pos.y, 0.0, 1.0)*BS; // back light component + +float f = pow( clamp(1.0+dot(nor, cam.rd), 0.0, 1.0), 2.0 )*FS; // fresnel component + + +vec3 c = vec3(0.0); +c += d*LC; // diffuse light integration + +c += mix(HC1, HC2, dot(nor, HLD))*AS; // hemisphere light integration (ambient) + +c += b*BC*o; // back light integration + +c += f*FC*o; // fresnel integration + + +return col*c; +} +vec3 render(Surface surface, Camera cam, vec2 uv) { +vec3 colour = vec3(.04, .045, .05); +colour = vec3(.35, .5, .75); +vec3 colourB = vec3(.9, .85, .8); +colour = mix(colourB, colour, pow(length(uv), 2.)/1.5); +if (surface.id > -1.) { +vec3 surfaceNormal = calcNormal( surface.position ); +vec3 ref = reflect(cam.rd, surfaceNormal); +colour = surfaceNormal; +vec3 pos = surface.position; +float t = iTime; +vec3 col = mix( +mix( +vec3(.8, .3, .6), vec3(.6, .3, .8), dot(surfaceNormal, surfaceNormal.zxy) +), vec3(1), smoothstep(0., .1, cos(surface.colour.r*40.)) +); +colour = shade(col, pos, surfaceNormal, ref, cam); +} +return colour; +} +void mainImage( out vec4 fragColor, in vec2 fragCoord ) { +vec3 c = vec3(0); +for(int x = 0; x<2; x++) { +for(int y = 0; y<2; y++) { +vec2 uv = toScreenspace(fragCoord+vec2(x, y)*.5); +Camera cam = getCamera(uv, vec3(1.5, 0, 1.5), vec3(0)); +Surface surface = march(cam); +c += render(surface, cam, uv); +} + +} +fragColor = vec4(c*.25, 1); +} +#define Kpre86x \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/shaderToyMesh/shaderToy.vert b/src/examples/v8.0.0/meshAndShaders/shaderToyMesh/shaderToy.vert new file mode 100644 index 000000000..f3e7917a5 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/shaderToyMesh/shaderToy.vert @@ -0,0 +1,14 @@ +// code copied from here https://www.shadertoy.com/view/XcS3zK Created by liamegan +#version 300 es +in vec2 aPosition; + +uniform mat3 uProjectionMatrix; +uniform mat3 uWorldTransformMatrix; + +uniform mat3 uTransformMatrix; + +void main() { + + mat3 mvp = uProjectionMatrix * uWorldTransformMatrix * uTransformMatrix; + gl_Position = vec4((mvp * vec3(aPosition, 1.0)).xy, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/sharedGeometry/index.js b/src/examples/v8.0.0/meshAndShaders/sharedGeometry/index.js new file mode 100644 index 000000000..99e3fa5d1 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/sharedGeometry/index.js @@ -0,0 +1,84 @@ +import { Application, Assets, Geometry, GlProgram, Mesh, Shader } from 'pixi.js'; +import vertex from './sharedGeometry.vert'; +import fragment from './sharedGeometry.frag'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ + resizeTo: window, + preference: 'webgl', + }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + const geometry = new Geometry({ + attributes: { + aPosition: [ + -100, + -100, // x, y + 100, + -100, // x, y + 100, + 100, // x, y, + ], + aUV: [0, 0, 1, 0, 1, 1], + }, + }); + + const glProgram = GlProgram.from({ + vertex, + fragment, + }); + + const triangle = new Mesh({ + geometry, + shader: new Shader({ + glProgram, + resources: { + uTexture: (await Assets.load('https://pixijs.com/assets/bg_scene_rotate.jpg')).source, + }, + }), + }); + + const triangle2 = new Mesh({ + geometry, + shader: new Shader({ + glProgram, + resources: { + uTexture: (await Assets.load('https://pixijs.com/assets/bg_rotate.jpg')).source, + }, + }), + }); + + const triangle3 = new Mesh({ + geometry, + shader: new Shader({ + glProgram, + resources: { + uTexture: (await Assets.load('https://pixijs.com/assets/bg_displacement.jpg')).source, + }, + }), + }); + + triangle.position.set(400, 300); + triangle.scale.set(2); + + triangle2.position.set(200, 100); + + triangle3.position.set(500, 400); + triangle3.scale.set(3); + + app.stage.addChild(triangle3, triangle2, triangle); + + app.ticker.add(() => + { + triangle.rotation += 0.01; + triangle2.rotation -= 0.01; + triangle3.rotation -= 0.005; + }); +})(); diff --git a/src/examples/v8.0.0/meshAndShaders/sharedGeometry/sharedGeometry.frag b/src/examples/v8.0.0/meshAndShaders/sharedGeometry/sharedGeometry.frag new file mode 100644 index 000000000..7e8cd6abe --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/sharedGeometry/sharedGeometry.frag @@ -0,0 +1,7 @@ +in vec2 vUV; + +uniform sampler2D uTexture; + +void main() { + gl_FragColor = texture2D(uTexture, vUV); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/sharedGeometry/sharedGeometry.vert b/src/examples/v8.0.0/meshAndShaders/sharedGeometry/sharedGeometry.vert new file mode 100644 index 000000000..70a3f972b --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/sharedGeometry/sharedGeometry.vert @@ -0,0 +1,18 @@ +in vec2 aPosition; +in vec2 aUV; + +out vec2 vUV; + +uniform mat3 uProjectionMatrix; +uniform mat3 uWorldTransformMatrix; + +uniform mat3 uTransformMatrix; + + +void main() { + + mat3 mvp = uProjectionMatrix * uWorldTransformMatrix * uTransformMatrix; + gl_Position = vec4((mvp * vec3(aPosition, 1.0)).xy, 0.0, 1.0); + + vUV = aUV; +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/sharedShader/index.js b/src/examples/v8.0.0/meshAndShaders/sharedShader/index.js new file mode 100644 index 000000000..5d7de835d --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/sharedShader/index.js @@ -0,0 +1,81 @@ +import { Application, Assets, Geometry, Mesh, Shader } from 'pixi.js'; +import vertex from './sharedShader.vert'; +import fragment from './sharedShader.frag'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ + resizeTo: window, + preference: 'webgl', + }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + const quadGeometry = new Geometry({ + attributes: { + aPosition: [ + -100, + -100, // x, y + 100, + -100, // x, y + 100, + 100, // x, y, + -100, + 100, // x, y, + ], + aUV: [0, 0, 1, 0, 1, 1, 0, 1], + }, + indexBuffer: [0, 1, 2, 0, 2, 3], + }); + + const geometry = new Geometry({ + attributes: { + aPosition: [ + -100, + -100, // x, y + 100, + -100, // x, y + 100, + 100, // x, y, + ], + aUV: [0, 0, 1, 0, 1, 1], + }, + }); + + const shader = Shader.from({ + gl: { + vertex, + fragment, + }, + resources: { + uTexture: (await Assets.load('https://pixijs.com/assets/bg_rotate.jpg')).source, + }, + }); + + const quad = new Mesh({ + geometry: quadGeometry, + shader, + }); + + const triangle = new Mesh({ + geometry, + shader, + }); + + quad.position.set(400, 300); + triangle.position.set(400, 300); + triangle.scale.set(2); + + app.stage.addChild(quad, triangle); + + app.ticker.add(() => + { + triangle.rotation += 0.01; + quad.rotation -= 0.01; + }); +})(); diff --git a/src/examples/v8.0.0/meshAndShaders/sharedShader/sharedShader.frag b/src/examples/v8.0.0/meshAndShaders/sharedShader/sharedShader.frag new file mode 100644 index 000000000..0eba55d1a --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/sharedShader/sharedShader.frag @@ -0,0 +1,7 @@ +in vec2 vUV; + +uniform sampler2D uTexture; + +void main() { + gl_FragColor = texture2D(uTexture, vUV).bgra; +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/sharedShader/sharedShader.vert b/src/examples/v8.0.0/meshAndShaders/sharedShader/sharedShader.vert new file mode 100644 index 000000000..70a3f972b --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/sharedShader/sharedShader.vert @@ -0,0 +1,18 @@ +in vec2 aPosition; +in vec2 aUV; + +out vec2 vUV; + +uniform mat3 uProjectionMatrix; +uniform mat3 uWorldTransformMatrix; + +uniform mat3 uTransformMatrix; + + +void main() { + + mat3 mvp = uProjectionMatrix * uWorldTransformMatrix * uTransformMatrix; + gl_Position = vec4((mvp * vec3(aPosition, 1.0)).xy, 0.0, 1.0); + + vUV = aUV; +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/triangle/index.js b/src/examples/v8.0.0/meshAndShaders/triangle/index.js new file mode 100644 index 000000000..31178422c --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/triangle/index.js @@ -0,0 +1,60 @@ +import { Application, Geometry, Mesh, Shader } from 'pixi.js'; +import vertex from './triangle.vert'; +import fragment from './triangle.frag'; +import source from './triangle.wgsl'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ + resizeTo: window, + preference: 'webgl', + }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + const geometry = new Geometry({ + attributes: { + aPosition: [-100, -50, 100, -50, 0, 100], + }, + }); + + // Webgl vertex and fragment shader source + const gl = { vertex, fragment }; + + // WebGPU vertex and fragment shader source + // Here vertex and fragment shader sources are inferred from the same WGSL source + const gpu = { + vertex: { + entryPoint: 'main', + source, + }, + fragment: { + entryPoint: 'main', + source, + }, + }; + + const shader = Shader.from({ + gl, + gpu, + }); + + const triangle = new Mesh({ + geometry, + shader, + }); + + triangle.position.set(400, 300); + + app.stage.addChild(triangle); + + app.ticker.add(() => + { + triangle.rotation += 0.01; + }); +})(); diff --git a/src/examples/v8.0.0/meshAndShaders/triangle/triangle.frag b/src/examples/v8.0.0/meshAndShaders/triangle/triangle.frag new file mode 100644 index 000000000..361b6366e --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/triangle/triangle.frag @@ -0,0 +1,3 @@ +void main() { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/triangle/triangle.vert b/src/examples/v8.0.0/meshAndShaders/triangle/triangle.vert new file mode 100644 index 000000000..7333cd69b --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/triangle/triangle.vert @@ -0,0 +1,13 @@ +in vec2 aPosition; + +uniform mat3 uProjectionMatrix; +uniform mat3 uWorldTransformMatrix; + +uniform mat3 uTransformMatrix; + + +void main() { + + mat3 mvp = uProjectionMatrix * uWorldTransformMatrix * uTransformMatrix; + gl_Position = vec4((mvp * vec3(aPosition, 1.0)).xy, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/triangle/triangle.wgsl b/src/examples/v8.0.0/meshAndShaders/triangle/triangle.wgsl new file mode 100644 index 000000000..6806621be --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/triangle/triangle.wgsl @@ -0,0 +1,30 @@ +struct GlobalUniforms { + projectionMatrix:mat3x3, + worldTransformMatrix:mat3x3, + worldColorAlpha: vec4, + uResolution: vec2, +} + +struct LocalUniforms { + uTransformMatrix:mat3x3, + uColor:vec4, + uRound:f32, +} + +@group(0) @binding(0) var globalUniforms : GlobalUniforms; +@group(1) @binding(0) var localUniforms : LocalUniforms; + +@vertex +fn main( + @location(0) aPosition : vec2, +) -> @builtin(position) vec4 { + var mvp = globalUniforms.projectionMatrix + * globalUniforms.worldTransformMatrix + * localUniforms.uTransformMatrix; + return vec4(mvp * vec3(aPosition, 1.0), 1.0); +}; + +@fragment +fn main() -> @location(0) vec4 { + return vec4(1.0, 0.0, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/triangleColor/index.js b/src/examples/v8.0.0/meshAndShaders/triangleColor/index.js new file mode 100644 index 000000000..a04c8b4dc --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/triangleColor/index.js @@ -0,0 +1,58 @@ +import { Application, Geometry, Mesh, Shader } from 'pixi.js'; +import vertex from './triangleColor.vert'; +import fragment from './triangleColor.frag'; +import source from './triangleColor.wgsl'; + +(async () => +{ + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ + resizeTo: window, + preference: 'webgpu', + }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + const geometry = new Geometry({ + attributes: { + aPosition: [-100, -50, 100, -50, 0, 100], + aColor: [1, 0, 0, 0, 1, 0, 0, 0, 1], + }, + }); + + const gl = { vertex, fragment }; + + const gpu = { + vertex: { + entryPoint: 'mainVert', + source, + }, + fragment: { + entryPoint: 'mainFrag', + source, + }, + }; + + const shader = Shader.from({ + gl, + gpu, + }); + + const triangle = new Mesh({ + geometry, + shader, + }); + + triangle.position.set(400, 300); + + app.stage.addChild(triangle); + + app.ticker.add(() => + { + triangle.rotation += 0.01; + }); +})(); diff --git a/src/examples/v8.0.0/meshAndShaders/triangleColor/triangleColor.frag b/src/examples/v8.0.0/meshAndShaders/triangleColor/triangleColor.frag new file mode 100644 index 000000000..0263833f6 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/triangleColor/triangleColor.frag @@ -0,0 +1,5 @@ +in vec3 vColor; + +void main() { + gl_FragColor = vec4(vColor, 1.0); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/triangleColor/triangleColor.vert b/src/examples/v8.0.0/meshAndShaders/triangleColor/triangleColor.vert new file mode 100644 index 000000000..3f1deac3e --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/triangleColor/triangleColor.vert @@ -0,0 +1,17 @@ +in vec2 aPosition; +in vec3 aColor; + +out vec3 vColor; +uniform mat3 uProjectionMatrix; +uniform mat3 uWorldTransformMatrix; + +uniform mat3 uTransformMatrix; + + +void main() { + + mat3 mvp = uProjectionMatrix * uWorldTransformMatrix * uTransformMatrix; + gl_Position = vec4((mvp * vec3(aPosition, 1.0)).xy, 0.0, 1.0); + + vColor = aColor; +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/triangleColor/triangleColor.wgsl b/src/examples/v8.0.0/meshAndShaders/triangleColor/triangleColor.wgsl new file mode 100644 index 000000000..70934a294 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/triangleColor/triangleColor.wgsl @@ -0,0 +1,40 @@ +struct GlobalUniforms { + projectionMatrix:mat3x3, + worldTransformMatrix:mat3x3, + worldColorAlpha: vec4, + uResolution: vec2, +} + +struct LocalUniforms { + uTransformMatrix:mat3x3, + uColor:vec4, + uRound:f32, +} + +@group(0) @binding(0) var globalUniforms : GlobalUniforms; +@group(1) @binding(0) var localUniforms : LocalUniforms; + +struct VertexOutput { + @builtin(position) position : vec4, + @location(0) vColor : vec3, +} + +@vertex +fn mainVert( + @location(0) aPosition : vec2, + @location(1) aColor : vec3, +) -> VertexOutput { + var mvp = globalUniforms.projectionMatrix + * globalUniforms.worldTransformMatrix + * localUniforms.uTransformMatrix; + + return VertexOutput( + vec4(mvp * vec3(aPosition, 1.0), 1.0), + aColor, + ); +}; + +@fragment +fn mainFrag(input: VertexOutput) -> @location(0) vec4{ + return vec4(input.vColor, 1.0); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/triangleTextured/index.js b/src/examples/v8.0.0/meshAndShaders/triangleTextured/index.js new file mode 100644 index 000000000..c6694e681 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/triangleTextured/index.js @@ -0,0 +1,59 @@ +import { Application, Assets, Geometry, Mesh, Shader } from 'pixi.js'; +import vertex from './triangleTextured.vert'; +import fragment from './triangleTextured.frag'; + +(async () => +{ + const texture = await Assets.load('https://pixijs.com/assets/bg_scene_rotate.jpg'); + + // Create a new application + const app = new Application(); + + // Initialize the application + await app.init({ + resizeTo: window, + preference: 'webgl', + }); + + // Append the application canvas to the document body + document.body.appendChild(app.canvas); + + const geometry = new Geometry({ + attributes: { + aPosition: [ + -100, + -100, // x, y + 100, + -100, // x, y + 100, + 100, + ], // x, y,, + aColor: [1, 0, 0, 0, 1, 0, 0, 0, 1], + aUV: [0, 0, 1, 0, 1, 1], + }, + }); + + const shader = Shader.from({ + gl: { + vertex, + fragment, + }, + resources: { + uTexture: texture.source, + }, + }); + + const triangle = new Mesh({ + geometry, + shader, + }); + + triangle.position.set(400, 300); + + app.stage.addChild(triangle); + + app.ticker.add(() => + { + triangle.rotation += 0.01; + }); +})(); diff --git a/src/examples/v8.0.0/meshAndShaders/triangleTextured/triangleTextured.frag b/src/examples/v8.0.0/meshAndShaders/triangleTextured/triangleTextured.frag new file mode 100644 index 000000000..804775515 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/triangleTextured/triangleTextured.frag @@ -0,0 +1,8 @@ +in vec3 vColor; +in vec2 vUV; + +uniform sampler2D uTexture; + +void main() { + gl_FragColor = texture2D(uTexture, vUV) * vec4(vColor, 1.0); +} \ No newline at end of file diff --git a/src/examples/v8.0.0/meshAndShaders/triangleTextured/triangleTextured.vert b/src/examples/v8.0.0/meshAndShaders/triangleTextured/triangleTextured.vert new file mode 100644 index 000000000..a144b8b04 --- /dev/null +++ b/src/examples/v8.0.0/meshAndShaders/triangleTextured/triangleTextured.vert @@ -0,0 +1,21 @@ +in vec2 aPosition; +in vec3 aColor; +in vec2 aUV; + +out vec3 vColor; +out vec2 vUV; + +uniform mat3 uProjectionMatrix; +uniform mat3 uWorldTransformMatrix; + +uniform mat3 uTransformMatrix; + + +void main() { + + mat3 mvp = uProjectionMatrix * uWorldTransformMatrix * uTransformMatrix; + gl_Position = vec4((mvp * vec3(aPosition, 1.0)).xy, 0.0, 1.0); + + vColor = aColor; + vUV = aUV; +} \ No newline at end of file diff --git a/static/assets/rainbow-gradient.png b/static/assets/rainbow-gradient.png new file mode 100644 index 000000000..fe5cee19b Binary files /dev/null and b/static/assets/rainbow-gradient.png differ diff --git a/static/assets/tiger.svg b/static/assets/tiger.svg new file mode 100644 index 000000000..679edec2e --- /dev/null +++ b/static/assets/tiger.svg @@ -0,0 +1,725 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/assets/tree.png b/static/assets/tree.png new file mode 100644 index 000000000..e4ac06c75 Binary files /dev/null and b/static/assets/tree.png differ